[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 6453 - (download) (as text) (annotate)
Tue Oct 12 00:06:21 2010 UTC (7 years, 9 months ago) by gage
File size: 43625 byte(s)
minor format change.


    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     type      => '',
  412     visible   => 0,
  413     configuration      => '',         # configuration defining the applet
  414     initialState       => '',         # initial state.
  415     getStateAlias      =>  'getXML',
  416     setStateAlias      =>  'setXML',
  417     configAlias        =>  '',        # deprecated
  418     getConfigAlias     =>  'getConfig',
  419     setConfigAlias     =>  'setConfig',
  420     initializeActionAlias => 'setXML',
  421     maxInitializationAttempts => 5,   # number of attempts to initialize applet
  422     submitActionAlias  =>  'getXML',
  423     submitActionScript  => '',        # script executed on submitting the WW question
  424     answerBoxAlias     =>  'answerBox',
  425     answerBox          =>  '',        # deprecated
  426     returnFieldName    => '',         # deprecated
  427     headerText         =>  DEFAULT_HEADER_TEXT(),
  428     objectText         => '',
  429     debugMode          => 0,
  430     selfLoading        => 0,
  431     @_,
  432   };
  433   bless $self, $class;
  434   $self->initialState('<xml></xml>');
  435   if ($self->{returnFieldName} or $self->{answerBox} ) { # backward compatibility
  436     warn "use answerBoxAlias instead of returnFieldName or answerBox";
  437     $self->{answerBox}='';
  438     $self->{returnFieldName}='';
  439   }
  440   if ($self->{configAlias}) { # backward compatibility
  441     warn "use setConfigAlias instead of configAlias";
  442     $self->{configAlias}='';
  443   }
  444   $self->configuration('<xml></xml>');
  445   return $self;
  446 }
  447 sub appletId {
  448   appletName(@_);
  449 }
  450 sub appletName {
  451   my $self = shift;
  452   $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty
  453     $self->{appletName};
  454 }
  455 sub archive {
  456   my $self = shift;
  457   $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty
  458     $self->{archive};
  459 }
  460 sub code {
  461   my $self = shift;
  462   $self->{code} = shift ||$self->{code}; # replace the current code if non-empty
  463     $self->{code};
  464 }
  465 sub codebase {
  466   my $self = shift;
  467   $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty
  468     $self->{codebase};
  469 }
  470 sub params {
  471   my $self = shift;
  472   if (ref($_[0]) =~/HASH/) {
  473     $self->{params} = shift;
  474   } elsif ( !defined($_[0]) or $_[0] =~ '') {
  475     # do nothing (read)
  476   } else {
  477     warn "You must enter a reference to a hash for the parameter list";
  478   }
  479   $self->{params};
  480 }
  481 
  482 sub width {
  483   my $self = shift;
  484   $self->{width} = shift ||$self->{width}; # replace the current width if non-empty
  485     $self->{width};
  486 }
  487 sub height {
  488   my $self = shift;
  489   $self->{height} = shift ||$self->{height}; # replace the current height if non-empty
  490     $self->{height};
  491 }
  492 sub bgcolor {
  493   my $self = shift;
  494   $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty
  495     $self->{bgcolor};
  496 }
  497 
  498 sub  header {
  499   my $self = shift;
  500   if ($_[0] eq "reset") {  # $applet->header('reset');  erases default header text.
  501     $self->{headerText}='';
  502   } else {
  503     $self->{headerText} .= join("",@_);  # $applet->header(new_text); concatenates new_text to existing header.
  504   }
  505     $self->{headerText};
  506 }
  507 sub  object {
  508   my $self = shift;
  509   if ($_[0] eq "reset") {
  510     $self->{objectText}='';
  511   } else {
  512     $self->{objectText} .= join("",@_);
  513   }
  514     $self->{objectText};
  515 }
  516 sub configuration {
  517   my $self = shift;
  518   my $str = shift;
  519   $self->{configuration} =  $str   || $self->{configuration}; # replace the current string if non-empty
  520   $self->{configuration} =~ s/\n//g;
  521     $self->{configuration};
  522 }
  523 
  524 sub initialState {
  525   my $self = shift;
  526   my $str = shift;
  527   $self->{initialState} = $str   ||$self->{initialState}; # replace the current string if non-empty
  528     $self->{initialState};
  529 }
  530 
  531 sub getStateAlias {
  532   my $self = shift;
  533   $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty
  534     $self->{getStateAlias};
  535 }
  536 
  537 sub setStateAlias {
  538   my $self = shift;
  539   $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty
  540     $self->{setStateAlias};
  541 }
  542 
  543 sub getConfigAlias {
  544   my $self = shift;
  545   $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty
  546     $self->{getConfigAlias};
  547 }
  548 sub setConfigAlias {
  549   my $self = shift;
  550   $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty
  551     $self->{setConfigAlias};
  552 }
  553 
  554 sub initializeActionAlias {
  555   my $self = shift;
  556   $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty
  557     $self->{initializeActionAlias};
  558 }
  559 sub maxInitializationAttempts {
  560   my $self = shift;
  561   $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts};
  562   $self->{maxInitializationAttempts};
  563 }
  564 sub submitActionAlias {
  565   my $self = shift;
  566   $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty
  567     $self->{submitActionAlias};
  568 }
  569 sub submitActionScript {
  570   my $self = shift;
  571   $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty
  572     $self->{submitActionScript};
  573 }
  574 
  575 sub answerBoxAlias {
  576   my $self = shift;
  577   $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty
  578     $self->{answerBox};
  579 }
  580 
  581 sub debugMode {
  582   my $self = shift;
  583   my $new_flag = shift;
  584   $self->{debugMode} = $new_flag if defined($new_flag);
  585   $self->{debugMode};
  586 }
  587 
  588 
  589 #######################
  590 # soon to be deprecated?
  591 #######################
  592 
  593 sub config {
  594   my $self = shift;
  595   my $str = shift;
  596   warn "use $self->configuration instead of $self->config.  Internally this string is ascii, not base64 encoded", join(' ', caller());
  597 #   $self->{base64_config} =  encode_base64($str)   || $self->{base64_config}; # replace the current string if non-empty
  598 #   $self->{base64_config} =~ s/\n//g;
  599 #     decode_base64($self->{base64_config});
  600 }
  601 sub state {    #deprecated
  602   my $self = shift;
  603   my $str = shift;
  604   warn "use $self->initialState instead of $self->state.  Internally this string is ascii, not base64 encoded", join(' ', caller());
  605 #   $self->{base64_state} =  encode_base64($str)   ||$self->{base64_state}; # replace the current string if non-empty
  606 #   $self->{base64_state} =~ s/\n//g;
  607 #     decode_base64($self->{base64_state});
  608 }
  609 sub base64_state{
  610   my $self = shift;
  611   warn "use $self->InitialState instead of $self->state.  Internally this string is ascii, not base64 encoded", join(' ', caller());
  612 
  613 
  614 }
  615 
  616 sub base64_config {
  617   my $self = shift;
  618   warn "use $self->configuration instead of $self->config.  Internally this string is ascii, not base64 encoded";
  619 }
  620 
  621 sub returnFieldName {
  622   my $self = shift;
  623     warn "use  answerBoxName  instead of returnFieldName";
  624 }
  625 sub answerBox {
  626   my $self = shift;
  627     warn "use  answerBoxAlias  instead of AnswerBox";
  628 }
  629 sub configAlias {
  630   my $self = shift;
  631     warn "use setConfigAlias instead of configAlias";
  632 }
  633 #########################
  634 #FIXME
  635 # need to be able to adjust header material
  636 
  637 sub insertHeader {
  638     my $self = shift;
  639 
  640     my $codebase              =  $self->codebase;
  641     my $appletId              =  $self->appletId;
  642     my $appletName            =  $self->appletName;
  643     my $initializeActionAlias =  $self->initializeActionAlias;
  644     my $submitActionScript    =  $self->submitActionScript;
  645     my $setStateAlias         =  $self->setStateAlias;
  646     my $getStateAlias         =  $self->getStateAlias;
  647 
  648     my $setConfigAlias        =  $self->setConfigAlias;
  649     my $getConfigAlias        =  $self->getConfigAlias;
  650     my $maxInitializationAttempts = $self->maxInitializationAttempts;
  651     my $debugMode             =  ($self->debugMode) ? "1": "0";
  652     my $answerBoxAlias        =  $self->{answerBoxAlias};
  653     my $onInit                =  $self->{onInit};   # function to indicate that applet is loaded (for geogebra:   ggbOnInit
  654     my $headerText            =  $self->header();
  655     my $selfLoading           =  $self->{selfLoading};
  656 
  657     #$submitActionScript =~ s/"/\\"/g;    # escape quotes for ActionScript
  658                                          # other variables should not have quotes.
  659 
  660     $submitActionScript =~ s/\n/ /g;     # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript
  661     $submitActionScript =~ s/\r/ /g;     # replace returns with spaces -- returns can cause trouble
  662     my  $base64_submitActionScript =     encode_base64($submitActionScript);
  663     my $base64_configuration  =  encode_base64($self->configuration);
  664     my $base64_initialState   =  encode_base64($self->initialState);
  665 
  666     $base64_submitActionScript =~s/\n//g;
  667     $base64_initialState  =~s/\n//g;  # base64 encoded xml
  668     $base64_configuration =~s/\n//g;  # base64 encoded xml
  669 
  670     $headerText =~ s/(\$\w+)/$1/gee;   # interpolate variables p17 of Cookbook
  671 
  672     return $headerText;
  673 
  674 
  675 }
  676 
  677 
  678 ########################################################
  679 # HEADER material for one flash or java applet
  680 ########################################################
  681 
  682 use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT';
  683     <script src="/webwork2_files/js/Base64.js" language="javascript">
  684     </script>
  685     <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
  686         //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
  687 
  688      </script>
  689   <script language="JavaScript">
  690 
  691      function getApplet(appletName) {
  692       var isIE = navigator.appName.indexOf("Microsoft") != -1;  // ie8 uses this for java and firefox uses it for flash.
  693       var obj = (isIE) ? window[appletName] : window.document[appletName];
  694       //return window.document[appletName];
  695       if (!obj) { obj = document.getElementById(appletName) }
  696       if (obj ) {   //RECENT FIX to ==
  697         return( obj );
  698       } else {
  699         alert ("can't find applet " + appletName);
  700       }
  701     }
  702 
  703     //////////////////////////////////////////////////////////
  704   //TEST code
  705   //
  706     //
  707     //////////////////////////////////////////////////////////
  708 
  709     ww_applet_list["$appletName"]                  = new ww_applet("$appletName");
  710 
  711 
  712   ww_applet_list["$appletName"].code             = "$code";
  713   ww_applet_list["$appletName"].codebase         = "$codebase";
  714     ww_applet_list["$appletName"].appletID         = "$appletID";
  715   ww_applet_list["$appletName"].base64_state     = "$base64_initialState";
  716   ww_applet_list["$appletName"].initialState     =  Base64.decode("$base64_initialState");
  717   ww_applet_list["$appletName"].configuration    =  Base64.decode("$base64_configuration");;
  718   ww_applet_list["$appletName"].getStateAlias    = "$getStateAlias";
  719   ww_applet_list["$appletName"].setStateAlias    = "$setStateAlias";
  720   ww_applet_list["$appletName"].setConfigAlias   = "$setConfigAlias";
  721   ww_applet_list["$appletName"].getConfigAlias   = "$getConfigAlias";
  722   ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias";
  723   ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
  724   ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript");
  725   ww_applet_list["$appletName"].answerBoxAlias     = "$answerBoxAlias";
  726   ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts;
  727   ww_applet_list["$appletName"].debugMode          = "$debugMode";
  728   ww_applet_list["$appletName"].onInit             = "$onInit";
  729 
  730 
  731     </script>
  732 
  733 END_HEADER_SCRIPT
  734 
  735 
  736 
  737 sub insertObject {
  738     my $self       = shift;
  739     my $code       = $self->{code};
  740     my $codebase   = $self->{codebase};
  741     my $appletId   = $self->{appletName};
  742     my $appletName = $self->{appletName};
  743     my $archive    = $self->{archive};
  744     my $width      = $self->{width};
  745     my $height     = $self->{height};
  746     my $applet_bgcolor = $self->{bgcolor};
  747     my $selfLoading = $self->{selfLoading};
  748     my $javaParameters = '';
  749     my $flashParameters = '';
  750     if (PGcore::not_null($self->{parameter_string}) ) {
  751       $javaParameters = $self->{parameter_string};
  752       $flashParameters = $self->{parameter_string};
  753     } else {
  754     my %param_hash = %{$self->params()};
  755     foreach my $key (keys %param_hash) {
  756       $javaParameters .= qq!<param name ="$key"  value = "$param_hash{$key}">\n!;
  757       $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&';
  758     }
  759     $flashParameters =~ s/\&$//;    # trim last &
  760   }
  761 
  762 
  763     $objectText = $self->{objectText};
  764     $objectText =~ s/(\$\w+)/$1/gee;
  765     $objectText .=qq{<script language="javascript">ww_applet_list["$appletName"].visible = 1;</script>}; # don't submit things if not visible
  766     return $objectText;
  767 }
  768 
  769 
  770 ###############################################################################################################
  771 #
  772 # FLASH APPLET  PACKAGE
  773 #
  774 ###############################################################################################################
  775 
  776 package FlashApplet;
  777 @ISA = qw(Applet);
  778 
  779 
  780 =head2 Insertion HTML code for FlashApplet
  781 
  782 =pod
  783 
  784 The secret to making this applet work with IE in addition to normal browsers
  785 is the addition of the C(<form></form>) construct just before the object.
  786 
  787 For some reason IE has trouble locating a flash object which is contained
  788 within a form.  Adding this second blank form with the larger problemMainForm
  789 seems to solve the problem.
  790 
  791 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  792 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  793 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  794 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  795 
  796     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  797       <form></form>
  798       <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  799            id="$appletName" width="500" height="375"
  800            codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  801          <param name="movie" value="$codebase/$appletName.swf" />
  802          <param name="quality" value="high" />
  803          <param name="bgcolor" value="$applet_bgcolor" />
  804          <param name="allowScriptAccess" value="sameDomain" />
  805          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  806            width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
  807            play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  808            type="application/x-shockwave-flash"
  809            pluginspage="http://www.macromedia.com/go/getflashplayer">
  810          </embed>
  811 
  812        </object>
  813     END_OBJECT_TEXT
  814 
  815 
  816 =cut
  817 
  818 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  819 
  820 
  821   <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  822              id="$appletName"  width="500" height="375"
  823              codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  824          <param name="movie" value="$codebase/$appletName.swf" />
  825          <param name="quality" value="high" />
  826          <param name="bgcolor" value="$applet_bgcolor" />
  827          <param name="allowScriptAccess" value="sameDomain" />
  828          <param name="FlashVars" value="$flashParameters"/>
  829          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  830              width="$width" height="$height" name="$appletName"  align="middle" id="$appletName"
  831              play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  832              type="application/x-shockwave-flash"
  833              pluginspage="http://www.macromedia.com/go/getflashplayer"
  834              FlashVars="$flashParameters">
  835          </embed>
  836 
  837      </object>
  838 END_OBJECT_TEXT
  839 
  840 sub new {
  841     my $class = shift;
  842   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  843                           type         => 'flash',
  844                   @_
  845   );
  846 
  847 }
  848 
  849 ###############################################################################################################
  850 #
  851 # JAVA APPLET  PACKAGE
  852 #
  853 ###############################################################################################################
  854 
  855 package JavaApplet;
  856 @ISA = qw(Applet);
  857 
  858 =head2 Insertion HTML code for JavaApplet
  859 
  860 =pod
  861 
  862 The secret to making this applet work with IE in addition to normal browsers
  863 is the addition of the C(<form></form>) construct just before the object.
  864 
  865 For some reason IE has trouble locating a flash object which is contained
  866 within a form.  Adding this second blank form with the larger problemMainForm
  867 seems to solve the problem.
  868 
  869 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  870 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  871 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  872 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  873 
  874     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  875      <applet
  876       code     = "$code"
  877       codebase = "$codebase"
  878       archive  = "$archive"
  879       name     = "$appletName"
  880       id       = "$appletName"
  881       width    = "$width"
  882       height   = "$height"
  883       MAYSCRIPT
  884      >
  885       $javaParameters
  886      </applet>
  887     END_OBJECT_TEXT
  888 
  889 =cut
  890 
  891 
  892 =pod
  893 
  894 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  895 
  896  <applet
  897   code     = "$code"
  898   codebase = "$codebase"
  899   archive  = "$archive"
  900   name     = "$appletName"
  901     id       = "$appletName"
  902     width    = "$width"
  903     height   = "$height"
  904     bgcolor  = "$applet_bgcolor"
  905     mayscript = "true";
  906  >
  907   $javaParameters
  908 
  909   Sorry, the Applet could not be started. Please make sure that
  910 Java 1.4.2 (or later) is installed and activated.
  911 (<a href="http://java.sun.com/getjava">click here to install Java now</a>)
  912  </applet>
  913 END_OBJECT_TEXT
  914 
  915 =cut
  916 
  917 #  classid  = "java:MyApplet.class"
  918 
  919 
  920 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  921 
  922 <applet
  923      id       = "$appletName"
  924      name     = "$appletName"
  925     code      = "$code"
  926      type     = "application/x-java-applet"
  927      codebase = "$codebase"
  928    archive  = "$archive"
  929    height   = "$height"
  930    width    = "$width"
  931    bgcolor  = "$applet_bgcolor"
  932    mayscript = "true"
  933   >
  934     <PARAM NAME="MAYSCRIPT" VALUE="true">
  935     $javaParameters
  936 
  937    Sorry, the Applet could not be started. Please make sure that
  938   Java 1.4.2 (or later) is installed and activated.
  939   (<a href="http://java.sun.com/getjava">click here to install Java now</a>)
  940 </applet>
  941 END_OBJECT_TEXT
  942 
  943 
  944 
  945 sub new {
  946     my $class = shift;
  947   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  948                           type         => 'java',
  949                   @_
  950   );
  951 
  952 }
  953 
  954 ###############################################################################################################
  955 #
  956 # CANVAS APPLET  PACKAGE
  957 #
  958 ###############################################################################################################
  959 
  960 package CanvasApplet;
  961 @ISA = qw(Applet);
  962 
  963 
  964 =head2 Insertion HTML code for CanvasApplet
  965 
  966 =pod
  967 
  968 The secret to making this applet work with IE in addition to normal browsers
  969 is the addition of the C(<form></form>) construct just before the object.
  970 
  971 For some reason IE has trouble locating a flash object which is contained
  972 within a form.  Adding this second blank form with the larger problemMainForm
  973 seems to solve the problem.
  974 
  975 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  976 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  977 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  978 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  979 
  980 use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  981   <form></form>
  982   <script> var width = 200; var height = 200;</script>
  983   <canvas name="cv" id="cv" data-src="http://localhost/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="400" height="400"></canvas>
  984 END_OBJECT_TEXT
  985 
  986 
  987 
  988 =cut
  989 
  990 
  991 use constant CANVAS_OBJECT_HEADER_TEXT =><<'END_HEADER_SCRIPT';
  992     <script src="/webwork2_files/js/Base64.js" language="javascript">
  993     </script>
  994     <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
  995         //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
  996 
  997      </script>
  998   <script language="JavaScript">
  999 
 1000 
 1001 
 1002     //////////////////////////////////////////////////////////
 1003   //CANVAS OBJECT HEADER CODE
 1004     //
 1005     //////////////////////////////////////////////////////////
 1006 
 1007     ww_applet_list["$appletName"] = new ww_applet("$appletName");
 1008 
 1009 
 1010   ww_applet_list["$appletName"].code             = "$code";
 1011   ww_applet_list["$appletName"].codebase         = "$codebase";
 1012     ww_applet_list["$appletName"].appletID         = "$appletID";
 1013   ww_applet_list["$appletName"].base64_state     = "$base64_initializationState";
 1014   ww_applet_list["$appletName"].initialState     = Base64.decode("$base64_initialState");
 1015   ww_applet_list["$appletName"].configuration    = Base64.decode("$base64_configuration");;
 1016   ww_applet_list["$appletName"].getStateAlias    = "$getStateAlias";
 1017   ww_applet_list["$appletName"].setStateAlias    = "$setStateAlias";
 1018   ww_applet_list["$appletName"].setConfigAlias   = "$setConfigAlias";
 1019   ww_applet_list["$appletName"].getConfigAlias   = "$getConfigAlias";
 1020   ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias";
 1021   ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
 1022   ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript");
 1023   ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias";
 1024   ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts;
 1025   ww_applet_list["$appletName"].debugMode = "$debugMode";
 1026     ww_applet_list["$appletName"].debugMode = "$selfLoading";
 1027 
 1028     ww_applet_list["$appletName"].reportsLoaded = 1;
 1029     ww_applet_list["$appletName"].object = $appletName;
 1030 
 1031     function getApplet(appletName) {
 1032       //var isIE = navigator.appName.indexOf("Microsoft") != -1;
 1033       //var obj = (isIE) ? window[appletName] : window.document[appletName];
 1034       //return window.document[appletName];
 1035       var obj = ww_applet_list[appletName].object;   // define fake applet for this object
 1036       if (obj && (obj.name == appletName)) {   //RECENT FIX to ==
 1037           //alert("getting fake applet " + obj.name);
 1038         return( obj );
 1039       } else {
 1040         alert ("can't find fake applet " + appletName + " in object "+obj.name);
 1041       }
 1042     }
 1043     </script>
 1044 
 1045 END_HEADER_SCRIPT
 1046 
 1047 
 1048 #FIXME   need to get rid of hardcoded url
 1049 
 1050 
 1051 use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT';
 1052     <script language="javascript">ww_applet_list["$appletName"].visible = 1; // don't submit things if not visible
 1053     </script>
 1054   <canvas name="cv" id="cv" data-src="/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="$width" height="$height"></canvas>
 1055 END_OBJECT_TEXT
 1056 
 1057 sub new {
 1058     my $class = shift;
 1059   $class -> SUPER::new( objectText   => CANVAS_OBJECT_TEXT(),
 1060                       headerText   => CANVAS_OBJECT_HEADER_TEXT(),
 1061                       type         => 'html5canvas',
 1062                   @_
 1063   );
 1064 
 1065 }
 1066 
 1067 
 1068 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9