Parent Directory
|
Revision Log
removed <form></form> from the comments. (Also in the previous update reverted the tags for java applets back to <applets> instead of <object> -- it seems safer --- at least with geogebra.
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 808 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 809 id="$appletName" width="500" height="375" 810 codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> 811 <param name="movie" value="$codebase/$appletName.swf" /> 812 <param name="quality" value="high" /> 813 <param name="bgcolor" value="$applet_bgcolor" /> 814 <param name="allowScriptAccess" value="sameDomain" /> 815 <param name="FlashVars" value="$flashParameters"/> 816 <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" 817 width="$width" height="$height" name="$appletName" align="middle" id="$appletName" 818 play="true" loop="false" quality="high" allowScriptAccess="sameDomain" 819 type="application/x-shockwave-flash" 820 pluginspage="http://www.macromedia.com/go/getflashplayer" 821 FlashVars="$flashParameters"> 822 </embed> 823 824 </object> 825 END_OBJECT_TEXT 826 827 sub new { 828 my $class = shift; 829 $class -> SUPER::new( objectText => DEFAULT_OBJECT_TEXT(), 830 @_ 831 ); 832 833 } 834 835 ############################################################################################################### 836 # 837 # JAVA APPLET PACKAGE 838 # 839 ############################################################################################################### 840 841 package JavaApplet; 842 @ISA = qw(Applet); 843 844 =head2 Insertion HTML code for JavaApplet 845 846 =pod 847 848 The secret to making this applet work with IE in addition to normal browsers 849 is the addition of the C(<form></form>) construct just before the object. 850 851 For some reason IE has trouble locating a flash object which is contained 852 within a form. Adding this second blank form with the larger problemMainForm 853 seems to solve the problem. 854 855 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2) 856 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated: 857 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js 858 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933 859 860 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 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 878 =pod 879 880 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 881 882 <applet 883 code = "$code" 884 codebase = "$codebase" 885 archive = "$archive" 886 name = "$appletName" 887 id = "$appletName" 888 width = "$width" 889 height = "$height" 890 bgcolor = "$applet_bgcolor" 891 MAYSCRIPT 892 > 893 $javaParameters 894 895 Sorry, the Applet could not be started. Please make sure that 896 Java 1.4.2 (or later) is installed and activated. 897 (<a href="http://java.sun.com/getjava">click here to install Java now</a>) 898 </applet> 899 END_OBJECT_TEXT 900 901 =cut 902 903 # classid = "java:MyApplet.class" 904 905 906 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 907 908 <applet 909 id = "$appletName" 910 name = "$appletName" 911 code = "$code" 912 type = "application/x-java-applet" 913 codebase = "$codebase" 914 archive = "$archive" 915 height = "$height" 916 width = "$width" 917 bgcolor = "$applet_bgcolor" 918 mayscript = "true" 919 > 920 <PARAM NAME="MAYSCRIPT" VALUE="true"> 921 $javaParameters 922 923 Sorry, the Applet could not be started. Please make sure that 924 Java 1.4.2 (or later) is installed and activated. 925 (<a href="http://java.sun.com/getjava">click here to install Java now</a>) 926 </applet> 927 END_OBJECT_TEXT 928 929 930 931 sub new { 932 my $class = shift; 933 $class -> SUPER::new( objectText => DEFAULT_OBJECT_TEXT(), 934 @_ 935 ); 936 937 } 938 939 ############################################################################################################### 940 # 941 # CANVAS APPLET PACKAGE 942 # 943 ############################################################################################################### 944 945 package CanvasApplet; 946 @ISA = qw(Applet); 947 948 949 =head2 Insertion HTML code for CanvasApplet 950 951 =pod 952 953 The secret to making this applet work with IE in addition to normal browsers 954 is the addition of the C(<form></form>) construct just before the object. 955 956 For some reason IE has trouble locating a flash object which is contained 957 within a form. Adding this second blank form with the larger problemMainForm 958 seems to solve the problem. 959 960 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2) 961 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated: 962 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js 963 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933 964 965 use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 966 <form></form> 967 <script> var width = 200; var height = 200;</script> 968 <canvas name="cv" id="cv" data-src="http://localhost/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="400" height="400"></canvas> 969 END_OBJECT_TEXT 970 971 972 973 =cut 974 975 976 use constant CANVAS_OBJECT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; 977 <script src="/webwork2_files/js/Base64.js" language="javascript"> 978 </script> 979 <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> 980 //upload functions stored in /opt/webwork/webwork2/htdocs/js ... 981 982 </script> 983 <script language="JavaScript"> 984 985 986 987 ////////////////////////////////////////////////////////// 988 //CANVAS OBJECT HEADER CODE 989 // 990 ////////////////////////////////////////////////////////// 991 992 ww_applet_list["$appletName"] = new ww_applet("$appletName"); 993 994 995 ww_applet_list["$appletName"].code = "$code"; 996 ww_applet_list["$appletName"].codebase = "$codebase"; 997 ww_applet_list["$appletName"].appletID = "$appletID"; 998 ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; 999 ww_applet_list["$appletName"].initialState = Base64.decode("$base64_initialState"); 1000 ww_applet_list["$appletName"].configuration = Base64.decode("$base64_configuration");; 1001 ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; 1002 ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; 1003 ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; 1004 ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; 1005 ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias"; 1006 ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; 1007 ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript"); 1008 ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias"; 1009 ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts; 1010 ww_applet_list["$appletName"].debugMode = "$debugMode"; 1011 1012 1013 ww_applet_list["$appletName"].reportsLoaded = 1; 1014 ww_applet_list["$appletName"].object = $appletName; 1015 1016 function getApplet(appletName) { 1017 //var isIE = navigator.appName.indexOf("Microsoft") != -1; 1018 //var obj = (isIE) ? window[appletName] : window.document[appletName]; 1019 //return window.document[appletName]; 1020 var obj = ww_applet_list[appletName].object; // define fake applet for this object 1021 if (obj && (obj.name == appletName)) { //RECENT FIX to == 1022 //alert("getting fake applet " + obj.name); 1023 return( obj ); 1024 } else { 1025 alert ("can't find fake applet " + appletName + " in object "+obj.name); 1026 } 1027 } 1028 </script> 1029 1030 END_HEADER_SCRIPT 1031 1032 1033 #FIXME need to get rid of hardcoded url 1034 1035 1036 use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 1037 1038 <canvas name="cv" id="cv" data-src="/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="$width" height="$height"></canvas> 1039 END_OBJECT_TEXT 1040 1041 sub new { 1042 my $class = shift; 1043 $class -> SUPER::new( objectText => CANVAS_OBJECT_TEXT(), 1044 headerText => CANVAS_OBJECT_HEADER_TEXT(), 1045 @_ 1046 ); 1047 1048 } 1049 1050 1051 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |