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