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