Parent Directory
|
Revision Log
Cleaning up duplicated lines
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.16 2009/02/19 03:04:22 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 my $appletName = "LineThruPointsWW"; 27 $applet = new FlashApplet( 28 # can be replaced by $applet =FlashApplet() when using AppletObjects.pl 29 codebase => findAppletCodebase("$appletName.swf"), 30 appletName => $appletName, 31 appletId => $appletName, 32 submitActionAlias => 'checkAnswer', 33 ); 34 35 ################################### 36 # Configure applet 37 ################################### 38 39 #xml data to set up the problem-rac 40 $applet->config(qq{<XML> 41 <point xval='$xval_1' yval='$yval_1' /> 42 <point xval='$xval_2' yval='$yval_2' /> 43 </XML>}); 44 45 46 ################################### 47 # insert applet header material 48 ################################### 49 HEADER_TEXT($applet->insertHeader ); 50 51 ################################### 52 # Text section 53 # 54 55 ################################### 56 #insert applet into body 57 ################################### 58 TEXT( MODES(TeX=>'object code', HTML=>$applet->insertObject)); 59 60 61 =head1 DESCRIPTION 62 63 This file provides an object to store in one place 64 all of the information needed to call an applet. 65 66 The object FlashApplet has defaults for inserting flash applets. 67 68 =over 69 70 =item * 71 72 =item * 73 74 =back 75 76 (not yet completed) 77 78 The module JavaApplet has defaults for inserting java applets. 79 80 The module Applet stores common code for the two types of applet. 81 82 =head1 USAGE 83 84 These modules are activate by listing it in the modules section of global.conf and rebooting the server. 85 The companion file to this one is macros/AppletObjects.pl 86 87 qw(Applet FlashApplet JavaApplet) 88 89 =cut 90 91 92 93 package Applet; 94 95 use URI::Escape; 96 97 98 99 use MIME::Base64 qw( encode_base64 decode_base64); 100 101 102 =head2 Default javaScript functions placed in header 103 104 =pod 105 106 These functions are automatically defined for use for 107 any javaScript placed in the text of a PG question. 108 109 getApplet(appletName) -- finds the applet path in the DOM 110 111 submitAction() -- calls the submit action of the applets 112 113 initializeWWquestion() -- calls the initialize action of the applets 114 115 getQE(name) -- gets an HTML element of the question by name 116 or by id. Be sure to keep all names and ids 117 unique within a given PG question. 118 119 getQuestionElement(name) -- long form of getQE(name) 120 121 listQuestionElements() -- for discovering the names of inputs in the 122 PG question. An alert dialog will list all 123 of the elements. 124 Usage: Place this at the END of the question, just before END_DOCUMENT(): 125 126 TEXT(qq!<script> listQuestionElements() </script>!); 127 ENDDOCUMENT(); 128 to obtain a list of all of the HTML elements in the question 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 height rectangle alloted in the html page for displaying the applet 149 150 params an anonymous array containing name/value pairs 151 to configure the applet [name =>'value, ...] 152 153 header stores the text to be added to the header section of the html page 154 object stores the text which places the applet on the html page 155 156 debug in debug mode several alerts mark progress through the procedure of calling the applet 157 158 config configuration are those customizable attributes of the applet which don't 159 change as it is used. When stored in hidden answer fields 160 it is usually stored in base64 encoded format. 161 base64_config base64 encode version of the contents of config 162 163 configAlias (default: config ) names the applet command called with the contents of $self->config 164 to configure the applet. The parameters are passed to the applet in plain text using <xml> 165 The outer tags must be <xml> ..... </xml> 166 state state consists of those customizable attributes of the applet which change 167 as the applet is used. It is stored by the calling .pg question so that 168 when revisiting the question the applet 169 will be restored to the same state it was left in when the question was last 170 viewed. 171 172 getStateAlias (default: getState) alias for command called to read the current state of the applet. 173 The state is passed in plain text xml format with outer tags: <xml>....</xml> 174 setStateAlias (default: setState) alias for the command called to reset the state of the applet. 175 The state is passed in plain text in xml format with outer tags: <xml>....</xml> 176 177 base64_state returns the base64 encoded version of the state stored in the applet object. 178 179 initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState 180 submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the 181 .pg question is pressed. 182 answerBox -- name of answer box to return answer to: default defaultAnswerBox 183 getAnswer -- (formerly sendData) get student answer from applet and place in answerBox 184 returnFieldName -- (deprecated) synonmym for answerBox 185 186 187 =cut 188 189 190 191 192 sub new { 193 my $class = shift; 194 my $self = { 195 appletName =>'', 196 code=>'', 197 codebase=>'', 198 # appletId =>'', #always use identical applet Id's and applet Names 199 params =>undef, 200 width => 550, 201 height => 400, 202 bgcolor => "#869ca7", 203 base64_state => undef, # this is an state to use for initializing the first occurence of the question. 204 base64_config => undef, # this is the initial (and final?) configuration 205 getStateAlias => 'getXML', 206 setStateAlias => 'setXML', 207 configAlias => 'config', 208 initializeActionAlias => 'setXML', 209 submitActionAlias => 'getXML', 210 submitActionScript => '', # script executed on submitting the WW question 211 answerBox => 'answerBox', 212 headerText => DEFAULT_HEADER_TEXT(), 213 objectText => '', 214 debug => 0, 215 @_, 216 }; 217 bless $self, $class; 218 $self->state('<xml></xml>'); 219 $self->config('<xml></xml>'); 220 return $self; 221 } 222 223 sub header { 224 my $self = shift; 225 if ($_[0] eq "reset") { # $applet->header('reset'); erases default header text. 226 $self->{headerText}=''; 227 } else { 228 $self->{headerText} .= join("",@_); # $applet->header(new_text); concatenates new_text to existing header. 229 } 230 $self->{headerText}; 231 } 232 sub object { 233 my $self = shift; 234 if ($_[0] eq "reset") { 235 $self->{objectText}=''; 236 } else { 237 $self->{objectText} .= join("",@_); 238 } 239 $self->{objectText}; 240 } 241 sub params { 242 my $self = shift; 243 if (ref($_[0]) =~/HASH/) { 244 $self->{params} = shift; 245 } elsif ( !defined($_[0]) or $_[0] =~ '') { 246 # do nothing (read) 247 } else { 248 warn "You must enter a reference to a hash for the parameter list"; 249 } 250 $self->{params}; 251 } 252 253 sub initializeActionAlias { 254 my $self = shift; 255 $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty 256 $self->{initializeActionAlias}; 257 } 258 259 sub submitActionAlias { 260 my $self = shift; 261 $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty 262 $self->{submitActionAlias}; 263 } 264 sub submitActionScript { 265 my $self = shift; 266 $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty 267 $self->{submitActionScript}; 268 } 269 sub getStateAlias { 270 my $self = shift; 271 $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty 272 $self->{getStateAlias}; 273 } 274 275 sub setStateAlias { 276 my $self = shift; 277 $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty 278 $self->{setStateAlias}; 279 } 280 sub configAlias { 281 my $self = shift; 282 $self->{configAlias} = shift ||$self->{configAlias}; # replace the current contents if non-empty 283 $self->{configAlias}; 284 } 285 sub returnFieldName { 286 my $self = shift; 287 $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty 288 $self->{answerBox}; 289 } 290 sub answerBox { 291 my $self = shift; 292 $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty 293 $self->{answerBox}; 294 } 295 sub codebase { 296 my $self = shift; 297 $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty 298 $self->{codebase}; 299 } 300 sub code { 301 my $self = shift; 302 $self->{code} = shift ||$self->{code}; # replace the current code if non-empty 303 $self->{code}; 304 } 305 sub height { 306 my $self = shift; 307 $self->{height} = shift ||$self->{height}; # replace the current height if non-empty 308 $self->{height}; 309 } 310 sub width { 311 my $self = shift; 312 $self->{width} = shift ||$self->{width}; # replace the current width if non-empty 313 $self->{width}; 314 } 315 sub bgcolor { 316 my $self = shift; 317 $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty 318 $self->{bgcolor}; 319 } 320 sub archive { 321 my $self = shift; 322 $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty 323 $self->{archive}; 324 } 325 sub appletName { 326 my $self = shift; 327 $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty 328 $self->{appletName}; 329 } 330 sub debug { 331 my $self = shift; 332 my $new_flag = shift; 333 $self->{debug} = $new_flag if defined($new_flag); 334 $self->{debug}; 335 } 336 sub appletId { 337 appletName(@_); 338 } 339 sub state { 340 my $self = shift; 341 my $str = shift; 342 $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty 343 $self->{base64_state} =~ s/\n//g; 344 decode_base64($self->{base64_state}); 345 } 346 347 sub base64_state{ 348 my $self = shift; 349 $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty 350 $self->{base64_state}; 351 } 352 sub config { 353 my $self = shift; 354 my $str = shift; 355 $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty 356 $self->{base64_config} =~ s/\n//g; 357 decode_base64($self->{base64_config}); 358 } 359 sub base64_config { 360 my $self = shift; 361 $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty 362 $self->{base64_config} =$self->{base64_config}; 363 $self->{base64_config}; 364 } 365 #FIXME 366 # need to be able to adjust header material 367 368 sub insertHeader { 369 my $self = shift; 370 371 my $codebase = $self->codebase; 372 my $appletId = $self->appletId; 373 my $appletName = $self->appletName; 374 my $base64_initialState = $self->base64_state; 375 my $initializeAction = $self->initializeActionAlias; 376 my $submitActionAlias = $self->submitActionAlias; 377 my $submitActionScript = $self->submitActionScript; 378 my $setStateAlias = $self->setStateAlias; 379 my $getStateAlias = $self->getStateAlias; 380 my $configAlias = $self->configAlias; 381 my $base64_config = $self->base64_config; 382 my $debugMode = ($self->debug) ? "1": "0"; 383 my $returnFieldName = $self->{returnFieldName}; 384 my $answerBox = $self->{answerBox}; 385 my $headerText = $self->header(); 386 387 388 $submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript 389 # other variables should not have quotes. 390 391 $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript 392 $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble 393 394 $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook 395 396 return $headerText; 397 398 399 } 400 401 sub insertObject { 402 my $self = shift; 403 my $code = $self->{code}; 404 my $codebase = $self->{codebase}; 405 my $appletId = $self->{appletName}; 406 my $appletName = $self->{appletName}; 407 my $archive = $self->{archive}; 408 my $width = $self->{width}; 409 my $height = $self->{height}; 410 my $applet_bgcolor = $self->{bgcolor}; 411 my $javaParameters = ''; 412 my $flashParameters = ''; 413 my %param_hash = %{$self->params()}; 414 foreach my $key (keys %param_hash) { 415 $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; 416 $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&'; 417 } 418 $flashParameters =~ s/\&$//; # trim last & 419 420 421 $objectText = $self->{objectText}; 422 $objectText =~ s/(\$\w+)/$1/gee; 423 return $objectText; 424 } 425 # sub initialize { 426 # my $self = shift; 427 # return q{ 428 # <script> 429 # initializeAllApplets(); 430 # // this should really be done in the <body> tag 431 # </script> 432 # }; 433 # 434 # } 435 ######################################################## 436 # HEADER material for one flash or java applet 437 ######################################################## 438 439 use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; 440 <script src="/webwork2_files/js/Base64.js" language="javascript"> 441 </script> 442 <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> 443 //upload functions stored in /opt/webwork/webwork2/htdocs/js ... 444 </script> 445 <script language="JavaScript"> 446 447 // set debug mode for this applet 448 set_debug($debugMode); 449 450 ////////////////////////////////////////////////////////// 451 //TEST code 452 // 453 // 454 ////////////////////////////////////////////////////////// 455 456 ww_applet_list["$appletName"] = new ww_applet("$appletName"); 457 458 459 ww_applet_list["$appletName"].code = "$code"; 460 ww_applet_list["$appletName"].codebase = "$codebase"; 461 ww_applet_list["$appletName"].appletID = "$appletID"; 462 ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; 463 ww_applet_list["$appletName"].base64_config = "$base64_config"; 464 ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; 465 ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; 466 ww_applet_list["$appletName"].configAlias = "$configAlias"; 467 ww_applet_list["$appletName"].initializeActionAlias = "$initializeAction"; 468 ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; 469 ww_applet_list["$appletName"].submitActionScript = "$submitActionScript"; 470 ww_applet_list["$appletName"].answerBox = "$answerBox"; 471 ww_applet_list["$appletName"].debug = "$debugMode"; 472 473 </script> 474 475 END_HEADER_SCRIPT 476 477 package FlashApplet; 478 @ISA = qw(Applet); 479 480 481 =head2 Insertion HTML code for FlashApplet 482 483 =pod 484 485 The secret to making this applet work with IE in addition to normal browsers 486 is the addition of the C(<form></form>) construct just before the object. 487 488 For some reason IE has trouble locating a flash object which is contained 489 within a form. Adding this second blank form with the larger problemMainForm 490 seems to solve the problem. 491 492 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2) 493 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated: 494 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js 495 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933 496 497 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 498 <form></form> 499 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 500 id="$appletName" width="500" height="375" 501 codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> 502 <param name="movie" value="$codebase/$appletName.swf" /> 503 <param name="quality" value="high" /> 504 <param name="bgcolor" value="$applet_bgcolor" /> 505 <param name="allowScriptAccess" value="sameDomain" /> 506 <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" 507 width="$width" height="$height" name="$appletName" align="middle" id="$appletName" 508 play="true" loop="false" quality="high" allowScriptAccess="sameDomain" 509 type="application/x-shockwave-flash" 510 pluginspage="http://www.macromedia.com/go/getflashplayer"> 511 </embed> 512 513 </object> 514 END_OBJECT_TEXT 515 516 517 =cut 518 519 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 520 <form></form> 521 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 522 id="$appletName" width="500" height="375" 523 codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> 524 <param name="movie" value="$codebase/$appletName.swf" /> 525 <param name="quality" value="high" /> 526 <param name="bgcolor" value="$applet_bgcolor" /> 527 <param name="allowScriptAccess" value="sameDomain" /> 528 <param name="FlashVars" value="$flashParameters"/> 529 <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" 530 width="$width" height="$height" name="$appletName" align="middle" id="$appletName" 531 play="true" loop="false" quality="high" allowScriptAccess="sameDomain" 532 type="application/x-shockwave-flash" 533 pluginspage="http://www.macromedia.com/go/getflashplayer" 534 FlashVars="$flashParameters"> 535 </embed> 536 537 </object> 538 END_OBJECT_TEXT 539 540 sub new { 541 my $class = shift; 542 $class -> SUPER::new( objectText => DEFAULT_OBJECT_TEXT(), 543 @_ 544 ); 545 546 } 547 548 549 package JavaApplet; 550 @ISA = qw(Applet); 551 552 =head2 Insertion HTML code for JavaApplet 553 554 =pod 555 556 The secret to making this applet work with IE in addition to normal browsers 557 is the addition of the C(<form></form>) construct just before the object. 558 559 For some reason IE has trouble locating a flash object which is contained 560 within a form. Adding this second blank form with the larger problemMainForm 561 seems to solve the problem. 562 563 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2) 564 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated: 565 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js 566 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933 567 568 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 569 <form></form> 570 <applet 571 code = "$code" 572 codebase = "$codebase" 573 archive = "$archive" 574 name = "$appletName" 575 id = "$appletName" 576 width = "$width" 577 height = "$height" 578 MAYSCRIPT 579 > 580 $javaParameters 581 </applet> 582 END_OBJECT_TEXT 583 584 =cut 585 586 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; 587 <form></form> 588 <applet 589 code = "$code" 590 codebase = "$codebase" 591 archive = "$archive" 592 name = "$appletName" 593 id = "$appletName" 594 width = "$width" 595 height = "$height" 596 bgcolor = "$applet_bgcolor" 597 MAYSCRIPT 598 > 599 $javaParameters 600 601 Sorry, the Applet could not be started. Please make sure that 602 Java 1.4.2 (or later) is installed and activated. 603 (<a href="http://java.sun.com/getjava">click here to install Java now</a>) 604 </applet> 605 END_OBJECT_TEXT 606 607 sub new { 608 my $class = shift; 609 $class -> SUPER::new( objectText => DEFAULT_OBJECT_TEXT(), 610 @_ 611 ); 612 613 } 614 615 616 617 1;
aubreyja at gmail dot com | ViewVC Help |
Powered by ViewVC 1.0.9 |