You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(53) |
Feb
(56) |
Mar
|
Apr
|
May
(30) |
Jun
(78) |
Jul
(121) |
Aug
(155) |
Sep
(77) |
Oct
(61) |
Nov
(45) |
Dec
(94) |
2006 |
Jan
(116) |
Feb
(33) |
Mar
(11) |
Apr
(23) |
May
(60) |
Jun
(89) |
Jul
(130) |
Aug
(109) |
Sep
(124) |
Oct
(63) |
Nov
(82) |
Dec
(45) |
2007 |
Jan
(31) |
Feb
(35) |
Mar
(123) |
Apr
(36) |
May
(18) |
Jun
(134) |
Jul
(133) |
Aug
(241) |
Sep
(126) |
Oct
(31) |
Nov
(15) |
Dec
(5) |
2008 |
Jan
(11) |
Feb
(6) |
Mar
(16) |
Apr
(29) |
May
(43) |
Jun
(149) |
Jul
(27) |
Aug
(29) |
Sep
(37) |
Oct
(20) |
Nov
(4) |
Dec
(6) |
2009 |
Jan
(34) |
Feb
(30) |
Mar
(16) |
Apr
(6) |
May
(1) |
Jun
(32) |
Jul
(22) |
Aug
(7) |
Sep
(18) |
Oct
(50) |
Nov
(22) |
Dec
(8) |
2010 |
Jan
(17) |
Feb
(15) |
Mar
(10) |
Apr
(9) |
May
(67) |
Jun
(30) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
|
From: Gavin L. v. a. <we...@ma...> - 2009-06-04 14:04:26
|
Log Message: ----------- WWPlot: slightly better choice of dash-length and spacing for dashing option on lines and arrows. Modified Files: -------------- pg/lib: WWPlot.pm Revision Data ------------- Index: WWPlot.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WWPlot.pm,v retrieving revision 1.5 retrieving revision 1.6 diff -Llib/WWPlot.pm -Llib/WWPlot.pm -u -r1.5 -r1.6 --- lib/WWPlot.pm +++ lib/WWPlot.pm @@ -380,8 +380,8 @@ $self->im->setThickness( $w ); if ( $d ) { - my @dashing = ( $color )x(4*$w); - my @spacing = ( GD::gdTransparent )x(4*$w); + my @dashing = ( $color )x(4*$w*$w); + my @spacing = ( GD::gdTransparent )x(3*$w*$w); $self->im->setStyle( @dashing, @spacing ); $self->im->line(@{$self->position},$x,$y,GD::gdStyled); } else { @@ -433,8 +433,8 @@ $head->addPt($hbx - 2*$width*$px, $hby - 2*$width*$py); $self->im->filledPolygon( $head, $color ); if ( $d ) { - my @dashing = ( $color )x(4*$w); - my @spacing = ( GD::gdTransparent )x(4*$w); + my @dashing = ( $color )x(4*$w*$w); + my @spacing = ( GD::gdTransparent )x(3*$w*$w); $self->im->setStyle( @dashing, @spacing ); $self->im->line( $x0,$y0,$x1,$y1,GD::gdStyled); } else { |
From: Mike G. v. a. <we...@ma...> - 2009-06-04 02:35:34
|
Log Message: ----------- Added a provision allowing "email instructor" button to MathNerds. Modified Files: -------------- webwork2/lib/WeBWorK: ContentGenerator.pm Revision Data ------------- Index: ContentGenerator.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator.pm,v retrieving revision 1.195 retrieving revision 1.196 diff -Llib/WeBWorK/ContentGenerator.pm -Llib/WeBWorK/ContentGenerator.pm -u -r1.195 -r1.196 --- lib/WeBWorK/ContentGenerator.pm +++ lib/WeBWorK/ContentGenerator.pm @@ -51,6 +51,7 @@ use URI::Escape; use WeBWorK::Debug; use WeBWorK::PG; +use MIME::Base64; use WeBWorK::Template qw(template); use mod_perl; @@ -1457,8 +1458,11 @@ return "" unless $authz->hasPermissions($userID, "submit_feedback"); my $feedbackURL = $r->ce->{courseURLs}{feedbackURL}; + my $feedbackFormURL = $r->ce->{courseURLs}{feedbackFormURL}; if (defined $feedbackURL and $feedbackURL ne "") { return $self->feedbackMacro_url($feedbackURL); + } elsif (defined $feedbackFormURL and $feedbackFormURL ne "") { + return $self->feedbackMacro_form($feedbackFormURL,%params); } else { return $self->feedbackMacro_email(%params); } @@ -1480,6 +1484,7 @@ $result .= $self->hidden_authen_fields . "\n"; while (my ($key, $value) = each %params) { + next if $key eq 'pg_object'; # not used in internal feedback mechanism $result .= CGI::hidden($key, $value) . "\n"; } $result .= CGI::p({-align=>"left"}, CGI::submit(-name=>"feedbackForm", -label=>$feedbackName)); @@ -1488,6 +1493,34 @@ return $result; } +sub feedbackMacro_form { + my ($self, $feedbackFormURL, %params) = @_; + my $r = $self->r; + my $ce = $r->ce; + my $urlpath = $r->urlpath; + my $courseID = $urlpath->arg("courseID"); + + # feedback form url + my $feedbackName = $ce->{feedback_button_name} || "Email instructor"; + + my $result = CGI::start_form(-method=>"POST", -action=>$feedbackFormURL,-target=>"WW_info") . "\n"; + $result .= $self->hidden_authen_fields . "\n"; + + while (my ($key, $value) = each %params) { + if ($key eq 'pg_object') { + my $tmp = $value->{body_text}; + $tmp .= CGI::p(CGI::b("Note: "). CGI::i($value->{result}->{msg})) if $value->{result}->{msg} ; + $result .= CGI::hidden($key, encode_base64($tmp, "") ); + } else { + $result .= CGI::hidden($key, $value) . "\n"; + } + } + $result .= CGI::p({-align=>"left"}, CGI::submit(-name=>"feedbackForm", -label=>$feedbackName)); + $result .= CGI::endform() . "\n"; + + return $result; +} + sub feedbackMacro_url { my ($self, $url) = @_; my $feedbackName = $self->r->ce->{feedback_button_name} || "Email instructor"; |
From: Mike G. v. a. <we...@ma...> - 2009-06-04 02:35:13
|
Log Message: ----------- update certain tmp files for courses automatically -- this reduces the number of error messageswhen viewing old courses. Modified Files: -------------- webwork2/lib/WeBWorK/Utils: CourseIntegrityCheck.pm Revision Data ------------- Index: CourseIntegrityCheck.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Utils/CourseIntegrityCheck.pm,v retrieving revision 1.4 retrieving revision 1.5 diff -Llib/WeBWorK/Utils/CourseIntegrityCheck.pm -Llib/WeBWorK/Utils/CourseIntegrityCheck.pm -u -r1.4 -r1.5 --- lib/WeBWorK/Utils/CourseIntegrityCheck.pm +++ lib/WeBWorK/Utils/CourseIntegrityCheck.pm @@ -320,7 +320,7 @@ my @webworkDirectories = keys %{$ce->{webworkDirs}}; my @courseDirectories = keys %{$ce->{courseDirs}}; - my %updateable_directories = (html_temp=>1); #FIXME this is hardwired for the time being. + my %updateable_directories = (html_temp=>1,mailmerge=>1,tmpEditFileDir=>1); #FIXME this is hardwired for the time being. foreach my $dir (sort @courseDirectories) { next unless exists $updateable_directories{$dir}; |
From: Mike G. v. a. <we...@ma...> - 2009-06-04 02:34:49
|
Log Message: ----------- update certain tmp files for courses automatically -- this reduces the number of error messages when viewing old courses. Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator: CourseAdmin.pm Revision Data ------------- Index: CourseAdmin.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm,v retrieving revision 1.83 retrieving revision 1.84 diff -Llib/WeBWorK/ContentGenerator/CourseAdmin.pm -Llib/WeBWorK/ContentGenerator/CourseAdmin.pm -u -r1.83 -r1.84 --- lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -384,6 +384,7 @@ my $CIchecker = new WeBWorK::Utils::CourseIntegrityCheck(ce=>$tempCE); my ($tables_ok,$dbStatus) = $CIchecker->checkCourseTables($courseID); + $CIchecker->updateCourseDirectories(); #creates missing html_temp, mailmerge tmpEditFileDir directories; my ($directories_ok, $str2) = $CIchecker->checkCourseDirectories(); print CGI::li(CGI::a({href=>$self->systemLink($urlpath, authen => 0)}, $courseID), CGI::code( |
From: Mike G. v. a. <we...@ma...> - 2009-06-04 02:34:26
|
Log Message: ----------- Added a feature which allows connection of "email instructor" feature to MathNerds. Specifically the reference to the $pg object is passed back to the feedbackMacro as a parameter. Modified Files: -------------- webwork2/lib/WeBWorK/ContentGenerator: Problem.pm Revision Data ------------- Index: Problem.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm,v retrieving revision 1.216 retrieving revision 1.217 diff -Llib/WeBWorK/ContentGenerator/Problem.pm -Llib/WeBWorK/ContentGenerator/Problem.pm -u -r1.216 -r1.217 --- lib/WeBWorK/ContentGenerator/Problem.pm +++ lib/WeBWorK/ContentGenerator/Problem.pm @@ -1191,6 +1191,7 @@ showCorrectAnswers => $will{showCorrectAnswers}, showHints => $will{showHints}, showSolutions => $will{showSolutions}, + pg_object => $pg, ); print CGI::end_div(); |
From: Mike G. v. a. <we...@ma...> - 2009-06-04 02:13:46
|
Log Message: ----------- update applet support code Modified Files: -------------- webwork2/htdocs/js: ww_applet_support.js Revision Data ------------- Index: ww_applet_support.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/js/ww_applet_support.js,v retrieving revision 1.9 retrieving revision 1.10 diff -Lhtdocs/js/ww_applet_support.js -Lhtdocs/js/ww_applet_support.js -u -r1.9 -r1.10 --- htdocs/js/ww_applet_support.js +++ htdocs/js/ww_applet_support.js @@ -67,9 +67,9 @@ } // applet can set isReady flag by calling applet_loaded(appletName, loaded); -function applet_loaded(appletName,loaded) { - debug_add("applet reporting that it has been loaded = " + loaded ); - ww_applet_list[appletName].reportsLoaded = loaded; // 0 means not loaded +function applet_loaded(appletName,ready) { + debug_add("applet reporting that it has been loaded = " + ready ); + ww_applet_list[appletName].reportsLoaded = ready; // 0 means not loaded } @@ -209,17 +209,21 @@ var applet = getApplet(appletName); var setConfigAlias = this.setConfigAlias; - try { - if ( this.methodDefined(setConfigAlias) ) { + + try { + if ( this.methodDefined(this.setConfigAlias) ) { applet[setConfigAlias](this.configuration); - } + this.debug_add(" Calling " + appletName +"."+ setConfigAlias +"( " + this.configuration + " ) " ); + } else { + this.debug_add(" unable to execute " + appletName +"."+ setConfigAlias +"( " + this.configuration + " ) " ); + } } catch(e) { var msg = "Error in configuring " + appletName + " using command " + setConfigAlias + " : " + e ; alert(msg); } - this.debug_add(" Calling " + appletName +"."+ setConfigAlias +"( " + this.configuration + " ) " ); + }; @@ -273,11 +277,15 @@ if ( base64Q(state) ) { state=Base64.decode(state); } - - if (state.match(/^<xml>restart_applet<\/xml>/) ) { - alert("The applet " +appletName + "has been reset to its virgin state." + this.initialState); + if (state.match(/^<xml>restart_applet<\/xml>/) || + state.match(/^\s*$/) || + state.match(/^<xml>\s*<\/xml>/ ) ) { + //blank state also restarts applet ww_preserve_applet_state.value =this.initialState; //Fixme? should we set the last answer to blank as well? state = ww_preserve_applet_state.value; + if (state.match(/^<xml>restart_applet<\/xml>/) ) { + alert("The applet " +appletName + "has been reset to its virgin state." + this.initialState); + } } if (state.match(/<xml/i) || state.match(/<?xml/i) ) { // if state starts with <?xml @@ -398,7 +406,7 @@ eval(this.submitActionScript); //getQE(this.answerBox).value = applet.[getAnswer](); //FIXME -- not needed in general? this.debug_add("Completed submitAction(" + this.submitActionScript + ") \nfor applet " + appletName+ "\n"); - if (this.debugMode){alert(debugText); debugText="";} + if (this.debugMode>=2){alert(debugText); debugText="";} }; @@ -418,13 +426,23 @@ this.debug_add("Test 4 methods to see if the applet " + appletName + " has been loaded: \n"); + try { + if ( this.methodDefined(this.setConfigAlias) ) { + ready = 1; + } + } catch(e) { + var msg = "Unable to find set configuration command in applet " + appletName; + alert(msg); + } - if ( this.methodDefined(this.setConfigAlias) ) { - ready = 1; + try { + if ( this.methodDefined(this.setStateAlias) ) { + ready =1; + } + } catch(e) { + var msg = "Unable to set State command in applet " + appletName; + alert(msg); } - if ( this.methodDefined(this.setStateAlias) ) { - ready =1; - } if (typeof(this.reportsLoaded) !="undefined" && this.reportsLoaded != 0 ) { @@ -449,7 +467,7 @@ return(ready); } ww_applet.prototype.debug_add = function(str) { - if (this.debugMode) { + if (this.debugMode>=2) { debugText = debugText + "\n" +str; // a global text string } } @@ -475,7 +493,7 @@ if ( 0 < i && !applet_loaded ) { // wait until applet is loaded this.debug_add("Applet " + appletName + " is not yet ready try again\n"); - if (this.debugMode) { + if (this.debugMode>=2) { alert(debugText ); debugText=""; } @@ -492,11 +510,11 @@ //alert("setDebug") try{ - this.setDebug(this.debugMode); + this.setDebug((this.debugMode) ? 1:0); } catch(e) { var msg = "Unable set debug in " + appletName + " \n " +e; - if (this.debugMode) {this.debug_add(msg);} else {alert(msg)}; + if (this.debugMode>=2) {this.debug_add(msg);} else {alert(msg)}; } //alert("config applet"); @@ -506,7 +524,7 @@ } catch(e) { var msg = "Unable to configure " + appletName + " \n " +e; - if (this.debugMode) {this.debug_add(msg);} else {alert(msg)}; + if (this.debugMode>=2) {this.debug_add(msg);} else {alert(msg)}; } @@ -517,20 +535,20 @@ } catch(e) { var msg = "unable to initialize " + appletName + " \n " +e; - if (this.debugMode) { + if (this.debugMode>=2) { this.debug_add(msg); } else { alert(msg); } } - if (this.debugMode) { + if (this.debugMode>=2) { alert("\nBegin debugmode\n " + debugText ); debugText=""; }; } else { this.debug_add("Error: timed out waiting for applet " +appletName + " to load"); //alert("4 jsDebugMode " + jsDebugMode + " applet debugMode " +ww_applet.debugMode + " local debugMode " +debugMode); - if (this.debugMode) { + if (this.debugMode>=2) { alert(" in safe applet " + debugText ); debugText=""; } |
From: Gavin L. v. a. <we...@ma...> - 2009-06-03 21:30:27
|
Log Message: ----------- WWPlot: add a dashed option to lines and arrows Modified Files: -------------- pg/lib: WWPlot.pm Revision Data ------------- Index: WWPlot.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WWPlot.pm,v retrieving revision 1.4 retrieving revision 1.5 diff -Llib/WWPlot.pm -Llib/WWPlot.pm -u -r1.4 -r1.5 --- lib/WWPlot.pm +++ lib/WWPlot.pm @@ -147,13 +147,16 @@ $graph->moveTo($x,$y); $graph->lineTo($x,$y,$color); $graph->lineTo($x,$y,$color,$thickness); + $graph->lineTo($x,$y,$color,$thickness,'dashed'); $graph->arrowTo($x,$y,$color); $graph->arrowTo($x,$y,$color,$thickness); + $graph->arrowTo($x,$y,$color,$thickness,'dashed'); Moves to the point ($x, $y) (defined in real world coordinates) or draws a line or arrow from the current position to the specified point ($x, $y) using the color $color. $color is the name, e.g. 'white', of the color, not an index value or RGB specification. -$thickness gives the thickness of the line or arrow to draw. These are low level call +$thickness gives the thickness of the line or arrow to draw. If 'dashed' is specified, +the line or arrow is rendered with a dashed line. These are low level call back routines used by the function, label and stamp objects to draw themselves. =item ii, jj @@ -366,8 +369,9 @@ sub lineTo { my $self = shift; - my ($x,$y,$color, $w) = @_; + my ($x,$y,$color, $w, $d) = @_; $w = 1 if ! defined( $w ); + $d = 0 if ! defined( $d ); ## draw a dashed line? $x=$self->ii($x); $y=$self->jj($y); @@ -375,7 +379,14 @@ $color = $self->{'colors'}{'default_color'} unless defined($color); $self->im->setThickness( $w ); - $self->im->line(@{$self->position},$x,$y,$color); + if ( $d ) { + my @dashing = ( $color )x(4*$w); + my @spacing = ( GD::gdTransparent )x(4*$w); + $self->im->setStyle( @dashing, @spacing ); + $self->im->line(@{$self->position},$x,$y,GD::gdStyled); + } else { + $self->im->line(@{$self->position},$x,$y,$color); + } $self->im->setThickness( 1 ); #warn "color is $color"; @{$self->position} = ($x,$y); @@ -393,8 +404,9 @@ sub arrowTo { my $self = shift; - my ( $x1, $y1, $color, $w ) = @_; + my ( $x1, $y1, $color, $w, $d ) = @_; $w = 1 if ! defined( $w ); + $d = 0 if ! defined( $d ); my $width = ( $w == 1 ) ? 2 : $w; $x1 = $self->ii($x1); @@ -420,7 +432,14 @@ $head->addPt($hbx + 2*$width*$px, $hby + 2*$width*$py); $head->addPt($hbx - 2*$width*$px, $hby - 2*$width*$py); $self->im->filledPolygon( $head, $color ); - $self->im->line( $x0,$y0,$x1,$y1,$color ); + if ( $d ) { + my @dashing = ( $color )x(4*$w); + my @spacing = ( GD::gdTransparent )x(4*$w); + $self->im->setStyle( @dashing, @spacing ); + $self->im->line( $x0,$y0,$x1,$y1,GD::gdStyled); + } else { + $self->im->line( $x0,$y0,$x1,$y1,$color ); + } @{$self->position} = ( $x1, $y1 ); |
From: Gavin L. v. a. <we...@ma...> - 2009-06-03 19:37:58
|
Log Message: ----------- WWPlot: add arrowTo() method, support for width in lineTo() Modified Files: -------------- pg/lib: WWPlot.pm Revision Data ------------- Index: WWPlot.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/WWPlot.pm,v retrieving revision 1.3 retrieving revision 1.4 diff -Llib/WWPlot.pm -Llib/WWPlot.pm -u -r1.3 -r1.4 --- lib/WWPlot.pm +++ lib/WWPlot.pm @@ -142,16 +142,19 @@ to access methods defined in GD but not supported directly by WWPlot. (See the documentation for GD.) -=item moveTo, lineTo +=item moveTo, lineTo, arrowTo $graph->moveTo($x,$y); $graph->lineTo($x,$y,$color); - -Moves to the point ($x, $y) (defined in real world coordinates) or draws a line from the -current position to the specified point ($x, $y) using the color $color. $color is the -name, e.g. 'white', of the color, not an index value or RGB specification. These are -low level call back routines used by the function, label and stamp objects to draw themselves. - + $graph->lineTo($x,$y,$color,$thickness); + $graph->arrowTo($x,$y,$color); + $graph->arrowTo($x,$y,$color,$thickness); + +Moves to the point ($x, $y) (defined in real world coordinates) or draws a line or arrow +from the current position to the specified point ($x, $y) using the color $color. $color +is the name, e.g. 'white', of the color, not an index value or RGB specification. +$thickness gives the thickness of the line or arrow to draw. These are low level call +back routines used by the function, label and stamp objects to draw themselves. =item ii, jj @@ -363,12 +366,17 @@ sub lineTo { my $self = shift; - my ($x,$y,$color) = @_; + my ($x,$y,$color, $w) = @_; + $w = 1 if ! defined( $w ); + $x=$self->ii($x); $y=$self->jj($y); $color = $self->{'colors'}{$color} if $color=~/[A-Za-z]+/ && defined($self->{'colors'}{$color}) ; # colors referenced by name works here. $color = $self->{'colors'}{'default_color'} unless defined($color); + + $self->im->setThickness( $w ); $self->im->line(@{$self->position},$x,$y,$color); + $self->im->setThickness( 1 ); #warn "color is $color"; @{$self->position} = ($x,$y); } @@ -383,6 +391,44 @@ @{$self->position} = ( $x,$y ); } +sub arrowTo { + my $self = shift; + my ( $x1, $y1, $color, $w ) = @_; + $w = 1 if ! defined( $w ); + my $width = ( $w == 1 ) ? 2 : $w; + + $x1 = $self->ii($x1); + $y1 = $self->jj($y1); + $color = $self->{'colors'}{$color} if $color=~/[A-Za-z]+/ && defined($self->{'colors'}{$color}) ; + $color = $self->{'colors'}{'default_color'} unless defined($color); + + ## set thickness + $self->im->setThickness($w); + + my ($x0, $y0) = @{$self->position}; + my $dx = $x1 - $x0; + my $dy = $y1 - $y0; + my $len = sqrt($dx*$dx + $dy*$dy); + my $ux = $dx/$len; ## a unit vector in the direction of the arrow + my $uy = $dy/$len; + my $px = -1*$uy; ## a unit vector perpendicular + my $py = $ux; + my $hbx = $x1 - 5*$width*$ux; ## the base of the arrowhead + my $hby = $y1 - 5*$width*$uy; + my $head = new GD::Polygon; + $head->addPt($x1,$y1); + $head->addPt($hbx + 2*$width*$px, $hby + 2*$width*$py); + $head->addPt($hbx - 2*$width*$px, $hby - 2*$width*$py); + $self->im->filledPolygon( $head, $color ); + $self->im->line( $x0,$y0,$x1,$y1,$color ); + + @{$self->position} = ( $x1, $y1 ); + + ## reset thickness + $self->im->setThickness(1); +} + + sub v_axis { my $self = shift; @{$self->{vaxis}}=@_; # y_value, color |
From: dpvc v. a. <we...@ma...> - 2009-05-24 20:07:24
|
Log Message: ----------- make sure formulas are in the correct context Modified Files: -------------- pg/macros: parserImplicitEquation.pl Revision Data ------------- Index: parserImplicitEquation.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserImplicitEquation.pl,v retrieving revision 1.12 retrieving revision 1.13 diff -Lmacros/parserImplicitEquation.pl -Lmacros/parserImplicitEquation.pl -u -r1.12 -r1.13 --- macros/parserImplicitEquation.pl +++ macros/parserImplicitEquation.pl @@ -214,12 +214,12 @@ my $self = shift; my $class = ref($self) || $self; my $context = (Value::isContext($_[0]) ? shift : $self->context); my $f = shift; return $f if ref($f) eq $class; - $f = main::Formula($f); + $f = $context->Package("Formula")->new($context,$f); Value::Error("Your formula doesn't look like an implicit equation") unless $f->type eq 'Equality'; my $F = ($context->Package("Formula")->new($context,$f->{tree}{lop}) - $context->Package("Formula")->new($context,$f->{tree}{rop}))->reduce; - $F = $context->Package("Formula")->new($F) unless Value::isFormula($F); + $F = $context->Package("Formula")->new($context,$F) unless Value::isFormula($F); Value::Error("Your equation must be real-valued") unless $F->isRealNumber; Value::Error("Your equation should not be constant") if $F->isConstant; Value::Error("Your equation can not contain adaptive parameters") |
From: Mike G. v. a. <we...@ma...> - 2009-04-28 18:33:11
|
Log Message: ----------- cumulative updates made while developing Applet.pm on hosted2 Modified Files: -------------- pg/lib: Applet.pm Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.22 retrieving revision 1.23 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.22 -r1.23 --- lib/Applet.pm +++ lib/Applet.pm @@ -40,18 +40,17 @@ ################################### #data to set up the equation -$applet->config(qq{<XML expr='(x - $a)^3 + $b/$a * x' />}); +$applet->configuration(qq{<XML expr='(x - $a)^3 + $b/$a * x' />}); # initial points -$applet->state(qq{<XML> -</XML>}); +$applet->intialState(qq{<XML> </XML>}); ################################### #insert applet into body ################################### TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll( - includeAnswerBox => 1 - debug=>0, - reinitialize_button=>1, + includeAnswerBox => 1 + debug=>0, + reinitialize_button=>1, ))); @@ -103,7 +102,7 @@ These functions are automatically defined for use for any javaScript placed in the text of a PG question. - getApplet(appletName) -- finds the applet path in the DOM + getApplet(appletName) -- finds the applet path in the DOM submitAction() -- calls the submit action of the applets @@ -118,7 +117,8 @@ listQuestionElements() -- for discovering the names of inputs in the PG question. An alert dialog will list all of the elements. - Usage: Place this at the END of the question, just before END_DOCUMENT(): + + Usage: Place this at the END of the question, just before END_DOCUMENT(): TEXT(qq!<script> listQuestionElements() </script>!); ENDDOCUMENT(); @@ -139,50 +139,85 @@ ); - appletId for simplicity and reliability appletId and appletName are always the same + appletId for simplicity and reliability appletId and appletName are always the same appletName archive the name of the .jar file containing the applet code code the name of the applet code in the .jar archive codebase a prefix url used to find the archive and the applet itself - - height rectangle alloted in the html page for displaying the applet - + params an anonymous array containing name/value pairs to configure the applet [name =>'value, ...] + + width rectangle alloted in the html page for displaying the applet + height + bgcolor background color of the applet rectangle + header stores the text to be added to the header section of the html page object stores the text which places the applet on the html page - debugMode in debug mode several alerts mark progress through the procedure of calling the applet configuration configuration contains those customizable attributes of the applet which don't change as it is used. When stored in hidden answer fields it is usually stored in base64 encoded format. - - configAlias (default: setConfig ) names the applet command called with the contents of $self->config - to configure the applet. The parameters are passed to the applet in plain text using <xml> - The outer tags must be <xml> ..... </xml> - setConfigAlias (default: setConfig) -- a synonym for configAlias - getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used - mainly for debugging. In principal the configuration remains the same for a given instance - of the applet -- i.e. for the homework question for a single student. The state however - will change depending on the interactions between the student and the applet. initialState the state consists of those customizable attributes of the applet which change as the applet is used by the student. It is stored by the calling .pg question so that - when revisiting the question the applet will be restored to the same state it was left in when the question was last - viewed. - + when revisiting the question the applet will be restored to the same state it was + left in when the question was last viewed. + getStateAlias (default: getState) alias for command called to read the current state of the applet. The state is passed in plain text xml format with outer tags: <xml>....</xml> setStateAlias (default: setState) alias for the command called to reset the state of the applet. The state is passed in plain text in xml format with outer tags: <xml>....</xml> - initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState - submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the + configAlias (deprecated) -- a synonym for configAlias + + getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used + mainly for debugging. In principal the configuration remains the same for a given instance + of the applet -- i.e. for the homework question for a single student. The state however + will change depending on the interactions between the student and the applet. + setConfigAlias (default: setConfig ) names the applet command called with the contents of $self->config + to configure the applet. The parameters are passed to the applet in plain text using <xml> + The outer tags must be <xml> ..... </xml> + + + initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called + to initialize the applet (some overlap with config/ and setState + maxInitializationAttempts -- (default: 5) number attempts to test applet to see if it is installed. + If isActive() exists then the WW question waits until the return value is 1 before + calling the applet's confguration commands. + Because some applets have isActive return 0 even when they are ready, + if isActive() exists but does not return 1 then the applet's configuration commands + are called after maxInitializationAttempts number of times. If none of the configuration commands + of the applet can be detected then the WW question gives up after maxInitializationAttempts. + + submitActionAlias -- (default: getXML) applet subroutine called when the submit button of the .pg question is pressed. + submitActionScript -- (default: qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() }, + answerBoxAlias -- name of answer box to return answer to: default defaultAnswerBox - getAnswer -- (formerly sendData) get student answer from applet and place in answerBox returnFieldName -- (deprecated) synonmym for answerBoxAlias + + + debugMode (default: 0) for debugMode==1 the answerBox and the box preserving the applet state + between questions are made visible along with some buttons for manually getting the state of + the applet and setting the state of the applet. + + for debugMode==2, in addition to the answerBox and stateBox there are several alerts + which mark progress through the procedures of calling the applet. Useful for troubleshooting + where in the chain of command a communication failure occurs + + + Methods: + + insertHeader -- inserts text in header section of HTML page + insertObject -- inserts <object></object> or <applet></applet> tag in body of the HTML page + insertAll -- (defined in AppletObjects.pl) installs applet by inserting both header text and the object text + Usage: $applet->insertAll( + includeAnswerBox => 0, + debugMode => 0, + reinitialize_button =>0, + ); =cut @@ -263,21 +298,16 @@ =cut -=head4 Initialization sequence -When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them -to initialize themselves. -The applets initialization method is as follows: - - -- wait until the applet is loaded and the applet has loaded all of its auxiliary files. - -- set the debugMode in the applet - -- call the setConfig method in the javaScript applet -- (configuration parameters are "permanent" for the life of the applet - -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet +=head4 Instance variables in the javaScript applet ww_applet_list[appletName] + Most of the instance variables in the perl version of the applet are transferred to the javaScript applet + =cut -=head Methods defined for the javaScript applet ww_applet_list[appletName] + +=head4 Methods defined for the javaScript applet ww_applet_list[appletName] This is not a comprehensive list @@ -294,22 +324,7 @@ getState -- retrieves the current state and stores in the appletName_state HTML element. - - - - - -=head Submit sequence - -When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks -each of the applets on the page to perform its submit action which consists of - - -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then - the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml> - to be interpreted by the next setState command - -- Otherwise getState() from the applet and save it to the HTML input element appletName_state - -- Perform the javaScript commands in .submitActionScript (default: '' ) - a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer() ) +=cut =head4 Requirements for applets @@ -351,19 +366,48 @@ =cut +=head4 Initialization sequence + +When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them +to initialize themselves. + +The applets initialization method is as follows: + + -- wait until the applet is loaded and the applet has loaded all of its auxiliary files. + -- set the debugMode in the applet + -- call the setConfig method in the javaScript applet -- (configuration parameters are "permanent" for the life of the applet + -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet + +=cut + + +=head Submit sequence + +When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks +each of the applets on the page to perform its submit action which consists of + + -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then + the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml> + to be interpreted by the next setState command + -- Otherwise getState() from the applet and save it to the HTML input element appletName_state + -- Perform the javaScript commands in .submitActionScript (default: '' ) + a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer() ) + +=cut + + sub new { my $class = shift; my $self = { - appletName =>'', - code=>'', - codebase=>'', -# appletId =>'', #always use identical applet Id's and applet Names + appletName => '', +# appletId => '', #always use identical applet Id's and applet Names + archive => '', + code => '', + codebase => '', params =>undef, width => 550, height => 400, bgcolor => "#869ca7", -# base64_state => undef, # this is a state to use for initializing the first occurence of the question. -# base64_config => undef, # this is the initial (and final?) configuration configuration => '', # configuration defining the applet initialState => '', # initial state. getStateAlias => 'getXML', @@ -397,6 +441,56 @@ $self->configuration('<xml></xml>'); return $self; } +sub appletId { + appletName(@_); +} +sub appletName { + my $self = shift; + $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty + $self->{appletName}; +} +sub archive { + my $self = shift; + $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty + $self->{archive}; +} +sub code { + my $self = shift; + $self->{code} = shift ||$self->{code}; # replace the current code if non-empty + $self->{code}; +} +sub codebase { + my $self = shift; + $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty + $self->{codebase}; +} +sub params { + my $self = shift; + if (ref($_[0]) =~/HASH/) { + $self->{params} = shift; + } elsif ( !defined($_[0]) or $_[0] =~ '') { + # do nothing (read) + } else { + warn "You must enter a reference to a hash for the parameter list"; + } + $self->{params}; +} + +sub width { + my $self = shift; + $self->{width} = shift ||$self->{width}; # replace the current width if non-empty + $self->{width}; +} +sub height { + my $self = shift; + $self->{height} = shift ||$self->{height}; # replace the current height if non-empty + $self->{height}; +} +sub bgcolor { + my $self = shift; + $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty + $self->{bgcolor}; +} sub header { my $self = shift; @@ -416,34 +510,21 @@ } $self->{objectText}; } -sub params { - my $self = shift; - if (ref($_[0]) =~/HASH/) { - $self->{params} = shift; - } elsif ( !defined($_[0]) or $_[0] =~ '') { - # do nothing (read) - } else { - warn "You must enter a reference to a hash for the parameter list"; - } - $self->{params}; -} - -sub initializeActionAlias { +sub configuration { my $self = shift; - $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty - $self->{initializeActionAlias}; + my $str = shift; + $self->{configuration} = $str || $self->{configuration}; # replace the current string if non-empty + $self->{configuration} =~ s/\n//g; + $self->{configuration}; } -sub submitActionAlias { - my $self = shift; - $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty - $self->{submitActionAlias}; -} -sub submitActionScript { +sub initialState { my $self = shift; - $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty - $self->{submitActionScript}; + my $str = shift; + $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty + $self->{initialState}; } + sub getStateAlias { my $self = shift; $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty @@ -455,89 +536,52 @@ $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty $self->{setStateAlias}; } -sub configAlias { + +sub getConfigAlias { my $self = shift; - $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty - $self->{setConfigAlias}; + $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty + $self->{getConfigAlias}; } sub setConfigAlias { my $self = shift; $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty $self->{setConfigAlias}; } -sub getConfigAlias { - my $self = shift; - $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty - $self->{getConfigAlias}; -} -sub answerBoxName { - my $self = shift; - $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty - $self->{answerBox}; -} -sub codebase { - my $self = shift; - $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty - $self->{codebase}; -} -sub code { - my $self = shift; - $self->{code} = shift ||$self->{code}; # replace the current code if non-empty - $self->{code}; -} -sub height { +sub initializeActionAlias { my $self = shift; - $self->{height} = shift ||$self->{height}; # replace the current height if non-empty - $self->{height}; + $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty + $self->{initializeActionAlias}; } -sub width { +sub maxInitializationAttempts { my $self = shift; - $self->{width} = shift ||$self->{width}; # replace the current width if non-empty - $self->{width}; -} -sub bgcolor { + $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts}; + $self->{maxInitializationAttempts}; +} +sub submitActionAlias { my $self = shift; - $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty - $self->{bgcolor}; + $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty + $self->{submitActionAlias}; } -sub archive { +sub submitActionScript { my $self = shift; - $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty - $self->{archive}; + $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty + $self->{submitActionScript}; } -sub appletName { + +sub answerBoxAlias { my $self = shift; - $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty - $self->{appletName}; + $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty + $self->{answerBox}; } + sub debugMode { my $self = shift; my $new_flag = shift; $self->{debugMode} = $new_flag if defined($new_flag); $self->{debugMode}; } -sub appletId { - appletName(@_); -} -sub maxInitializationAttempts { - my $self = shift; - $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts}; - $self->{maxInitializationAttempts}; -} -sub initialState { - my $self = shift; - my $str = shift; - $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty - $self->{initialState}; -} -sub configuration { - my $self = shift; - my $str = shift; - $self->{configuration} = $str || $self->{configuration}; # replace the current string if non-empty - $self->{configuration} =~ s/\n//g; - $self->{configuration}; -} + ####################### # soon to be deprecated? @@ -579,6 +623,10 @@ my $self = shift; warn "use answerBoxAlias instead of AnswerBox"; } +sub configAlias { + my $self = shift; + warn "use setConfigAlias instead of configAlias"; +} ######################### #FIXME # need to be able to adjust header material @@ -622,40 +670,7 @@ } -sub insertObject { - my $self = shift; - my $code = $self->{code}; - my $codebase = $self->{codebase}; - my $appletId = $self->{appletName}; - my $appletName = $self->{appletName}; - my $archive = $self->{archive}; - my $width = $self->{width}; - my $height = $self->{height}; - my $applet_bgcolor = $self->{bgcolor}; - my $javaParameters = ''; - my $flashParameters = ''; - my %param_hash = %{$self->params()}; - foreach my $key (keys %param_hash) { - $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; - $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&'; - } - $flashParameters =~ s/\&$//; # trim last & - - $objectText = $self->{objectText}; - $objectText =~ s/(\$\w+)/$1/gee; - return $objectText; -} -# sub initialize { -# my $self = shift; -# return q{ -# <script> -# initializeAllApplets(); -# // this should really be done in the <body> tag -# </script> -# }; -# -# } ######################################################## # HEADER material for one flash or java applet ######################################################## @@ -701,6 +716,33 @@ END_HEADER_SCRIPT + + +sub insertObject { + my $self = shift; + my $code = $self->{code}; + my $codebase = $self->{codebase}; + my $appletId = $self->{appletName}; + my $appletName = $self->{appletName}; + my $archive = $self->{archive}; + my $width = $self->{width}; + my $height = $self->{height}; + my $applet_bgcolor = $self->{bgcolor}; + my $javaParameters = ''; + my $flashParameters = ''; + my %param_hash = %{$self->params()}; + foreach my $key (keys %param_hash) { + $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; + $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&'; + } + $flashParameters =~ s/\&$//; # trim last & + + + $objectText = $self->{objectText}; + $objectText =~ s/(\$\w+)/$1/gee; + return $objectText; +} + package FlashApplet; @ISA = qw(Applet); |
From: Mike G. v. a. <we...@ma...> - 2009-04-28 18:18:59
|
Log Message: ----------- comma typo. Fixes bug 1644 in rel-2-4-patches version of Applet.pm Tags: ---- rel-2-4-patches Modified Files: -------------- pg/lib: Applet.pm Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.12.2.1.2.1 retrieving revision 1.12.2.1.2.2 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.12.2.1.2.1 -r1.12.2.1.2.2 --- lib/Applet.pm +++ lib/Applet.pm @@ -396,7 +396,7 @@ my $self = { appletName => '', # appletId => '', #always use identical applet Id's and applet Names - archive => '' + archive => '', code => '', codebase => '', params =>undef, |
From: dpvc v. a. <we...@ma...> - 2009-04-05 22:52:40
|
Log Message: ----------- remove number pattern so that strings can start with digits Modified Files: -------------- pg/macros: contextString.pl Revision Data ------------- Index: contextString.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextString.pl,v retrieving revision 1.14 retrieving revision 1.15 diff -Lmacros/contextString.pl -Lmacros/contextString.pl -u -r1.14 -r1.15 --- macros/contextString.pl +++ macros/contextString.pl @@ -80,6 +80,7 @@ sub Init { my $context = $main::context{String} = Parser::Context->getCopy("Numeric"); $context->{name} = "String"; + $context->{pattern}{number} = qr/^$/; $context->parens->clear(); $context->variables->clear(); $context->constants->clear(); |
From: Mike G. v. a. <we...@ma...> - 2009-04-01 04:04:15
|
Log Message: ----------- backport the new applet API from head. Tags: ---- rel-2-4-patches Modified Files: -------------- pg/lib: Applet.pm Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.12.2.1 retrieving revision 1.12.2.1.2.1 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.12.2.1 -r1.12.2.1.2.1 --- lib/Applet.pm +++ lib/Applet.pm @@ -23,39 +23,35 @@ ################################### # Create link to applet ################################### - my $appletName = "LineThruPointsWW"; - $applet = new FlashApplet( - # can be replaced by $applet =FlashApplet() when using AppletObjects.pl - codebase => findAppletCodebase("$appletName.swf"), - appletName => $appletName, - appletId => $appletName, - submitActionAlias => 'checkAnswer', - ); - - ################################### - # Configure applet - ################################### - - #xml data to set up the problem-rac - $applet->config(qq{<XML> - <point xval='$xval_1' yval='$yval_1' /> - <point xval='$xval_2' yval='$yval_2' /> - </XML>}); - - - ################################### - # insert applet header material - ################################### - HEADER_TEXT($applet->insertHeader ); - - ################################### - # Text section - # - - ################################### - #insert applet into body - ################################### - TEXT( MODES(TeX=>'object code', HTML=>$applet->insertObject)); + $appletName = "PointGraph"; +$applet = FlashApplet( + codebase => findAppletCodebase("$appletName.swf"), + appletName => $appletName, + appletId => $appletName, + setStateAlias => 'setXML', + getStateAlias => 'getXML', + setConfigAlias => 'config', + answerBoxAlias => 'answerBox', + submitActionScript => qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() }, +); + +################################### +# Configure applet +################################### + +#data to set up the equation +$applet->configuration(qq{<XML expr='(x - $a)^3 + $b/$a * x' />}); +# initial points +$applet->intialState(qq{<XML> </XML>}); +################################### +#insert applet into body +################################### + +TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll( + includeAnswerBox => 1 + debug=>0, + reinitialize_button=>1, + ))); =head1 DESCRIPTION @@ -101,115 +97,395 @@ =head2 Default javaScript functions placed in header +=pod + These functions are automatically defined for use for any javaScript placed in the text of a PG question. - getApplet(appletName) -- finds the applet path in the DOM - - submitAction() -- calls the submit action of the applets - + getApplet(appletName) -- finds the applet path in the DOM + + submitAction() -- calls the submit action of the applets - initializeAction() -- calls the initialize action of the applets + initializeWWquestion() -- calls the initialize action of the applets getQE(name) -- gets an HTML element of the question by name or by id. Be sure to keep all names and ids unique within a given PG question. - + getQuestionElement(name) -- long form of getQE(name) - + listQuestionElements() -- for discovering the names of inputs in the PG question. An alert dialog will list all of the elements. - Usage: Place this at the END of the question, - just before END_DOCUMENT(): - - TEXT(qq!<script> listQuestionElements() </script>!); - ENDDOCUMENT(); + + Usage: Place this at the END of the question, just before END_DOCUMENT(): - list of accessor methods format: current_value = $self->method(new_value or empty) + TEXT(qq!<script> listQuestionElements() </script>!); + ENDDOCUMENT(); + to obtain a list of all of the HTML elements in the question + + ---------------------------------------------------------------------------- + + + List of accessor methods made available by the (perl) FlashApplet class. + They are also the names of the instance variables in + Usage: $current_value = $applet->method(new_value or empty) + These can also be set when creating the class -- for exampe: + $applet = new FlashApplet( + # can be replaced by $applet =FlashApplet() when using AppletObjects.pl + codebase => findAppletCodebase("$appletName.swf"), + appletName => $appletName, + appletId => $appletName, + submitActionAlias => 'checkAnswer', + ); + + + appletId for simplicity and reliability appletId and appletName are always the same + appletName + archive the name of the .jar file containing the applet code + code the name of the applet code in the .jar archive + codebase a prefix url used to find the archive and the applet itself + + params an anonymous array containing name/value pairs + to configure the applet [name =>'value, ...] + + width rectangle alloted in the html page for displaying the applet + height - appletId for simplicity and reliability appletId and appletName are always the same - appletName - - archive the name of the .jar file containing the applet code - code the name of the applet code in the .jar archive - codebase a prefix url used to find the archive and the applet itself + bgcolor background color of the applet rectangle - height rectangle alloted in the html page for displaying the applet - width - - params an anonymous array containing name/value pairs - to configure the applet [name =>'value, ...] - - header stores the text to be added to the header section of the html page + header stores the text to be added to the header section of the html page object stores the text which places the applet on the html page - - debug in debug mode several alerts mark progress through the procedure of calling the applet - - config configuration are those customizable attributes of the applet which don't - change as it is used. When stored in hidden answer fields - it is usually stored in base64 encoded format. - base64_config base64 encode version of the contents of config - - configAlias (default: config ) names the applet command called with the contents of $self->config - to configure the applet. The parameters are passed to the applet in plain text using <xml> - The outer tags must be <xml> ..... </xml> - state state consists of those customizable attributes of the applet which change - as the applet is used. It is stored by the calling .pg question so that - when revisiting the question the applet - will be restored to the same state it was left in when the question was last - viewed. - - getStateAlias (default: getState) alias for command called to read the current state of the applet. - The state is passed in plain text xml format with outer tags: <xml>....</xml> - setStateAlias (default: setState) alias for the command called to reset the state of the applet. - The state is passed in plain text in xml format with outer tags: <xml>....</xml> - base64_state returns the base64 encoded version of the state stored in the applet object. - - initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState - submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the + + configuration configuration contains those customizable attributes of the applet which don't + change as it is used. When stored in hidden answer fields + it is usually stored in base64 encoded format. + initialState the state consists of those customizable attributes of the applet which change + as the applet is used by the student. It is stored by the calling .pg question so that + when revisiting the question the applet will be restored to the same state it was + left in when the question was last viewed. + + getStateAlias (default: getState) alias for command called to read the current state of the applet. + The state is passed in plain text xml format with outer tags: <xml>....</xml> + setStateAlias (default: setState) alias for the command called to reset the state of the applet. + The state is passed in plain text in xml format with outer tags: <xml>....</xml> + + configAlias (deprecated) -- a synonym for configAlias + + getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used + mainly for debugging. In principal the configuration remains the same for a given instance + of the applet -- i.e. for the homework question for a single student. The state however + will change depending on the interactions between the student and the applet. + setConfigAlias (default: setConfig ) names the applet command called with the contents of $self->config + to configure the applet. The parameters are passed to the applet in plain text using <xml> + The outer tags must be <xml> ..... </xml> + + + initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called + to initialize the applet (some overlap with config/ and setState + maxInitializationAttempts -- (default: 5) number attempts to test applet to see if it is installed. + If isActive() exists then the WW question waits until the return value is 1 before + calling the applet's confguration commands. + Because some applets have isActive return 0 even when they are ready, + if isActive() exists but does not return 1 then the applet's configuration commands + are called after maxInitializationAttempts number of times. If none of the configuration commands + of the applet can be detected then the WW question gives up after maxInitializationAttempts. + + submitActionAlias -- (default: getXML) applet subroutine called when the submit button of the .pg question is pressed. + submitActionScript -- (default: qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() }, + + answerBoxAlias -- name of answer box to return answer to: default defaultAnswerBox + returnFieldName -- (deprecated) synonmym for answerBoxAlias + + + debugMode (default: 0) in debug mode several alerts mark progress through the procedure of calling the applet + + + Methods: + + insertHeader -- inserts text in header section of HTML page + insertObject -- inserts <object></object> or <applet></applet> tag in body of the HTML page + insertAll -- (defined in AppletObjects.pl) installs applet by inserting both header text and the object text + Usage: $applet->insertAll( + includeAnswerBox => 0, + debugMode => 0, + reinitialize_button =>0, + ); - returnFieldName - - - +=cut + +=head4 More details + +There are three different "images" of the applet. The first is the java or flash applet itself. The object that actually does the work. +The second is a perl image of the applet -- henceforth the perlApplet -- which is configured in the .pg file and allows a WeBWorK question +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 +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 +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 +the PG rendering process. + +The perlApplet is initialized by $newApplet = new flashApplet( appletName=>'myApplet',..... ); The jsApplet is automatically defined in +ww_applet_list["myApplet"] by copying the instance variables of $newApplet to a corresponding javaScript object. So $newApplet->{appletName} +corresponds to ww_applet_list["myApplet"].appletName. (This paragraph is not yet fully implemented :-(). + +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 +to a base64 constant and then converted back to text form when it is read by a javaScript subroutine. + +The perlApplet has methods that help place the jsApplet code on the HTML page and create the link to the applet itself. +In particular instance variables such as "setStateAlias", "getStateAlias" connect the WW default of "setState" to subroutine +name chosen by the applet designer. The aim is to make it easier to connect to applets previously designed to work +with javaScript in an HTML page or other systems. + + +The jsApplet acts as an intermediary for commands directed at the applet. +It is not necessary for the minimal operations of +configuring the applet and maintaining +state from one viewing of the WW question to address the applet directly. +The methods such as "setState", "getState", "setConfig" which are part of the jsApplet +take care of the book keeping details. +It is also possible to make direct calls to the applet from handcrafted javaScript subroutines, +but it may be convenient to store these as additional methods in the +jsApplet. + +=cut + +=head4 Detecting that the applet is ready + +Timing issues are among the pitfalls awaiting when using flash or java applets in WW questions. It is important that the WW question +does not issue any commands to the applet until the applet is fully loaded, including the uploading of any additional configuration +information from XML files. This can be tricky since the timing issues usually don't arise when initiating the applet from an HTML page. + +The WW API performs the following actions to determine if the applet is loaded: + + check the ww_applet_list[appletName].isReady flag (1== applet is ready) + -- this caches the readiness information so that it doesn't + have to be repeated within a given viewing of a WW question + If this is 1 then the applet is ready. + determine whether the applet's isActive subroutine is defined AND returns 1 when called. + -- if the return value is 1 the applet is ready, if it is zero or no response then the applet is NOT ready + -- If the applet has an isActive() subroutine -- there is no alias for this -- + then it must return 1 as soon as the applet is ready. Otherwise + the applet will timeout. + determine whether the applet's setConfig subroutine is defined. + -- applet.{setConfigAlias}. + determine whether the applet's setState subroutine is defined. + determine whether the jsApplets ww_applet_list[appletName].reportsLoaded flag is set to 1 + -- this can be set by the applet if it calls the javaScript function + "applet_loaded(appletName, loaded_status). The loaded_status is 1 or 0 + + Logic for determining applet status: if any one of the above checks succeeds (or returns 1) then the applet is + consdered to be ready UNLESS the isActive() exists and the call returns a 0 or no response. In this case + the applet is assumed to be loading additional data and is not yet ready. + + For this reason if the isActive subroutine + is defined in the applet it must return a 1 once the applet is prepared to accept additional commands. + (Since there are some extent flashApplets with non-functioning isActive() subroutines a temporary workaround + assuems that after C<maxInitializationAttempts> -- 5 by default -- the applet is in fact ready but the + isActive() subroutine is non functioning. This can give rise to false "readiness" signals if the applet + takes a long time to load auxiliary files.) + +The applet itself can take measures to insure that the setConfig subroutine is prepared to respond immediately once the applet is loaded. +It can include timers that delay execution of the configuring actions until all of the auxiliary files needed by the applet are loaded. + + +=cut + + + + +=head4 Instance variables in the javaScript applet ww_applet_list[appletName] + + Most of the instance variables in the perl version of the applet are transferred to the javaScript applet + +=cut + + +=head4 Methods defined for the javaScript applet ww_applet_list[appletName] + +This is not a comprehensive list + + setConfig -- transmits the information for configuring the applet + + getConfig -- retrieves the configuration information -- this is used mainly for debugging and may not be defined in most applets + + + setState -- sets the current state (1) from the appletName_state HTML element if this contains an <xml>...</xml> string + -- if the value contains <xml>restart_applet</xml> then set the current state to ww_applet_list[appletName].initialState + -- if the value is a blank string set the current state to ww_applet_list[appletName].initialState + + + getState -- retrieves the current state and stores in the appletName_state HTML element. + + +=cut + +=head4 Requirements for applets + +The following methods are desirable in an applet that preserves state in a WW question. None of them are required. + + setState(str) (default: setXML) + -- set the current state of the applet from an xml string + -- should be able to accept an empty string or a string of + the form <XML>.....</XML> without creating errors + -- can be designed to receive other forms of input if it is + coordinated with the WW question. + getState() (default: getXML) + -- return the current state of the applet in an xml string. + -- an empty string or a string of the form <XML>.....</XML> + are the standard responses. + -- can be designed to return other strings if it is + coordinated with the WW question. + setConfig(str) (default: setConfig) + -- If the applet allows configuration this configures the applet + from an xml string + -- should be able to accept an empty string or a string of the + form <XML>.....</XML> without creating errors + -- can be designed to receive other forms of input if it is + coordinated with the WW question. + getConfig (default: getConfig) + -- This returns a string defining the configuration of the + applet in an xml string + -- an empty string or a string of the form <XML>.....</XML> + are the standard responses. + -- can be designed to return other strings if it is + coordinated with the WW question. + -- this method is used for debugging to ensure that + the configuration was set as expected. + getAnswer (default: getAnswer) + -- Returns a string (usually NOT xml) which is the + response that the student is effectvely submitting to answer + the WW question. + =cut +=head4 Initialization sequence +When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them +to initialize themselves. + +The applets initialization method is as follows: + + -- wait until the applet is loaded and the applet has loaded all of its auxiliary files. + -- set the debugMode in the applet + -- call the setConfig method in the javaScript applet -- (configuration parameters are "permanent" for the life of the applet + -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet + +=cut + + +=head Submit sequence + +When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks +each of the applets on the page to perform its submit action which consists of + + -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then + the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml> + to be interpreted by the next setState command + -- Otherwise getState() from the applet and save it to the HTML input element appletName_state + -- Perform the javaScript commands in .submitActionScript (default: '' ) + a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer() ) + +=cut sub new { my $class = shift; my $self = { - appletName =>'', - code=>'', - codebase=>'', -# appletId =>'', #always use identical applet Id's and applet Names + appletName => '', +# appletId => '', #always use identical applet Id's and applet Names + archive => '' + code => '', + codebase => '', params =>undef, width => 550, height => 400, - base64_state => undef, # this is an state to use for initializing the first occurence of the question. - base64_config => undef, # this is the initial (and final?) configuration + bgcolor => "#869ca7", + configuration => '', # configuration defining the applet + initialState => '', # initial state. getStateAlias => 'getXML', setStateAlias => 'setXML', - configAlias => 'config', + configAlias => '', # deprecated + getConfigAlias => 'getConfig', + setConfigAlias => 'setConfig', initializeActionAlias => 'setXML', + maxInitializationAttempts => 5, # number of attempts to initialize applet submitActionAlias => 'getXML', - returnFieldName => 'receivedField', + submitActionScript => '', # script executed on submitting the WW question + answerBoxAlias => 'answerBox', + answerBox => '', # deprecated + returnFieldName => '', # deprecated headerText => DEFAULT_HEADER_TEXT(), objectText => '', - debug => 0, + debugMode => 0, @_, }; bless $self, $class; - $self->state('<xml></xml>'); - $self->config('<xml></xml>'); + $self->initialState('<xml></xml>'); + if ($self->{returnFieldName} or $self->{answerBox} ) { # backward compatibility + warn "use answerBoxAlias instead of returnFieldName or answerBox"; + $self->{answerBox}=''; + $self->{returnFieldName}=''; + } + if ($self->{configAlias}) { # backward compatibility + warn "use setConfigAlias instead of configAlias"; + $self->{configAlias}=''; + } + $self->configuration('<xml></xml>'); return $self; } +sub appletId { + appletName(@_); +} +sub appletName { + my $self = shift; + $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty + $self->{appletName}; +} +sub archive { + my $self = shift; + $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty + $self->{archive}; +} +sub code { + my $self = shift; + $self->{code} = shift ||$self->{code}; # replace the current code if non-empty + $self->{code}; +} +sub codebase { + my $self = shift; + $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty + $self->{codebase}; +} +sub params { + my $self = shift; + if (ref($_[0]) =~/HASH/) { + $self->{params} = shift; + } elsif ( !defined($_[0]) or $_[0] =~ '') { + # do nothing (read) + } else { + warn "You must enter a reference to a hash for the parameter list"; + } + $self->{params}; +} + +sub width { + my $self = shift; + $self->{width} = shift ||$self->{width}; # replace the current width if non-empty + $self->{width}; +} +sub height { + my $self = shift; + $self->{height} = shift ||$self->{height}; # replace the current height if non-empty + $self->{height}; +} +sub bgcolor { + my $self = shift; + $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty + $self->{bgcolor}; +} sub header { my $self = shift; @@ -229,29 +505,21 @@ } $self->{objectText}; } -sub params { +sub configuration { my $self = shift; - if (ref($_[0]) =~/HASH/) { - $self->{params} = shift; - } elsif ( !defined($_[0]) or $_[0] =~ '') { - # do nothing (read) - } else { - warn "You must enter a reference to a hash for the parameter list"; - } - $self->{params}; -} - -sub initializeActionAlias { - my $self = shift; - $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty - $self->{initializeActionAlias}; + my $str = shift; + $self->{configuration} = $str || $self->{configuration}; # replace the current string if non-empty + $self->{configuration} =~ s/\n//g; + $self->{configuration}; } -sub submitActionAlias { +sub initialState { my $self = shift; - $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty - $self->{submitActionAlias}; + my $str = shift; + $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty + $self->{initialState}; } + sub getStateAlias { my $self = shift; $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty @@ -263,101 +531,132 @@ $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty $self->{setStateAlias}; } -sub configAlias { - my $self = shift; - $self->{configAlias} = shift ||$self->{configAlias}; # replace the current contents if non-empty - $self->{configAlias}; -} -sub returnFieldName { + +sub getConfigAlias { my $self = shift; - $self->{returnFieldName} = shift ||$self->{returnFieldName}; # replace the current contents if non-empty - $self->{returnFieldName}; + $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty + $self->{getConfigAlias}; } -sub codebase { +sub setConfigAlias { my $self = shift; - $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty - $self->{codebase}; + $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty + $self->{setConfigAlias}; } -sub code { + +sub initializeActionAlias { my $self = shift; - $self->{code} = shift ||$self->{code}; # replace the current code if non-empty - $self->{code}; + $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty + $self->{initializeActionAlias}; } -sub height { +sub maxInitializationAttempts { my $self = shift; - $self->{height} = shift ||$self->{height}; # replace the current height if non-empty - $self->{height}; -} -sub width { + $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts}; + $self->{maxInitializationAttempts}; +} +sub submitActionAlias { my $self = shift; - $self->{width} = shift ||$self->{width}; # replace the current width if non-empty - $self->{width}; + $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty + $self->{submitActionAlias}; } -sub archive { +sub submitActionScript { my $self = shift; - $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty - $self->{archive}; + $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty + $self->{submitActionScript}; } -sub appletName { + +sub answerBoxAlias { my $self = shift; - $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty - $self->{appletName}; + $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty + $self->{answerBox}; } -sub debug { + +sub debugMode { my $self = shift; my $new_flag = shift; - $self->{debug} = $new_flag if defined($new_flag); - $self->{debug}; + $self->{debugMode} = $new_flag if defined($new_flag); + $self->{debugMode}; } -sub appletId { - appletName(@_); + + +####################### +# soon to be deprecated? +####################### + +sub config { + my $self = shift; + my $str = shift; + warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded", join(' ', caller()); +# $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty +# $self->{base64_config} =~ s/\n//g; +# decode_base64($self->{base64_config}); } sub state { my $self = shift; my $str = shift; - $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty - $self->{base64_state} =~ s/\n//g; - decode_base64($self->{base64_state}); + warn "use $self->initialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller()); +# $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty +# $self->{base64_state} =~ s/\n//g; +# decode_base64($self->{base64_state}); } - sub base64_state{ my $self = shift; - $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty - $self->{base64_state}; + warn "use $self->InitialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller()); + + } -sub config { + +sub base64_config { my $self = shift; - my $str = shift; - $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty - $self->{base64_config} =~ s/\n//g; - decode_base64($self->{base64_config}); + warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded"; } -sub base64_config { + +sub returnFieldName { + my $self = shift; + warn "use answerBoxName instead of returnFieldName"; +} +sub answerBox { + my $self = shift; + warn "use answerBoxAlias instead of AnswerBox"; +} +sub configAlias { my $self = shift; - $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty - $self->{base64_config} =$self->{base64_config}; - $self->{base64_config}; + warn "use setConfigAlias instead of configAlias"; } +######################### #FIXME # need to be able to adjust header material sub insertHeader { my $self = shift; - my $codebase = $self->codebase; - my $appletId = $self->appletId; - my $appletName = $self->appletName; - my $base64_initialState = $self->base64_state; - my $initializeAction = $self->initializeActionAlias; - my $submitAction = $self->submitActionAlias; - my $setState = $self->setStateAlias; - my $getState = $self->getStateAlias; - my $config = $self->configAlias; - my $base64_config = $self->base64_config; - my $debugMode = ($self->debug) ? "1": "0"; - my $returnFieldName = $self->{returnFieldName}; -# my $encodeStateQ = ($self->debug)?'' : "state = Base64.encode(state);"; # in debug mode base64 encoding is not used. -# my $decodeStateQ = "if (!state.match(/<XML>*/i) ) {state = Base64.decode(state)}"; # decode if <XML> is not present - my $headerText = $self->header(); + + my $codebase = $self->codebase; + my $appletId = $self->appletId; + my $appletName = $self->appletName; + my $initializeActionAlias = $self->initializeActionAlias; + my $submitActionScript = $self->submitActionScript; + my $setStateAlias = $self->setStateAlias; + my $getStateAlias = $self->getStateAlias; + + my $setConfigAlias = $self->setConfigAlias; + my $getConfigAlias = $self->getConfigAlias; + my $maxInitializationAttempts = $self->maxInitializationAttempts; + my $debugMode = ($self->debugMode) ? "1": "0"; + my $answerBoxAlias = $self->{answerBoxAlias}; + my $headerText = $self->header(); + + + #$submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript + # other variables should not have quotes. + + $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript + $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble + my $base64_submitActionScript = encode_base64($submitActionScript); + my $base64_configuration = encode_base64($self->configuration); + my $base64_initialState = encode_base64($self->initialState); + + $base64_submitActionScript =~s/\n//g; + $base64_initialState =~s/\n//g; # base64 encoded xml + $base64_configuration =~s/\n//g; # base64 encoded xml $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook @@ -366,6 +665,54 @@ } + +######################################################## +# HEADER material for one flash or java applet +######################################################## + +use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; + <script src="/webwork2_files/js/Base64.js" language="javascript"> + </script> + <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> + //upload functions stored in /opt/webwork/webwork2/htdocs/js ... + + </script> + <script language="JavaScript"> + + + + ////////////////////////////////////////////////////////// + //TEST code + // + // + ////////////////////////////////////////////////////////// + + ww_applet_list["$appletName"] = new ww_applet("$appletName"); + + + ww_applet_list["$appletName"].code = "$code"; + ww_applet_list["$appletName"].codebase = "$codebase"; + ww_applet_list["$appletName"].appletID = "$appletID"; + ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; + ww_applet_list["$appletName"].initialState = Base64.decode("$base64_initialState"); + ww_applet_list["$appletName"].configuration = Base64.decode("$base64_configuration");; + ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; + ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; + ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; + ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; + ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias"; + ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; + ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript"); + ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias"; + ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts; + ww_applet_list["$appletName"].debugMode = "$debugMode"; + + </script> + +END_HEADER_SCRIPT + + + sub insertObject { my $self = shift; my $code = $self->{code}; @@ -375,6 +722,7 @@ my $archive = $self->{archive}; my $width = $self->{width}; my $height = $self->{height}; + my $applet_bgcolor = $self->{bgcolor}; my $javaParameters = ''; my $flashParameters = ''; my %param_hash = %{$self->params()}; @@ -389,153 +737,12 @@ $objectText =~ s/(\$\w+)/$1/gee; return $objectText; } -sub initialize { - my $self = shift; - return q{ - <script> - initializeAction(); - // this should really be done in the <body> tag - </script> - }; - -} -######################################################## -# HEADER material for one flash or java applet -######################################################## - -use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; - - <script language="JavaScript"> - - // set debug mode for this applet - set_debug($debugMode); - - ////////////////////////////////////////////////////////// - //CONFIGURATIONS - // - // configurations are "permanent" - ////////////////////////////////////////////////////////// - - applet_config_list["$appletName"] = function() { - debug_add("applet_config_list:\n attempt to configure $appletName . $config ( $base64_config ) if config function is defined: " - ); - try { - if (( typeof(getApplet("$appletName").$config) == "function" ) ) { - debug_add("CONFIGURE $appletName"); - getApplet("$appletName").$config(Base64.decode("$base64_config")); - } - } catch(e) { - alert("Error executing configuration command $config for $appletName: " + e ); - } - } - //////////////////////////////////////////////////////////// - // - //STATE: - // state can vary as the applet is manipulated -- it is reset from the questions _state values - // - ////////////////////////////////////////////////////////// - - applet_setState_list["$appletName"] = function(state) { - debug_add("Begin setState for applet $appletName"); - debug_add("Obtain state from $appletName"+"_state"); - state = state || getQE("$appletName"+"_state").value; - if ( base64Q(state) ) { - state=Base64.decode(state); - } - if (state.match(/<xml/i) || state.match(/<?xml/i) ) { // if state starts with <?xml - - debug_add("applet_setState_list: \n set (decoded) state for $appletName to " + - state +"\nfunction type is " +typeof(getApplet("$appletName").$setState) - ); - try { - if (( typeof(getApplet("$appletName").$setState) =="function" ) ) { - debug_add("setState for $appletName"); - getApplet("$appletName").$setState( state ); - } - } catch(e) { - alert("Error in setting state of $appletName using command $setState : " + e ); - } - } else if (debug) { - alert("new state was empty string or did not begin with <xml-- state was not reset"); - } - }; - applet_getState_list["$appletName"] = function () { - debug_add("get current state for applet $appletName and store it in $appletName"+"_state"); - var applet = getApplet("$appletName"); - try { - if (( typeof(applet.$getState) == "function" ) ) { // there may be no state function - state = applet.$getState(); // get state in xml format - debug_add("state has type " + typeof(state)); - state = String(state); // geogebra returned an object type instead of a string type - debug_add("state converted to type " + typeof(state)); - } - - if (!debug) { - state = Base64.encode(state); - }; // replace state by encoded version unless in debug mode - - debug_add("state is "+state); // this should still be in plain text - getQE("$appletName"+"_state").value = state; //place state in input item (debug: textarea, otherwise: hidden) - } catch (e) { - alert("Error in getting state for $appletName " + e ); - } - }; - - //////////////////////////////////////////////////////////// - // - //INITIALIZE - // - //////////////////////////////////////////////////////////// - - - applet_checkLoaded_list["$appletName"] = function() { // this function returns 0 unless: - // applet has already been flagged as ready in applet_isReady_list - // applet.config is defined (or alias for .config) - // applet.setState is defined - // applet.isActive is defined - // applet reported that it is loaded by calling loadQ() - var ready = 0; - var applet = getApplet("$appletName"); - if (!debug && applet_isReady_list["$appletName"]) {return(1)}; // memorize readiness in non-debug mode - if ( typeof(applet.$config) == "function") { - debug_add( "applet.config is " + typeof(applet.$config) ); - ready = 1; - } - if( typeof(applet.$getState) == "function") { - debug_add( "applet.getState is " + typeof(applet.$getState) ); - ready =1; - } - if (typeof(applet.isActive) == "function" && applet.isActive ) { - debug_add( "applet.isActive is " + typeof(applet.isActive) ); - ready =1; - } - if (typeof(applet_reportsLoaded_list["$appletName"]) !="undefined" && applet_reportsLoaded_list["$appletName"] != 0 ) { - debug_add( "applet reports that it is loaded " + applet_reportsLoaded_list["$appletName"] ); - ready =1; - } - applet_isReady_list["$appletName"]= ready; - return(ready); - } - - applet_initializeAction_list["$appletName"] = function (state) { - applet_setState_list["$appletName"](state); - }; - - applet_submitAction_list["$appletName"] = function () { - if (! applet_isReady_list["$appletName"] ) { - alert("$appletName is not ready"); - } - applet_getState_list["$appletName"](); - //getQE("$returnFieldName").value = getApplet("$appletName").sendData(); //FIXME -- not needed in general? - }; - </script> - -END_HEADER_SCRIPT package FlashApplet; @ISA = qw(Applet); +=head2 Insertion HTML code for FlashApplet =pod @@ -558,9 +765,9 @@ codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> <param name="movie" value="$codebase/$appletName.swf" /> <param name="quality" value="high" /> - <param name="bgcolor" value="#869ca7" /> + <param name="bgcolor" value="$applet_bgcolor" /> <param name="allowScriptAccess" value="sameDomain" /> - <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" + <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" width="$width" height="$height" name="$appletName" align="middle" id="$appletName" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" @@ -580,10 +787,10 @@ codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> <param name="movie" value="$codebase/$appletName.swf" /> <param name="quality" value="high" /> - <param name="bgcolor" value="#869ca7" /> + <param name="bgcolor" value="$applet_bgcolor" /> <param name="allowScriptAccess" value="sameDomain" /> <param name="FlashVars" value="$flashParameters"/> - <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" + <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" width="$width" height="$height" name="$appletName" align="middle" id="$appletName" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" @@ -606,7 +813,7 @@ package JavaApplet; @ISA = qw(Applet); - +=head2 Insertion HTML code for JavaApplet =pod @@ -650,6 +857,7 @@ id = "$appletName" width = "$width" height = "$height" + bgcolor = "$applet_bgcolor" MAYSCRIPT > $javaParameters |
From: Mike G. v. a. <we...@ma...> - 2009-04-01 04:03:47
|
Log Message: ----------- backport the new applet api from HEAD Tags: ---- rel-2-4-patches Modified Files: -------------- pg/macros: AppletObjects.pl Revision Data ------------- Index: AppletObjects.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/AppletObjects.pl,v retrieving revision 1.11.2.1 retrieving revision 1.11.2.1.2.1 diff -Lmacros/AppletObjects.pl -Lmacros/AppletObjects.pl -u -r1.11.2.1 -r1.11.2.1.2.1 --- macros/AppletObjects.pl +++ macros/AppletObjects.pl @@ -22,7 +22,7 @@ =head1 DESCRIPTION This subroutines in this -file provide mechanisms to insert Flash applets (and later Java applets) +file provide mechanisms to insert Flash applets (and Java applets) into a WeBWorK problem. @@ -39,184 +39,18 @@ # don't reload this file ######################################################################### -sub _AppletObjects_init { - +sub _AppletObjects_init{ main::HEADER_TEXT(<<'END_HEADER_TEXT'); <script language="javascript">AC_FL_RunContent = 0;</script> <script src="/webwork2_files/applets/AC_RunActiveContent.js" language="javascript"> </script> <script src="/webwork2_files/js/Base64.js" language="javascript"> - </script> - -<script language="JavaScript"> - -////////////////////////////////////////////////////////// -// applet lists -////////////////////////////////////////////////////////// - - var applet_initializeAction_list = new Object; // functions for initializing question with an applet - var applet_submitAction_list = new Object; // functions for submitting question with applet - var applet_setState_list = new Object; // functions for setting state (XML) from applets - var applet_getState_list = new Object; // functions for getting state (XML) from applets - var applet_config_list = new Object; // functions for configuring on applets - var applet_checkLoaded_list = new Object; // functions for probing the applet to see if it is loaded - var applet_reportsLoaded_list = new Object; // flag set by applet - var applet_isReady_list = new Object; // flag set by javaScript in checkLoaded - -////////////////////////////////////////////////////////// -// DEBUGGING tools -////////////////////////////////////////////////////////// - var debug; - var debugText = ""; - function set_debug(num) { // setting debug for any applet sets it for all of them - if (num) { - debug =1; - } - } - function debug_add(str) { - if (debug) { - debugText = debugText + "\n\n" +str; - } - } - -////////////////////////////////////////////////////////// -// INITIALIZE and SUBMIT actions -////////////////////////////////////////////////////////// - - function submitAction() { - - if (debug) { - debugText = " Begin looping through applet_submitAction_list\n"; - } - for (var applet in applet_submitAction_list) { - - applet_submitAction_list[applet](); - } - if (debug) { - alert(debugText); debugText=""; - }; - } - function initializeAction() { - var iMax = 10; - debugText="start intializeAction() with up to " +iMax + " attempts\n"; - for (var appletName in applet_initializeAction_list) { - safe_applet_initialize(appletName, iMax); - } - - } - - // applet can set isReady flag by calling applet_loaded(appletName, loaded); - function applet_loaded(appletName,loaded) { - applet_reportsLoaded_list[appletName] = loaded; // 0 means not loaded - debug_add("applet reporting that it has been loaded = " + loaded ); - } - - // insures that applet is loaded before initializing it - function safe_applet_initialize(appletName, i) { - debug_add("Iteration " + i + " of safe_applet_initialize with applet " + appletName ); + </script> + <script src="/webwork2_files/js/ww_applet_support.js"> + //upload functions stored in /opt/webwork/webwork2/htdocs/js ... - i--; - var applet_loaded = applet_checkLoaded_list[appletName](); - debug_add("applet is ready = " + applet_loaded ); - - if ( 0 < i && !applet_loaded ) { // wait until applet is loaded - debug_add("applet " + appletName + "not ready try again"); - window.setTimeout( "safe_applet_initialize(\"" + appletName + "\"," + i + ")",1); - } else if( 0 < i ){ // now that applet is loaded configure it and initialize it with saved data. - debug_add(" Ready to initialize applet " + appletName + " with " + i + " iterations left. "); - - // in-line handler -- configure and initialize - try{ - if (debug && typeof(getApplet(appletName).debug) == "function" ) { - getApplet(appletName).debug(1); // turn the applet's debug functions on. - } - } catch(e) { - alert("Unable to set debug mode for applet " + appletName); - } - try{ - applet_config_list[appletName](); - } catch(e) { - alert("Unable to configure " + appletName + " \n " +e ); - } - try{ - applet_initializeAction_list[appletName](); - } catch(e) { - alert("unable to initialize " + appletName + " \n " +e ); - } - - } else { - if (debug) {alert("Error: timed out waiting for applet " +appletName + " to load");} - } - if (debug) {alert(debugText); debugText="";}; - } - -/////////////////////////////////////////////////////// -// Utility functions -/////////////////////////////////////////////////////// - - - function getApplet(appletName) { - var isIE = navigator.appName.indexOf("Microsoft") != -1; - var obj = (isIE) ? window[appletName] : window.document[appletName]; - //return window.document[appletName]; - if (obj && (obj.name = appletName)) { - return( obj ); - } else { - // alert ("can't find applet " + appletName); - } - } - - function listQuestionElements() { // list all HTML input and textarea elements in main problem form - var isIE = navigator.appName.indexOf("Microsoft") != -1; - var elementList = (isIE) ? document.getElementsByTagName("input") : document.problemMainForm.getElementsByTagName("input"); - var str=elementList.length +" Question Elements\n type | name = value < id > \n"; - for( var i=0; i< elementList.length; i++) { - str = str + " "+i+" " + elementList[i].type - + " | " + elementList[i].name - + "= " + elementList[i].value + - " <" + elementList[i].id + ">\n"; - } - elementList = (isIE) ? document.getElementsByTagName("textarea") : document.problemMainForm.getElementsByTagName("textarea"); - for( var i=0; i< elementList.length; i++) { - str = str + " "+i+" " + elementList[i].type - + " | " + elementList[i].name - + "= " + elementList[i].value + - " <" + elementList[i].id + ">\n"; - } - alert(str +"\n Place listQuestionElements() at end of document in order to get all form elements!"); - } - - function base64Q(str) { - return ( !str.match(/<XML/i) && !str.match(/<?xml/i)); - } - function setEmptyState(appletName){ - var newState = "<xml></xml>"; - applet_setState_list[appletName](newState); - var applet = getApplet(appletName); - getQE(appletName+"_state").value = newState; - getQE("previous_" + appletName + "_state").value = newState - } - - function getQE(name1) { // get Question Element in problemMainForm by name - var isIE = navigator.appName.indexOf("Microsoft") != -1; - var obj = (isIE) ? document.getElementById(name1) - :document.problemMainForm[name1]; - // needed for IE -- searches id and name space so it can be unreliable if names are not unique - if (!obj || obj.name != name1) { - alert("Can't find element " + name1); - listQuestionElements(); - } else { - return( obj ); - } - - } - function getQuestionElement(name1) { - return getQE(name1); - } - - </script> - + </script> END_HEADER_TEXT }; @@ -274,60 +108,110 @@ sub insertAll { ## inserts both header text and object text my $self = shift; my %options = @_; - $self->debug( (defined($options{debug}) and $options{debug}==1) ? 1 : 0 ); - my $reset_button = $options{reset_button} || 0; + + # debugMode can be turned on by setting it to 1 in either the applet definition or at insertAll time + my $debugMode = (defined($options{debug}) and $options{debug}==1) ? 1 : 0; + my $includeAnswerBox = (defined($options{includeAnswerBox}) and $options{includeAnswerBox}==1) ? 1 : 0; + $debugMode = $debugMode || $self->debugMode; + $self->debugMode( $debugMode); + + + my $reset_button = $options{reinitialize_button} || 0; + warn qq! please change "reset_button=>1" to "reinitialize_button=>1" in the applet->installAll() command ! if defined($options{reset_button}); # prepare html code for storing state my $appletName = $self->appletName; my $appletStateName = "${appletName}_state"; my $getState = $self->getStateAlias; my $setState = $self->setStateAlias; - my $base64_initialState = $self->base64_state; + my $getConfig = $self->getConfigAlias; + my $setConfig = $self->setConfigAlias; + + my $base64_initialState = encode_base64($self->initialState); main::RECORD_FORM_LABEL($appletStateName); #this insures that they'll be saved from one invocation to the next - #main::RECORD_FORM_LABEL("previous_$appletStateName"); my $answer_value = ''; - $answer_value = ${$main::inputs_ref}{$appletStateName} if defined(${$main::inputs_ref}{$appletStateName}); - - if ( defined( $main::rh_sticky_answers->{$appletStateName} ) ) { + + if ( defined( ${$main::inputs_ref}{$appletStateName} ) and ${$main::inputs_ref}{$appletStateName} =~ /\S/ ) { + $answer_value = ${$main::inputs_ref}{$appletStateName}; + } elsif ( defined( $main::rh_sticky_answers->{$appletStateName} ) ) { + warn "type of sticky answers is ", ref( $main::rh_sticky_answers->{$appletStateName} ); $answer_value = shift( @{ $main::rh_sticky_answers->{$appletStateName} }); - $answer_value = '' unless defined($answer_value); } $answer_value =~ tr/\\$@`//d; #`## make sure student answers can not be interpolated by e.g. EV3 $answer_value =~ s/\s+/ /g; ## remove excessive whitespace from student answer - ####### # insert a hidden variable to hold the applet's state (debug =>1 makes it visible for debugging and provides debugging buttons) ####### - my $base_64_encoded_answer_value = ($answer_value =~/<XML|<?xml/i)? encode_base64($answer_value) : $answer_value; + my $base_64_encoded_answer_value; + my $decoded_answer_value; + if ( $answer_value =~/<XML|<?xml/i) { + $base_64_encoded_answer_value = encode_base64($answer_value); + $decoded_answer_value = $answer_value; + } else { + $decoded_answer_value = decode_base64($answer_value); + if ( $decoded_answer_value =~/<XML|<?xml/i) { # great, we've decoded the answer to obtain an xml string + $base_64_encoded_answer_value = $answer_value; + } else { #WTF?? apparently we don't have XML tags + $answer_value = "<xml>$answer_value</xml>"; + $base_64_encoded_answer_value = encode_base64($answer_value); + $decoded_answer_value = $answer_value; + } + } $base_64_encoded_answer_value =~ s/\r|\n//g; # get rid of line returns - my $decoded_answer_value = ($answer_value =~/<XML|<?xml/i) ? $answer_value : decode_base64($answer_value); + # debug version of the applet state answerBox and controls my $debug_input_element = qq!\n<textarea rows="4" cols="80" name = "$appletStateName">$decoded_answer_value</textarea><br/> <input type="button" value="$getState" - onClick="applet_getState_list['$appletName']()" + onClick="debugText=''; + ww_applet_list['$appletName'].getState(); + alert(debugText);" > <input type="button" value="$setState" - onClick="var tmp = getQE('$appletStateName').value; - applet_setState_list['$appletName'](tmp);" + onClick="debugText=''; + ww_applet_list['$appletName'].setState(); + alert(debugText);" > + <input type="button" value="$getConfig" + onClick="debugText=''; + ww_applet_list['$appletName'].getConfig()"; " + > + <input type="button" value="$setConfig" + onClick="debugText=''; + ww_applet_list['$appletName'].setConfig(); + alert(debugText);" + > !; - my $state_input_element = ($self->debug == 1) ? $debug_input_element : + + my $state_input_element = ($debugMode) ? $debug_input_element : qq!\n<input type="hidden" name = "$appletStateName" value ="$base_64_encoded_answer_value">!; my $reset_button_str = ($reset_button) ? - qq!<br/><input type='button' value='set applet state empty' onClick="setEmptyState('$appletName')"> - <input type="button" value="reinitialize applet" onClick="getQE('$appletStateName').value='$base64_initialState'"/>! - : '' - ; + qq!<input type='button' value='return this question to its initial state' onClick="setAppletStateToRestart('$appletName')"><br/>! + : '' ; + # <input type="button" value="reinitialize applet" onClick="getQE('$appletStateName').value='$base64_initialState'"/><br/> # always base64 encode the hidden answer value to prevent problems with quotes. # - $state_storage_html_code = - $reset_button_str. - $state_input_element. - qq!<input type="hidden" name="previous_$appletStateName" value = "$base_64_encoded_answer_value">!; + $state_storage_html_code = qq!<input type="hidden" name="previous_$appletStateName" value = "$base_64_encoded_answer_value">! + . $state_input_element. $reset_button_str + ; + my $answerBox_code =''; + if ($includeAnswerBox) { + if ($debugMode) { + + $answerBox_code = $main::BR . main::NAMED_ANS_RULE('answerBox', 50 ); + $answerBox_code .= qq! + <br/><input type="button" value="get Answer from applet" onClick="eval(ww_applet_list['$appletName'].submitActionScript )"/> + <br/> + !; + } else { + $answerBox_code = main::NAMED_HIDDEN_ANS_RULE('answerBox', 50 ); + } + } ####### # insert header material ####### main::HEADER_TEXT($self->insertHeader()); - return main::MODES(TeX=>' {\bf applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code); + # update the debug mode for this applet. + main::HEADER_TEXT(qq!<script> ww_applet_list["$appletName"].debugMode = $debugMode;\n</script>!); + return main::MODES(TeX=>' {\bf applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code.$answerBox_code); } =head3 Example problem |
From: Mike G. v. a. <we...@ma...> - 2009-04-01 04:02:52
|
Log Message: ----------- backporting applet javaScript support from HEAD Largely so it will appear in the wiki POD docs. Tags: ---- rel-2-4-patches Added Files: ----------- webwork2/htdocs/js: ww_applet_support.js Revision Data ------------- --- /dev/null +++ htdocs/js/ww_applet_support.js @@ -0,0 +1,543 @@ +// ################################################################################ +// # WeBWorK Online Homework Delivery System +// # Copyright © 2000-2009 The WeBWorK Project, http://openwebwork.sf.net/ +// # $CVSHeader: webwork2/htdocs/js/ww_applet_support.js,v 1.9.2.1 2009/04/01 03:51:41 gage Exp $ +// # +// # This program is free software; you can redistribute it and/or modify it under +// # the terms of either: (a) the GNU General Public License as published by the +// # Free Software Foundation; either version 2, or (at your option) any later +// # version, or (b) the "Artistic License" which comes with this package. +// # +// # This program is distributed in the hope that it will be useful, but WITHOUT +// # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +// # Artistic License for more details. +// ################################################################################ + + + +////////////////////////////////////////////////////////// +// applet lists +////////////////////////////////////////////////////////// + + + var ww_applet_list = new Object; // holds java script version (jsApplet) ww_applet objects + + +////////////////////////////////////////////////////////// +// DEBUGGING tools +////////////////////////////////////////////////////////// + var jsDebugMode=0; // set this to one when needed for major debugging -- puts all applets in debugMode + var debugText = ""; + function debug_add(str) { + debugText = debugText + "\n" +str; + } + +////////////////////////////////////////////////////////// +// INITIALIZE and SUBMIT actions +////////////////////////////////////////////////////////// + +function submitAction() { // called from the submit button defined in Problem.pm + + if (jsDebugMode==1) { + debugText = "Call submitAction() function on each applet\n"; + } + + for (var appletName in ww_applet_list ) { + ww_applet_list[appletName].submitAction(); + } + if (jsDebugMode==1) { debug_add("\n Done calling submitAction() on each applet.\n");} + if (jsDebugMode==1) { + alert(debugText); debugText=""; + }; +} + +function initializeAction() { // deprecated call -- removed + alert("You might be using an old template (stored at webwork2/conf/templates). The <body> tag in the system.template calls a function 'initializeAction()' -- this function name should be replaced by 'initializeWWquestion()'. Please update to a recent version of system.template"); + initializeWWquestion(); +} + +function initializeWWquestion() { // called from <body> tag defined in the webwork2/conf/template + for (var appletName in ww_applet_list) { + var maxInitializationAttempts = ww_applet_list[appletName].maxInitializationAttempts; + // alert("Initialize each applet. \nUse up to " +maxInitializationAttempts + " cycles to load" +"\n"); + ww_applet_list[appletName].safe_applet_initialize(maxInitializationAttempts); + } + +} + +// applet can set isReady flag by calling applet_loaded(appletName, loaded); +function applet_loaded(appletName,loaded) { + debug_add("applet reporting that it has been loaded = " + loaded ); + ww_applet_list[appletName].reportsLoaded = loaded; // 0 means not loaded +} + + +// insures that applet is loaded before initializing it + + + +/////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////// + + +function getApplet(appletName) { + var isIE = navigator.appName.indexOf("Microsoft") != -1; + var obj = (isIE) ? window[appletName] : window.document[appletName]; + //return window.document[appletName]; + if (obj && (obj.name = appletName)) { + return( obj ); + } else { + alert ("can't find applet " + appletName); + } + } + +function listQuestionElements() { // list all HTML input and textarea elements in main problem form + var isIE = navigator.appName.indexOf("Microsoft") != -1; + var elementList = (isIE) ? document.getElementsByTagName("input") : document.problemMainForm.getElementsByTagName("input"); + var str=elementList.length +" Question Elements\n type | name = value < id > \n"; + for( var i=0; i< elementList.length; i++) { + str = str + " "+i+" " + elementList[i].type + + " | " + elementList[i].name + + "= " + elementList[i].value + + " <" + elementList[i].id + ">\n"; + } + elementList = (isIE) ? document.getElementsByTagName("textarea") : document.problemMainForm.getElementsByTagName("textarea"); + for( var i=0; i< elementList.length; i++) { + str = str + " "+i+" " + elementList[i].type + + " | " + elementList[i].name + + "= " + elementList[i].value + + " <" + elementList[i].id + ">\n"; + } + var msg = " ( Place listQuestionElements() at end of document in order to get all form elements! )\n"+str; + alert(msg); +} + +function base64Q(str) { /// determine whether an XML string has been base64 encoded. + return ( !str.match(/<XML/i) && !str.match(/<?xml/i)); +} +function setAppletStateToRestart(appletName){ + var newState = "<xml>restart_applet</xml>"; + //ww_applet_list[appletName].setState(newState); + getQE(appletName+"_state").value = newState; + getQE("previous_" + appletName + "_state").value = newState +} + +function getQE(name1) { // get Question Element in problemMainForm by name + var isIE = navigator.appName.indexOf("Microsoft") != -1; + var obj = (isIE) ? document.getElementById(name1) + :document.problemMainForm[name1]; + // needed for IE -- searches id and name space so it can be unreliable if names are not unique + if (!obj || obj.name != name1) { + var msg = "Can't find element " + name1; + if (jsDebugMode==1) { + debug_add(msg + "\n ( Place listQuestionElements() at end of document in order to get all form elements! )\n" ); + } else { + alert(msg); listQuestionElements(); + }; + + } else { + return( obj ); + } + +} + + +function getQuestionElement(name1) { + return getQE(name1); +} + + +/////////////////////////////////////////////////////// +// WW_Applet class definition +/////////////////////////////////////////////////////// + +function ww_applet(appletName) { + this.appletName = appletName; + this.code = ''; + this.codebase = ''; + this.appletID = ''; +// this.base64_state = ''; +// this.base64_config = ''; + this.configuration = ''; + this.initialState = ''; + this.getStateAlias = ''; + this.setStateAlias = ''; + this.configAlias = ''; + this.initializeActionAlias = ''; + this.submitActionAlias = ''; + this.submitActionScript = ''; + this.getAnswerAlias = ''; + this.answerBox = ''; + this.debugMode = 0 ; + this.isReady = 0 ; + this.reportsLoaded = 0 ; +}; +////////////////////////////////////////////////////////// +// methodDefined +// +// make sure that the applet has this function available +////////////////////////////////////////////////////////// + +ww_applet.prototype.methodDefined = function(methodName) { + var appletName = this.appletName; + var applet = getApplet(appletName); + try { + if (typeof(applet[methodName]) == "function" ) { + this.debug_add("Method " + methodName + " is defined in " + appletName ); + return(true); + } else { + this.debug_add("Method " + methodName + " is not defined in " + appletName); + return(false); + } + } catch(e) { + var msg = "Error in accessing " + methodName + " in applet " +appletName + "Error: " +e ; + alert(msg); + } + return(false); +} + +////////////////////////////////////////////////////////// +//CONFIGURATIONS +// +// configurations are "permanent" +////////////////////////////////////////////////////////// +ww_applet.prototype.setConfig = function () { + + var appletName = this.appletName; + var applet = getApplet(appletName); + var setConfigAlias = this.setConfigAlias; + + try { + if ( this.methodDefined(setConfigAlias) ) { + applet[setConfigAlias](this.configuration); + } + + } catch(e) { + + var msg = "Error in configuring " + appletName + " using command " + setConfigAlias + " : " + e ; + alert(msg); + } + this.debug_add(" Calling " + appletName +"."+ setConfigAlias +"( " + this.configuration + " ) " ); + + }; + + ww_applet.prototype.getConfig = function() { // used for debugging purposes -- gets the configuration from the applet + + + var appletName = this.appletName; + var applet = getApplet(appletName); + var getConfigAlias = this.getConfigAlias; + + + try { + if (this.methodDefined(getConfigAlias) ) { + alert( applet[getConfigAlias]() ); + } else { + alert("in getConfig " + debugText); + } + } catch(e) { + var msg = " Error in getting configuration from applet " + appletName + " " + e; + alert(msg); + } +} + + + +//////////////////////////////////////////////////////////// +// +//STATE: +// state can vary as the applet is manipulated -- it is reset from the questions _state values +// +////////////////////////////////////////////////////////// + + +ww_applet.prototype.setState = function(state) { + + var appletName = this.appletName; + var applet = getApplet(appletName); + var setStateAlias = this.setStateAlias; + + debug_add("\n++++++++++++++++++++++++++++++++++++++++\nBegin process of setting state for applet " + appletName); + + if (state) { + debug_add("Obtain state from calling parameter:\n " + state + "\n"); + } else { + this.debug_add("Obtain state from " + appletName +"_state"); + + var ww_preserve_applet_state = getQE(appletName + "_state"); // hidden answer box preserving applet state + state = ww_preserve_applet_state.value; + } + + if ( base64Q(state) ) { + state=Base64.decode(state); + } + + if (state.match(/^<xml>restart_applet<\/xml>/) ) { + alert("The applet " +appletName + "has been reset to its virgin state." + this.initialState); + ww_preserve_applet_state.value =this.initialState; //Fixme? should we set the last answer to blank as well? + state = ww_preserve_applet_state.value; + } + if (state.match(/<xml/i) || state.match(/<?xml/i) ) { // if state starts with <?xml + + this.debug_add("Set state for " + appletName + " to \n------------------------------\n" + + state + "\n------------------------------\n"); + + try { + + if ( this.methodDefined(setStateAlias) ) { + applet[setStateAlias]( state ); // change the applets current state + } + } catch(e) { + msg = "Error in setting state of " + appletName + " using command " + setStateAlias + " : " + e ; + alert(msg); + } + } else if (jsDebugMode==1) { + this.debug_add(" new state was empty string or did not begin with <xml> -- Applet state was not reset"); + } + return(''); +}; + +ww_applet.prototype.getState = function () { + + var state ="<xml>foobar</xml>"; + var appletName = this.appletName; + var applet = getApplet(appletName); + var getStateAlias = this.getStateAlias; + + this.debug_add(" Begin getState for applet " + appletName ); + + try { + if (this.methodDefined(getStateAlias)) { // there may be no state function + state = applet[getStateAlias](); // get state in xml format + debug_add(" state has type " + typeof(state)); + state = String(state); // geogebra returned an object type instead of a string type + // this insures that we can view the state as a string + this.debug_add(" state converted to type " + typeof(state)); + } else { + this.debug_add(" Applet does not have a getState method named: "+ getStateAlias + "."); + state ="<xml>undefined_state</xml>"; + } + + } catch (e) { + var msg = " Error in getting state from applet " + appletName + " " + e; + alert(msg); + } + + if (this.debugMode==0) { + state = Base64.encode(state); + }; // replace state by encoded version unless in debug mode + + this.debug_add(" state is \n "+ state + "\n"); // state should still be in plain text + var ww_preserve_applet_state = getQE(appletName + "_state"); // answer box preserving applet state (jsDebugMode: textarea, otherwise: hidden) + ww_preserve_applet_state.value = state; //place state in input item (jsDebugMode: textarea, otherwise: hidden) + this.debug_add("State stored in answer box "+ appletName + "_state and getState is finished."); + +}; + +ww_applet.prototype.setDebug = function(debugMode) { + // sets debug mode in the flash or java applet + // applet's method must be called debug + + var appletName = this.appletName; + var applet = getApplet(appletName); + debugMode = jsDebugMode || debugMode ; + + try{ + if (this.methodDefined("debug") ) { + applet.debug(debugMode); // set the applet's debug functions on. + } else { + this.debug_add( " Unable to set debug state in applet " + appletName + "."); + + } + } catch(e) { + var msg = "Unable to set debug mode for applet " + appletName; + alert(msg); + } + + +} + + + +//////////////////////////////////////////////////////////// +// +//INITIALIZE +// +//////////////////////////////////////////////////////////// + +ww_applet.prototype.initializeAction = function () { + var state = ''; + this.setState(); +}; + +ww_applet.prototype.submitAction = function () { + var appletName = this.appletName; + // var getAnswer = this.getAnswerAlias; + var ww_preserve_applet_state = getQE(appletName + "_state"); // hidden HTML input element preserving applet state + var saved_state = ww_preserve_applet_state.value; + + this.debug_add("Begin submit action for applet " + appletName); + var applet = getApplet(appletName); + if (! this.isReady ) { + alert(appletName + " is not ready"); + this.initializeAction(); + } + // Check to see if we want to restart the applet + + if (saved_state.match(/^<xml>restart_applet<\/xml>/) ) { + this.debug_add("Restarting the applet "+appletName); + setAppletStateToRestart(appletName); // erases all of the saved state + return(''); + } + // if we are not restarting the applet save the state and submit + + this.getState(); // have ww_applet retrieve state from applet and store in answerbox + this.debug_add("Submit Action Script " + this.submitActionScript + "\n"); + eval(this.submitActionScript); + //getQE(this.answerBox).value = applet.[getAnswer](); //FIXME -- not needed in general? + this.debug_add("Completed submitAction(" + this.submitActionScript + ") \nfor applet " + appletName+ "\n"); + if (this.debugMode){alert(debugText); debugText="";} +}; + + +ww_applet.prototype.checkLoaded = function() { // this function returns 0 unless: + // applet has already been flagged as ready in applet_isReady_list + // applet.config is defined (or alias for .config) + // applet.setState is defined + // applet.isActive is defined and returns 1; + // applet reported that it is loaded by calling applet_loaded() + var ready = 0; + var appletName = this.appletName; + var applet = getApplet(appletName); + + // alert("2 jsDebugMode " + jsDebugMode + " applet debugMode " + this.debugMode + " local debugMode " + debugMode); + + if (this.debugMode==0 && this.isReady) {return(1)}; // memorize readiness in non-debug mode + + this.debug_add("Test 4 methods to see if the applet " + appletName + " has been loaded: \n"); + + + if ( this.methodDefined(this.setConfigAlias) ) { + ready = 1; + } + if ( this.methodDefined(this.setStateAlias) ) { + ready =1; + } + + + if (typeof(this.reportsLoaded) !="undefined" && this.reportsLoaded != 0 ) { + this.debug_add( " " + appletName + " applet self reports that it has completed loading. " ); + ready =1; + } + + // the return value of the isActive() method, when defined, overrides the other indications + // that the applet is ready + + if ( this.methodDefined("isActive") ) { + if (applet.isActive()) { //this could be zero if applet is loaded, but it is loading auxiliary data. + this.debug_add( "Applet " +appletName + " signals it is active."); + ready =1; + } else { + this.debug_add( "Applet " + appletName + " signals it is not active. -- \n it may still be loading data."); + ready = "still_loading"; + } + } + + this.isReady = ready; + return(ready); +} +ww_applet.prototype.debug_add = function(str) { + if (this.debugMode) { + debugText = debugText + "\n" +str; // a global text string + } +} +ww_applet.prototype.safe_applet_initialize = function(i) { + //alert("begin safe_applet_initialize"); + var appletName = this.appletName; + i--; + this.debug_add(" Try to initialize applet " + appletName + ". Count down: " + i + ".\n" ); + + //alert("1 jsDebugMode " + jsDebugMode + " applet debugMode " +this.debugMode); + + var applet_loaded = this.checkLoaded(); + + if (applet_loaded=="still_loading" && !(i> 0) ) { + // it's possible that the isActive() response of the applet is not working properly + alert("The isActive() method of applet " +appletName + " claims it is still loading! We'll ignore this."); + i=1; + applet_loaded=1; + } else if (applet_loaded=="still_loading") { + applet_loaded=0; // keep trying + } + + + if ( 0 < i && !applet_loaded ) { // wait until applet is loaded + this.debug_add("Applet " + appletName + " is not yet ready try again\n"); + if (this.debugMode) { + alert(debugText ); + debugText=""; + } + window.setTimeout( "ww_applet_list[\""+ appletName + "\"].safe_applet_initialize(" + i + ")",100); + } else if( 0 < i ) { // now that applet is loaded configure it and initialize it with saved data. + + this.debug_add(" applet is ready = " + applet_loaded ); + + this.debug_add("Applet "+ appletName + " initialization completed\n with " + i + + " possible attempts remaining. \n" + + "------------------------------\n"); + + // in-line handler -- configure and initialize + //alert("setDebug") + try{ + + this.setDebug(this.debugMode); + + } catch(e) { + var msg = "Unable set debug in " + appletName + " \n " +e; + if (this.debugMode) {this.debug_add(msg);} else {alert(msg)}; + } + + //alert("config applet"); + try{ + + this.setConfig(); // for applets that require a configuration (which doesn't change for a given WW question + + } catch(e) { + var msg = "Unable to configure " + appletName + " \n " +e; + if (this.debugMode) {this.debug_add(msg);} else {alert(msg)}; + } + + + //alert("initializeAction"); + try{ + + this.initializeAction(); // this is often the setState action. + + } catch(e) { + var msg = "unable to initialize " + appletName + " \n " +e; + if (this.debugMode) { + this.debug_add(msg); + } else { + alert(msg); + } + } + if (this.debugMode) { + alert("\nBegin debugmode\n " + debugText ); + debugText=""; + }; + } else { + this.debug_add("Error: timed out waiting for applet " +appletName + " to load"); + //alert("4 jsDebugMode " + jsDebugMode + " applet debugMode " +ww_applet.debugMode + " local debugMode " +debugMode); + if (this.debugMode) { + alert(" in safe applet " + debugText ); + debugText=""; + } + } + +} + +function iamhere() { + alert( "javaScript loaded. functions still work"); +} \ No newline at end of file |
From: Mike G. v. a. <we...@ma...> - 2009-03-22 18:44:08
|
Log Message: ----------- minor changes to refine the applet interface and to make it work smoothly in both debuMode and non-debugMode Also changed the name of the reset_button to the reinitialize_button and the title the button carries Modified Files: -------------- pg/macros: AppletObjects.pl pg/lib: Applet.pm Revision Data ------------- Index: AppletObjects.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/AppletObjects.pl,v retrieving revision 1.19 retrieving revision 1.20 diff -Lmacros/AppletObjects.pl -Lmacros/AppletObjects.pl -u -r1.19 -r1.20 --- macros/AppletObjects.pl +++ macros/AppletObjects.pl @@ -111,11 +111,13 @@ # debugMode can be turned on by setting it to 1 in either the applet definition or at insertAll time my $debugMode = (defined($options{debug}) and $options{debug}==1) ? 1 : 0; + my $includeAnswerBox = (defined($options{includeAnswerBox}) and $options{includeAnswerBox}==1) ? 1 : 0; $debugMode = $debugMode || $self->debugMode; $self->debugMode( $debugMode); - my $reset_button = $options{reset_button} || 0; + my $reset_button = $options{reinitialize_button} || 0; + warn qq! please change "reset_button=>1" to "reinitialize_button=>1" in the applet->installAll() command ! if defined($options{reset_button}); # prepare html code for storing state my $appletName = $self->appletName; my $appletStateName = "${appletName}_state"; @@ -124,9 +126,8 @@ my $getConfig = $self->getConfigAlias; my $setConfig = $self->setConfigAlias; - my $base64_initialState = $self->base64_state; + my $base64_initialState = encode_base64($self->initialState); main::RECORD_FORM_LABEL($appletStateName); #this insures that they'll be saved from one invocation to the next - #main::RECORD_FORM_LABEL("previous_$appletStateName"); my $answer_value = ''; if ( defined( ${$main::inputs_ref}{$appletStateName} ) and ${$main::inputs_ref}{$appletStateName} =~ /\S/ ) { @@ -183,21 +184,27 @@ my $state_input_element = ($debugMode) ? $debug_input_element : qq!\n<input type="hidden" name = "$appletStateName" value ="$base_64_encoded_answer_value">!; my $reset_button_str = ($reset_button) ? - qq!<br/><input type='button' value='set applet state to restart' onClick="setAppletStateToRestart('$appletName')"> - <input type="button" value="reinitialize applet" onClick="getQE('$appletStateName').value='$base64_initialState'"/><br/>! - : '' - ; + qq!<input type='button' value='return this question to its initial state' onClick="setAppletStateToRestart('$appletName')"><br/>! + : '' ; + # <input type="button" value="reinitialize applet" onClick="getQE('$appletStateName').value='$base64_initialState'"/><br/> # always base64 encode the hidden answer value to prevent problems with quotes. # - $state_storage_html_code = qq!<input type="hidden" name="previous_$appletStateName" value = "$base_64_encoded_answer_value">! - . $reset_button_str - . $state_input_element + $state_storage_html_code = qq!<input type="hidden" name="previous_$appletStateName" value = "$base_64_encoded_answer_value">! + . $state_input_element. $reset_button_str ; - $answerBox_code = qq!<br/><input type="input" name="answerBox" value="" size =50><br/> - <input type="button" value="get Answer from applet" onClick="eval(ww_applet_list['$appletName'].submitActionScript )"/> - <br/> - !; - $answerBox_code = ($debugMode) ? $answerBox_code : q!<input type="hidden" name="answerBox" value="" size =50>!; + my $answerBox_code =''; + if ($includeAnswerBox) { + if ($debugMode) { + + $answerBox_code = $main::BR . main::NAMED_ANS_RULE('answerBox', 50 ); + $answerBox_code .= qq! + <br/><input type="button" value="get Answer from applet" onClick="eval(ww_applet_list['$appletName'].submitActionScript )"/> + <br/> + !; + } else { + $answerBox_code = main::NAMED_HIDDEN_ANS_RULE('answerBox', 50 ); + } + } ####### # insert header material ####### Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.21 retrieving revision 1.22 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.21 -r1.22 --- lib/Applet.pm +++ lib/Applet.pm @@ -31,7 +31,8 @@ setStateAlias => 'setXML', getStateAlias => 'getXML', setConfigAlias => 'config', - answerBoxAlias => 'receivedField', + answerBoxAlias => 'answerBox', + submitActionScript => qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() }, ); ################################### @@ -48,8 +49,9 @@ ################################### TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll( + includeAnswerBox => 1 debug=>0, - reset_button=>1, + reinitialize_button=>1, ))); @@ -151,13 +153,12 @@ header stores the text to be added to the header section of the html page object stores the text which places the applet on the html page - debug in debug mode several alerts mark progress through the procedure of calling the applet + debugMode in debug mode several alerts mark progress through the procedure of calling the applet - config configuration are those customizable attributes of the applet which don't + configuration configuration contains those customizable attributes of the applet which don't change as it is used. When stored in hidden answer fields it is usually stored in base64 encoded format. - base64_config base64 encode version of the contents of config - + configAlias (default: setConfig ) names the applet command called with the contents of $self->config to configure the applet. The parameters are passed to the applet in plain text using <xml> The outer tags must be <xml> ..... </xml> @@ -176,8 +177,6 @@ setStateAlias (default: setState) alias for the command called to reset the state of the applet. The state is passed in plain text in xml format with outer tags: <xml>....</xml> - base64_state returns the base64 encoded version of the state stored in the applet object. - initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the .pg question is pressed. @@ -363,10 +362,10 @@ width => 550, height => 400, bgcolor => "#869ca7", - base64_state => undef, # this is a state to use for initializing the first occurence of the question. - base64_config => undef, # this is the initial (and final?) configuration -# configuration => '', # configuration defining the applet - initialState => '', # initial state. (I'm considering storing everything as ascii and converting on the fly to base64 when needed.) +# base64_state => undef, # this is a state to use for initializing the first occurence of the question. +# base64_config => undef, # this is the initial (and final?) configuration + configuration => '', # configuration defining the applet + initialState => '', # initial state. getStateAlias => 'getXML', setStateAlias => 'setXML', configAlias => '', # deprecated @@ -395,7 +394,7 @@ warn "use setConfigAlias instead of configAlias"; $self->{configAlias}=''; } - $self->config('<xml></xml>'); + $self->configuration('<xml></xml>'); return $self; } @@ -532,35 +531,44 @@ $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty $self->{initialState}; } - -sub config { +sub configuration { my $self = shift; my $str = shift; - $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty - $self->{base64_config} =~ s/\n//g; - decode_base64($self->{base64_config}); + $self->{configuration} = $str || $self->{configuration}; # replace the current string if non-empty + $self->{configuration} =~ s/\n//g; + $self->{configuration}; } + ####################### # soon to be deprecated? ####################### + +sub config { + my $self = shift; + my $str = shift; + warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded", join(' ', caller()); +# $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty +# $self->{base64_config} =~ s/\n//g; +# decode_base64($self->{base64_config}); +} sub state { my $self = shift; my $str = shift; - $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty - $self->{base64_state} =~ s/\n//g; - decode_base64($self->{base64_state}); + warn "use $self->initialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller()); +# $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty +# $self->{base64_state} =~ s/\n//g; +# decode_base64($self->{base64_state}); } sub base64_state{ my $self = shift; - $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty - $self->{base64_state}; + warn "use $self->InitialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller()); + + } sub base64_config { my $self = shift; - $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty - $self->{base64_config} =$self->{base64_config}; - $self->{base64_config}; + warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded"; } sub returnFieldName { @@ -581,9 +589,7 @@ my $codebase = $self->codebase; my $appletId = $self->appletId; my $appletName = $self->appletName; - my $base64_initialState = $self->base64_state; my $initializeActionAlias = $self->initializeActionAlias; - my $submitActionAlias = $self->submitActionAlias; my $submitActionScript = $self->submitActionScript; my $setStateAlias = $self->setStateAlias; my $getStateAlias = $self->getStateAlias; @@ -591,19 +597,23 @@ my $setConfigAlias = $self->setConfigAlias; my $getConfigAlias = $self->getConfigAlias; my $maxInitializationAttempts = $self->maxInitializationAttempts; - my $base64_config = $self->base64_config; my $debugMode = ($self->debugMode) ? "1": "0"; my $answerBoxAlias = $self->{answerBoxAlias}; my $headerText = $self->header(); - $submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript + #$submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript # other variables should not have quotes. $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble my $base64_submitActionScript = encode_base64($submitActionScript); + my $base64_configuration = encode_base64($self->configuration); + my $base64_initialState = encode_base64($self->initialState); + $base64_submitActionScript =~s/\n//g; + $base64_initialState =~s/\n//g; # base64 encoded xml + $base64_configuration =~s/\n//g; # base64 encoded xml $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook @@ -674,15 +684,15 @@ ww_applet_list["$appletName"].codebase = "$codebase"; ww_applet_list["$appletName"].appletID = "$appletID"; ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; - ww_applet_list["$appletName"].initialState = Base64.decode("$base64_intialState"); - ww_applet_list["$appletName"].base64_config = "$base64_config"; + ww_applet_list["$appletName"].initialState = Base64.decode("$base64_initialState"); + ww_applet_list["$appletName"].configuration = Base64.decode("$base64_configuration");; ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias"; ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; - ww_applet_list["$appletName"].submitActionScript = Base64.decode("$submitActionScript_base64"); + ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript"); ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias"; ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts; ww_applet_list["$appletName"].debugMode = "$debugMode"; |
From: Mike G. v. a. <we...@ma...> - 2009-03-22 18:42:35
|
Log Message: ----------- refining the applet API Modified Files: -------------- webwork2/htdocs/js: ww_applet_support.js Revision Data ------------- Index: ww_applet_support.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/js/ww_applet_support.js,v retrieving revision 1.8 retrieving revision 1.9 diff -Lhtdocs/js/ww_applet_support.js -Lhtdocs/js/ww_applet_support.js -u -r1.8 -r1.9 --- htdocs/js/ww_applet_support.js +++ htdocs/js/ww_applet_support.js @@ -20,32 +20,17 @@ // applet lists ////////////////////////////////////////////////////////// -// var applet_initializeAction_list = new Object; // functions for initializing question with an applet -// var applet_submitAction_list = new Object; // functions for submitting question with applet -// var applet_setState_list = new Object; // functions for setting state (XML) from applets -// var applet_getState_list = new Object; // functions for getting state (XML) from applets -// var applet_config_list = new Object; // functions for configuring on applets -// var applet_checkLoaded_list = new Object; // functions for probing the applet to see if it is loaded -// var applet_reportsLoaded_list = new Object; // flag set by applet -// var applet_isReady_list = new Object; // flag set by javaScript in checkLoaded - var ww_applet_list = new Object; // holds intelligent ww_applet objects + var ww_applet_list = new Object; // holds java script version (jsApplet) ww_applet objects ////////////////////////////////////////////////////////// // DEBUGGING tools ////////////////////////////////////////////////////////// - var jsDebugMode; + var jsDebugMode=0; // set this to one when needed for major debugging -- puts all applets in debugMode var debugText = ""; - function set_debug(num) { // setting debug for any applet sets it for all of them - if (num) { - jsDebugMode =1; - } - } - function debug_add(str) { - if (jsDebugMode) { + function debug_add(str) { debugText = debugText + "\n" +str; - } } ////////////////////////////////////////////////////////// @@ -53,16 +38,16 @@ ////////////////////////////////////////////////////////// function submitAction() { // called from the submit button defined in Problem.pm - - if (jsDebugMode) { + + if (jsDebugMode==1) { debugText = "Call submitAction() function on each applet\n"; } for (var appletName in ww_applet_list ) { ww_applet_list[appletName].submitAction(); } - debug_add("\n Done calling submitAction() on each applet.\n"); - if (jsDebugMode) { + if (jsDebugMode==1) { debug_add("\n Done calling submitAction() on each applet.\n");} + if (jsDebugMode==1) { alert(debugText); debugText=""; }; } @@ -73,10 +58,10 @@ } function initializeWWquestion() { // called from <body> tag defined in the webwork2/conf/template - var iMax = 5; - debugText="Initialize each applet. \nUse up to " +iMax + " cycles to wait for each applet to load\n"; - for (var appletName in ww_applet_list) { - safe_applet_initialize(appletName, iMax); + for (var appletName in ww_applet_list) { + var maxInitializationAttempts = ww_applet_list[appletName].maxInitializationAttempts; + // alert("Initialize each applet. \nUse up to " +maxInitializationAttempts + " cycles to load" +"\n"); + ww_applet_list[appletName].safe_applet_initialize(maxInitializationAttempts); } } @@ -91,60 +76,6 @@ // insures that applet is loaded before initializing it -function safe_applet_initialize(appletName, i) { - i--; - debug_add(" Try to initialize applet " + appletName + ". Count down: " + i + ".\n" ); - - - var ww_applet = ww_applet_list[appletName]; - var applet_loaded = ww_applet.checkLoaded(); - if (applet_loaded=="still_loading" && !(i> 0) ) { - // it's possible that the isActive() response of the applet is not working properly - alert("The isActive() method of applet " +appletName + " claims it is still loading! We'll ignore this."); - i=1; - applet_loaded=1; - } else if (applet_loaded=="still_loading") { - applet_loaded=0; // keep trying - } - - - debug_add(" applet is ready = " + applet_loaded ); - - if ( 0 < i && !applet_loaded ) { // wait until applet is loaded - debug_add(" applet " + appletName + " is not yet ready try again"); - window.setTimeout( "safe_applet_initialize(\"" + appletName + "\"," + i + ")",1); - } else if( 0 < i ){ // now that applet is loaded configure it and initialize it with saved data. - debug_add(appletName + " initialization completed with " + i + " possible attempts remaining. \n"); - - // in-line handler -- configure and initialize - try{ - ww_applet.setDebug(jsDebugMode); - } catch(e) { - var msg = "Unable set debug in " + appletName + " \n " +e; - if (jsDebugMode) {debug_add(msg);} else {alert(msg)}; - } - try{ - - ww_applet.config(); - - } catch(e) { - var msg = "Unable to configure " + appletName + " \n " +e; - if (jsDebugMode) {debug_add(msg);} else {alert(msg)}; - } - try{ - - ww_applet.initializeAction(); - - } catch(e) { - var msg = "unable to initialize " + appletName + " \n " +e; - if (jsDebugMode) {debug_add(msg);} else {alert(msg)}; - } - - } else { - if (jsDebugMode) {debug_add("Error: timed out waiting for applet " +appletName + " to load");} - } - if (jsDebugMode) {alert(debugText); debugText="";}; -} /////////////////////////////////////////////////////// // Utility functions @@ -186,7 +117,7 @@ function base64Q(str) { /// determine whether an XML string has been base64 encoded. return ( !str.match(/<XML/i) && !str.match(/<?xml/i)); } -function setAppletStateToRestart(appletName){ +function setAppletStateToRestart(appletName){ var newState = "<xml>restart_applet</xml>"; //ww_applet_list[appletName].setState(newState); getQE(appletName+"_state").value = newState; @@ -200,7 +131,7 @@ // needed for IE -- searches id and name space so it can be unreliable if names are not unique if (!obj || obj.name != name1) { var msg = "Can't find element " + name1; - if (jsDebugMode) { + if (jsDebugMode==1) { debug_add(msg + "\n ( Place listQuestionElements() at end of document in order to get all form elements! )\n" ); } else { alert(msg); listQuestionElements(); @@ -227,8 +158,10 @@ this.code = ''; this.codebase = ''; this.appletID = ''; - this.base64_state = ''; - this.base64_config = ''; +// this.base64_state = ''; +// this.base64_config = ''; + this.configuration = ''; + this.initialState = ''; this.getStateAlias = ''; this.setStateAlias = ''; this.configAlias = ''; @@ -237,55 +170,88 @@ this.submitActionScript = ''; this.getAnswerAlias = ''; this.answerBox = ''; - this.debug = ''; + this.debugMode = 0 ; this.isReady = 0 ; this.reportsLoaded = 0 ; }; +////////////////////////////////////////////////////////// +// methodDefined +// +// make sure that the applet has this function available +////////////////////////////////////////////////////////// +ww_applet.prototype.methodDefined = function(methodName) { + var appletName = this.appletName; + var applet = getApplet(appletName); + try { + if (typeof(applet[methodName]) == "function" ) { + this.debug_add("Method " + methodName + " is defined in " + appletName ); + return(true); + } else { + this.debug_add("Method " + methodName + " is not defined in " + appletName); + return(false); + } + } catch(e) { + var msg = "Error in accessing " + methodName + " in applet " +appletName + "Error: " +e ; + alert(msg); + } + return(false); +} ////////////////////////////////////////////////////////// //CONFIGURATIONS // // configurations are "permanent" ////////////////////////////////////////////////////////// -ww_applet.prototype.config = function () { +ww_applet.prototype.setConfig = function () { var appletName = this.appletName; var applet = getApplet(appletName); var setConfigAlias = this.setConfigAlias; - debug_add(" Calling " + appletName +"."+ setConfigAlias +"( " + Base64.decode(this.base64_config) + " ) " ); - try { + + try { if ( this.methodDefined(setConfigAlias) ) { - applet[setConfigAlias](Base64.decode(this.base64_config)); + applet[setConfigAlias](this.configuration); } + } catch(e) { + var msg = "Error in configuring " + appletName + " using command " + setConfigAlias + " : " + e ; alert(msg); } + this.debug_add(" Calling " + appletName +"."+ setConfigAlias +"( " + this.configuration + " ) " ); + }; + + ww_applet.prototype.getConfig = function() { // used for debugging purposes -- gets the configuration from the applet + + + var appletName = this.appletName; + var applet = getApplet(appletName); + var getConfigAlias = this.getConfigAlias; + + + try { + if (this.methodDefined(getConfigAlias) ) { + alert( applet[getConfigAlias]() ); + } else { + alert("in getConfig " + debugText); + } + } catch(e) { + var msg = " Error in getting configuration from applet " + appletName + " " + e; + alert(msg); + } +} + + + //////////////////////////////////////////////////////////// // //STATE: // state can vary as the applet is manipulated -- it is reset from the questions _state values // ////////////////////////////////////////////////////////// -ww_applet.prototype.methodDefined = function(methodName) { - var appletName = this.appletName; - var applet = getApplet(appletName); - try { - if (typeof(applet[methodName]) == "function" ) { - debug_add("Method " + methodName + " is defined in " + appletName ); - return(true); - } else { - debug_add("Method " + methodName + " is not defined in " + appletName); - return(false); - } - } catch(e) { - var msg = "Error in accessing " + methodName + " in applet " +appletName + "Error: " +e ; - alert(msg); - } - return(false); -} + ww_applet.prototype.setState = function(state) { @@ -293,12 +259,12 @@ var applet = getApplet(appletName); var setStateAlias = this.setStateAlias; - debug_add("\nBegin process of setting state for applet " + appletName); + debug_add("\n++++++++++++++++++++++++++++++++++++++++\nBegin process of setting state for applet " + appletName); if (state) { - debug_add(" Obtain state from calling parameter:\n " + state + "\n"); + debug_add("Obtain state from calling parameter:\n " + state + "\n"); } else { - debug_add(" Obtain state from " + appletName +"_state"); + this.debug_add("Obtain state from " + appletName +"_state"); var ww_preserve_applet_state = getQE(appletName + "_state"); // hidden answer box preserving applet state state = ww_preserve_applet_state.value; @@ -307,20 +273,19 @@ if ( base64Q(state) ) { state=Base64.decode(state); } - // if we are restarting the applet bail -- we don't want to set the state. if (state.match(/^<xml>restart_applet<\/xml>/) ) { - alert("The applet " +appletName + "has been reset to its virgin state."); - ww_preserve_applet_state.value =""; //Fixme? should we set the last answer to blank as well? - return(''); + alert("The applet " +appletName + "has been reset to its virgin state." + this.initialState); + ww_preserve_applet_state.value =this.initialState; //Fixme? should we set the last answer to blank as well? + state = ww_preserve_applet_state.value; } if (state.match(/<xml/i) || state.match(/<?xml/i) ) { // if state starts with <?xml - debug_add(" Set (decoded) state for " + appletName + " to \n\n" + - state +"\n\n Check that applet's setState method " +setStateAlias + " is a function: " +typeof(applet[setStateAlias]) - ); + this.debug_add("Set state for " + appletName + " to \n------------------------------\n" + + state + "\n------------------------------\n"); try { + if ( this.methodDefined(setStateAlias) ) { applet[setStateAlias]( state ); // change the applets current state } @@ -328,8 +293,8 @@ msg = "Error in setting state of " + appletName + " using command " + setStateAlias + " : " + e ; alert(msg); } - } else if (jsDebugMode) { - debug_add(" new state was empty string or did not begin with <xml> -- Applet state was not reset"); + } else if (jsDebugMode==1) { + this.debug_add(" new state was empty string or did not begin with <xml> -- Applet state was not reset"); } return(''); }; @@ -341,7 +306,7 @@ var applet = getApplet(appletName); var getStateAlias = this.getStateAlias; - debug_add(" Begin getState for applet " + appletName ); + this.debug_add(" Begin getState for applet " + appletName ); try { if (this.methodDefined(getStateAlias)) { // there may be no state function @@ -349,9 +314,9 @@ debug_add(" state has type " + typeof(state)); state = String(state); // geogebra returned an object type instead of a string type // this insures that we can view the state as a string - debug_add(" state converted to type " + typeof(state)); + this.debug_add(" state converted to type " + typeof(state)); } else { - debug_add(" Applet does not have a getState method named: "+ getStateAlias + "."); + this.debug_add(" Applet does not have a getState method named: "+ getStateAlias + "."); state ="<xml>undefined_state</xml>"; } @@ -360,28 +325,30 @@ alert(msg); } - if (!jsDebugMode) { + if (this.debugMode==0) { state = Base64.encode(state); }; // replace state by encoded version unless in debug mode - debug_add(" state is \n "+ state + "\n"); // state should still be in plain text + this.debug_add(" state is \n "+ state + "\n"); // state should still be in plain text var ww_preserve_applet_state = getQE(appletName + "_state"); // answer box preserving applet state (jsDebugMode: textarea, otherwise: hidden) ww_preserve_applet_state.value = state; //place state in input item (jsDebugMode: textarea, otherwise: hidden) - debug_add("State stored in answer box "+ appletName + "_state and getState is finished."); + this.debug_add("State stored in answer box "+ appletName + "_state and getState is finished."); }; ww_applet.prototype.setDebug = function(debugMode) { + // sets debug mode in the flash or java applet + // applet's method must be called debug var appletName = this.appletName; var applet = getApplet(appletName); - debugMode = debugMode || this.debug; + debugMode = jsDebugMode || debugMode ; try{ if (this.methodDefined("debug") ) { - applet.debug(1); // turn the applet's debug functions on. + applet.debug(debugMode); // set the applet's debug functions on. } else { - debug_add( " Unable to set debug state in applet " + appletName + "."); + this.debug_add( " Unable to set debug state in applet " + appletName + "."); } } catch(e) { @@ -391,23 +358,7 @@ } -ww_applet.prototype.getConfig = function() { // used for debugging purposes -- gets the configuration from the applet - var config = "foobar"; - var appletName = this.appletName; - var applet = getApplet(appletName); - var getConfigAlias = this.getConfigAlias; - try { - if (this.methodDefined(getConfigAlias) ) { - alert( applet[getConfigAlias]() ); - } else { - alert(debugText); - } - } catch(e) { - var msg = " Error in getting configuration from applet " + appletName + " " + e; - alert(msg); - } -} - + //////////////////////////////////////////////////////////// @@ -421,32 +372,33 @@ this.setState(); }; -ww_applet.prototype.submitAction = function () { +ww_applet.prototype.submitAction = function () { var appletName = this.appletName; // var getAnswer = this.getAnswerAlias; - var ww_preserve_applet_state = getQE(appletName + "_state"); // hidden answer box preserving applet state + var ww_preserve_applet_state = getQE(appletName + "_state"); // hidden HTML input element preserving applet state var saved_state = ww_preserve_applet_state.value; - if (jsDebugMode) {debug_add("Begin submit action for applet " + appletName);} + this.debug_add("Begin submit action for applet " + appletName); var applet = getApplet(appletName); if (! this.isReady ) { alert(appletName + " is not ready"); - initializeAction(); + this.initializeAction(); } // Check to see if we want to restart the applet if (saved_state.match(/^<xml>restart_applet<\/xml>/) ) { - if (jsDebugMode) { debug_add("Restarting the applet "+appletName);} + this.debug_add("Restarting the applet "+appletName); setAppletStateToRestart(appletName); // erases all of the saved state return(''); } // if we are not restarting the applet save the state and submit this.getState(); // have ww_applet retrieve state from applet and store in answerbox - if (jsDebugMode) {debug_add("Submit Action Script " + this.submitActionScript + "\n");} + this.debug_add("Submit Action Script " + this.submitActionScript + "\n"); eval(this.submitActionScript); //getQE(this.answerBox).value = applet.[getAnswer](); //FIXME -- not needed in general? - if (jsDebugMode) {debug_add("Completed submitAction() for applet " + appletName+ "\n");} + this.debug_add("Completed submitAction(" + this.submitActionScript + ") \nfor applet " + appletName+ "\n"); + if (this.debugMode){alert(debugText); debugText="";} }; @@ -459,8 +411,14 @@ var ready = 0; var appletName = this.appletName; var applet = getApplet(appletName); - if (!jsDebugMode && this.isReady) {return(1)}; // memorize readiness in non-debug mode - debug_add("Test 4 methods to see if the applet " + appletName + " has been loaded: \n"); + + // alert("2 jsDebugMode " + jsDebugMode + " applet debugMode " + this.debugMode + " local debugMode " + debugMode); + + if (this.debugMode==0 && this.isReady) {return(1)}; // memorize readiness in non-debug mode + + this.debug_add("Test 4 methods to see if the applet " + appletName + " has been loaded: \n"); + + if ( this.methodDefined(this.setConfigAlias) ) { ready = 1; } @@ -468,23 +426,117 @@ ready =1; } + + if (typeof(this.reportsLoaded) !="undefined" && this.reportsLoaded != 0 ) { + this.debug_add( " " + appletName + " applet self reports that it has completed loading. " ); + ready =1; + } + + // the return value of the isActive() method, when defined, overrides the other indications + // that the applet is ready + if ( this.methodDefined("isActive") ) { if (applet.isActive()) { //this could be zero if applet is loaded, but it is loading auxiliary data. - debug_add( "Applet " +appletName + " signals it is active."); + this.debug_add( "Applet " +appletName + " signals it is active."); ready =1; } else { - debug_add( "Applet " + appletName + " signals it is not active. -- \n it may still be loading data."); + this.debug_add( "Applet " + appletName + " signals it is not active. -- \n it may still be loading data."); ready = "still_loading"; } } - if (typeof(this.reportsLoaded) !="undefined" && this.reportsLoaded != 0 ) { - debug_add( " " + appletName + " applet self reports that it has completed loading. " ); - ready =1; - } + this.isReady = ready; return(ready); } +ww_applet.prototype.debug_add = function(str) { + if (this.debugMode) { + debugText = debugText + "\n" +str; // a global text string + } +} +ww_applet.prototype.safe_applet_initialize = function(i) { + //alert("begin safe_applet_initialize"); + var appletName = this.appletName; + i--; + this.debug_add(" Try to initialize applet " + appletName + ". Count down: " + i + ".\n" ); + //alert("1 jsDebugMode " + jsDebugMode + " applet debugMode " +this.debugMode); + + var applet_loaded = this.checkLoaded(); + + if (applet_loaded=="still_loading" && !(i> 0) ) { + // it's possible that the isActive() response of the applet is not working properly + alert("The isActive() method of applet " +appletName + " claims it is still loading! We'll ignore this."); + i=1; + applet_loaded=1; + } else if (applet_loaded=="still_loading") { + applet_loaded=0; // keep trying + } + + + if ( 0 < i && !applet_loaded ) { // wait until applet is loaded + this.debug_add("Applet " + appletName + " is not yet ready try again\n"); + if (this.debugMode) { + alert(debugText ); + debugText=""; + } + window.setTimeout( "ww_applet_list[\""+ appletName + "\"].safe_applet_initialize(" + i + ")",100); + } else if( 0 < i ) { // now that applet is loaded configure it and initialize it with saved data. + + this.debug_add(" applet is ready = " + applet_loaded ); + + this.debug_add("Applet "+ appletName + " initialization completed\n with " + i + + " possible attempts remaining. \n" + + "------------------------------\n"); + + // in-line handler -- configure and initialize + //alert("setDebug") + try{ + + this.setDebug(this.debugMode); + + } catch(e) { + var msg = "Unable set debug in " + appletName + " \n " +e; + if (this.debugMode) {this.debug_add(msg);} else {alert(msg)}; + } + + //alert("config applet"); + try{ + + this.setConfig(); // for applets that require a configuration (which doesn't change for a given WW question + + } catch(e) { + var msg = "Unable to configure " + appletName + " \n " +e; + if (this.debugMode) {this.debug_add(msg);} else {alert(msg)}; + } + + + //alert("initializeAction"); + try{ + + this.initializeAction(); // this is often the setState action. + + } catch(e) { + var msg = "unable to initialize " + appletName + " \n " +e; + if (this.debugMode) { + this.debug_add(msg); + } else { + alert(msg); + } + } + if (this.debugMode) { + alert("\nBegin debugmode\n " + debugText ); + debugText=""; + }; + } else { + this.debug_add("Error: timed out waiting for applet " +appletName + " to load"); + //alert("4 jsDebugMode " + jsDebugMode + " applet debugMode " +ww_applet.debugMode + " local debugMode " +debugMode); + if (this.debugMode) { + alert(" in safe applet " + debugText ); + debugText=""; + } + } + +} function iamhere() { alert( "javaScript loaded. functions still work"); |
From: dpvc v. a. <we...@ma...> - 2009-03-22 11:07:57
|
Log Message: ----------- Have popup handle a context passed to its new() method, lik all other MathObjects Modified Files: -------------- pg/macros: parserPopUp.pl Revision Data ------------- Index: parserPopUp.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/parserPopUp.pl,v retrieving revision 1.8 retrieving revision 1.9 diff -Lmacros/parserPopUp.pl -Lmacros/parserPopUp.pl -u -r1.8 -r1.9 --- macros/parserPopUp.pl +++ macros/parserPopUp.pl @@ -76,6 +76,7 @@ # sub new { my $self = shift; my $class = ref($self) || $self; + shift if Value::isContext($_[0]); # remove context, if given (it is not used) my $choices = shift; my $value = shift; Value::Error("A PopUp's first argument should be a list of menu items") unless ref($choices) eq 'ARRAY'; |
From: Mike G. v. a. <we...@ma...> - 2009-03-15 19:35:43
|
Log Message: ----------- Added documentation for applet API added initialState to the instance variables Modified Files: -------------- pg/lib: Applet.pm pg/macros: AppletObjects.pl Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.20 retrieving revision 1.21 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.20 -r1.21 --- lib/Applet.pm +++ lib/Applet.pm @@ -23,39 +23,34 @@ ################################### # Create link to applet ################################### - my $appletName = "LineThruPointsWW"; - $applet = new FlashApplet( - # can be replaced by $applet =FlashApplet() when using AppletObjects.pl - codebase => findAppletCodebase("$appletName.swf"), - appletName => $appletName, - appletId => $appletName, - submitActionAlias => 'checkAnswer', - ); - - ################################### - # Configure applet - ################################### - - #xml data to set up the problem-rac - $applet->config(qq{<XML> - <point xval='$xval_1' yval='$yval_1' /> - <point xval='$xval_2' yval='$yval_2' /> - </XML>}); - - - ################################### - # insert applet header material - ################################### - HEADER_TEXT($applet->insertHeader ); - - ################################### - # Text section - # - - ################################### - #insert applet into body - ################################### - TEXT( MODES(TeX=>'object code', HTML=>$applet->insertObject)); + $appletName = "PointGraph"; +$applet = FlashApplet( + codebase => findAppletCodebase("$appletName.swf"), + appletName => $appletName, + appletId => $appletName, + setStateAlias => 'setXML', + getStateAlias => 'getXML', + setConfigAlias => 'config', + answerBoxAlias => 'receivedField', +); + +################################### +# Configure applet +################################### + +#data to set up the equation +$applet->config(qq{<XML expr='(x - $a)^3 + $b/$a * x' />}); +# initial points +$applet->state(qq{<XML> +</XML>}); +################################### +#insert applet into body +################################### + +TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll( + debug=>0, + reset_button=>1, + ))); =head1 DESCRIPTION @@ -186,9 +181,9 @@ initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the .pg question is pressed. - answerBox -- name of answer box to return answer to: default defaultAnswerBox + answerBoxAlias -- name of answer box to return answer to: default defaultAnswerBox getAnswer -- (formerly sendData) get student answer from applet and place in answerBox - returnFieldName -- (deprecated) synonmym for answerBox + returnFieldName -- (deprecated) synonmym for answerBoxAlias =cut @@ -207,10 +202,116 @@ corresponds to ww_applet_list["myApplet"].appletName. (This paragraph is not yet fully implemented :-(). 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 -to a base64 constant and then converted back to text form when it is read by an javaScript subroutine. +to a base64 constant and then converted back to text form when it is read by a javaScript subroutine. + +The perlApplet has methods that help place the jsApplet code on the HTML page and create the link to the applet itself. +In particular instance variables such as "setStateAlias", "getStateAlias" connect the WW default of "setState" to subroutine +name chosen by the applet designer. The aim is to make it easier to connect to applets previously designed to work +with javaScript in an HTML page or other systems. + + +The jsApplet acts as an intermediary for commands directed at the applet. +It is not necessary for the minimal operations of +configuring the applet and maintaining +state from one viewing of the WW question to address the applet directly. +The methods such as "setState", "getState", "setConfig" which are part of the jsApplet +take care of the book keeping details. +It is also possible to make direct calls to the applet from handcrafted javaScript subroutines, +but it may be convenient to store these as additional methods in the +jsApplet. + +=cut + +=head4 Detecting that the applet is ready + +Timing issues are among the pitfalls awaiting when using flash or java applets in WW questions. It is important that the WW question +does not issue any commands to the applet until the applet is fully loaded, including the uploading of any additional configuration +information from XML files. This can be tricky since the timing issues usually don't arise when initiating the applet from an HTML page. + +The WW API performs the following actions to determine if the applet is loaded: + + check the ww_applet_list[appletName].isReady flag (1== applet is ready) + -- this caches the readiness information so that it doesn't + have to be repeated within a given viewing of a WW question + If this is 1 then the applet is ready. + determine whether the applet's isActive subroutine is defined AND returns 1 when called. + -- if the return value is 1 the applet is ready, if it is zero or no response then the applet is NOT ready + -- If the applet has an isActive() subroutine -- there is no alias for this -- + then it must return 1 as soon as the applet is ready. Otherwise + the applet will timeout. + determine whether the applet's setConfig subroutine is defined. + -- applet.{setConfigAlias}. + determine whether the applet's setState subroutine is defined. + determine whether the jsApplets ww_applet_list[appletName].reportsLoaded flag is set to 1 + -- this can be set by the applet if it calls the javaScript function + "applet_loaded(appletName, loaded_status). The loaded_status is 1 or 0 + + Logic for determining applet status: if any one of the above checks succeeds (or returns 1) then the applet is + consdered to be ready UNLESS the isActive() exists and the call returns a 0 or no response. In this case + the applet is assumed to be loading additional data and is not yet ready. + + For this reason if the isActive subroutine + is defined in the applet it must return a 1 once the applet is prepared to accept additional commands. + (Since there are some extent flashApplets with non-functioning isActive() subroutines a temporary workaround + assuems that after C<maxInitializationAttempts> -- 5 by default -- the applet is in fact ready but the + isActive() subroutine is non functioning. This can give rise to false "readiness" signals if the applet + takes a long time to load auxiliary files.) + +The applet itself can take measures to insure that the setConfig subroutine is prepared to respond immediately once the applet is loaded. +It can include timers that delay execution of the configuring actions until all of the auxiliary files needed by the applet are loaded. + + +=cut + + +=head4 Initialization sequence + +When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them +to initialize themselves. + +The applets initialization method is as follows: + + -- wait until the applet is loaded and the applet has loaded all of its auxiliary files. + -- set the debugMode in the applet + -- call the setConfig method in the javaScript applet -- (configuration parameters are "permanent" for the life of the applet + -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet =cut +=head Methods defined for the javaScript applet ww_applet_list[appletName] + +This is not a comprehensive list + + setConfig -- transmits the information for configuring the applet + + getConfig -- retrieves the configuration information -- this is used mainly for debugging and may not be defined in most applets + + + setState -- sets the current state (1) from the appletName_state HTML element if this contains an <xml>...</xml> string + -- if the value contains <xml>restart_applet</xml> then set the current state to ww_applet_list[appletName].initialState + -- if the value is a blank string set the current state to ww_applet_list[appletName].initialState + + + getState -- retrieves the current state and stores in the appletName_state HTML element. + + + + + + + +=head Submit sequence + +When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks +each of the applets on the page to perform its submit action which consists of + + -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then + the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml> + to be interpreted by the next setState command + -- Otherwise getState() from the applet and save it to the HTML input element appletName_state + -- Perform the javaScript commands in .submitActionScript (default: '' ) + a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer() ) + =head4 Requirements for applets The following methods are desirable in an applet that preserves state in a WW question. None of them are required. @@ -245,7 +346,7 @@ the configuration was set as expected. getAnswer (default: getAnswer) -- Returns a string (usually NOT xml) which is the - response that the student is submitting to answer + response that the student is effectvely submitting to answer the WW question. @@ -272,6 +373,7 @@ getConfigAlias => 'getConfig', setConfigAlias => 'setConfig', initializeActionAlias => 'setXML', + maxInitializationAttempts => 5, # number of attempts to initialize applet submitActionAlias => 'getXML', submitActionScript => '', # script executed on submitting the WW question answerBoxAlias => 'answerBox', @@ -279,7 +381,7 @@ returnFieldName => '', # deprecated headerText => DEFAULT_HEADER_TEXT(), objectText => '', - debug => 0, + debugMode => 0, @_, }; bless $self, $class; @@ -410,16 +512,20 @@ $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty $self->{appletName}; } -sub debug { +sub debugMode { my $self = shift; my $new_flag = shift; - $self->{debug} = $new_flag if defined($new_flag); - $self->{debug}; + $self->{debugMode} = $new_flag if defined($new_flag); + $self->{debugMode}; } sub appletId { appletName(@_); } - +sub maxInitializationAttempts { + my $self = shift; + $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts}; + $self->{maxInitializationAttempts}; +} sub initialState { my $self = shift; my $str = shift; @@ -463,7 +569,7 @@ } sub answerBox { my $self = shift; - warn "use answerBoxName instead of AnswerBox"; + warn "use answerBoxAlias instead of AnswerBox"; } ######################### #FIXME @@ -475,19 +581,19 @@ my $codebase = $self->codebase; my $appletId = $self->appletId; my $appletName = $self->appletName; - my $base64_initialState = $self->base64_state; - my $initializeAction = $self->initializeActionAlias; + my $base64_initialState = $self->base64_state; + my $initializeActionAlias = $self->initializeActionAlias; my $submitActionAlias = $self->submitActionAlias; - my $submitActionScript = $self->submitActionScript; + my $submitActionScript = $self->submitActionScript; my $setStateAlias = $self->setStateAlias; my $getStateAlias = $self->getStateAlias; my $setConfigAlias = $self->setConfigAlias; my $getConfigAlias = $self->getConfigAlias; + my $maxInitializationAttempts = $self->maxInitializationAttempts; my $base64_config = $self->base64_config; - my $debugMode = ($self->debug) ? "1": "0"; - my $returnFieldName = $self->{returnFieldName}; - my $answerBox = $self->{answerBox}; + my $debugMode = ($self->debugMode) ? "1": "0"; + my $answerBoxAlias = $self->{answerBoxAlias}; my $headerText = $self->header(); @@ -496,6 +602,8 @@ $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble + my $base64_submitActionScript = encode_base64($submitActionScript); + $base64_submitActionScript =~s/\n//g; $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook @@ -551,8 +659,7 @@ </script> <script language="JavaScript"> - // set debug mode for this applet - set_debug($debugMode); + ////////////////////////////////////////////////////////// //TEST code @@ -564,19 +671,21 @@ ww_applet_list["$appletName"].code = "$code"; - ww_applet_list["$appletName"].codebase = "$codebase"; - ww_applet_list["$appletName"].appletID = "$appletID"; - ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; - ww_applet_list["$appletName"].base64_config = "$base64_config"; - ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; - ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; + ww_applet_list["$appletName"].codebase = "$codebase"; + ww_applet_list["$appletName"].appletID = "$appletID"; + ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; + ww_applet_list["$appletName"].initialState = Base64.decode("$base64_intialState"); + ww_applet_list["$appletName"].base64_config = "$base64_config"; + ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; + ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; - ww_applet_list["$appletName"].initializeActionAlias = "$initializeAction"; + ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias"; ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; - ww_applet_list["$appletName"].submitActionScript = "$submitActionScript"; - ww_applet_list["$appletName"].answerBox = "$answerBox"; - ww_applet_list["$appletName"].debug = "$debugMode"; + ww_applet_list["$appletName"].submitActionScript = Base64.decode("$submitActionScript_base64"); + ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias"; + ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts; + ww_applet_list["$appletName"].debugMode = "$debugMode"; </script> Index: AppletObjects.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/AppletObjects.pl,v retrieving revision 1.18 retrieving revision 1.19 diff -Lmacros/AppletObjects.pl -Lmacros/AppletObjects.pl -u -r1.18 -r1.19 --- macros/AppletObjects.pl +++ macros/AppletObjects.pl @@ -39,7 +39,7 @@ # don't reload this file ######################################################################### -sub _AppletObjects_init { +sub _AppletObjects_init{ main::HEADER_TEXT(<<'END_HEADER_TEXT'); <script language="javascript">AC_FL_RunContent = 0;</script> @@ -108,7 +108,13 @@ sub insertAll { ## inserts both header text and object text my $self = shift; my %options = @_; - $self->debug( (defined($options{debug}) and $options{debug}==1) ? 1 : 0 ); + + # debugMode can be turned on by setting it to 1 in either the applet definition or at insertAll time + my $debugMode = (defined($options{debug}) and $options{debug}==1) ? 1 : 0; + $debugMode = $debugMode || $self->debugMode; + $self->debugMode( $debugMode); + + my $reset_button = $options{reset_button} || 0; # prepare html code for storing state my $appletName = $self->appletName; @@ -169,12 +175,12 @@ > <input type="button" value="$setConfig" onClick="debugText=''; - ww_applet_list['$appletName'].config(); + ww_applet_list['$appletName'].setConfig(); alert(debugText);" > !; - my $state_input_element = ($self->debug == 1) ? $debug_input_element : + my $state_input_element = ($debugMode) ? $debug_input_element : qq!\n<input type="hidden" name = "$appletStateName" value ="$base_64_encoded_answer_value">!; my $reset_button_str = ($reset_button) ? qq!<br/><input type='button' value='set applet state to restart' onClick="setAppletStateToRestart('$appletName')"> @@ -183,10 +189,6 @@ ; # always base64 encode the hidden answer value to prevent problems with quotes. # - $state_storage_html_code = - $reset_button_str. - $state_input_element. - qq!<input type="hidden" name="previous_$appletStateName" value = "$base_64_encoded_answer_value">!; $state_storage_html_code = qq!<input type="hidden" name="previous_$appletStateName" value = "$base_64_encoded_answer_value">! . $reset_button_str . $state_input_element @@ -195,11 +197,13 @@ <input type="button" value="get Answer from applet" onClick="eval(ww_applet_list['$appletName'].submitActionScript )"/> <br/> !; - $answerBox_code = ($self->debug == 1) ? $answerBox_code : ""; + $answerBox_code = ($debugMode) ? $answerBox_code : q!<input type="hidden" name="answerBox" value="" size =50>!; ####### # insert header material ####### main::HEADER_TEXT($self->insertHeader()); + # update the debug mode for this applet. + main::HEADER_TEXT(qq!<script> ww_applet_list["$appletName"].debugMode = $debugMode;\n</script>!); return main::MODES(TeX=>' {\bf applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code.$answerBox_code); } |
From: Mike G. v. a. <we...@ma...> - 2009-03-10 21:09:33
|
Log Message: ----------- Fixed an extra paren that was causing problems. Modified Files: -------------- pg/lib: Applet.pm Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.19 retrieving revision 1.20 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.19 -r1.20 --- lib/Applet.pm +++ lib/Applet.pm @@ -284,7 +284,7 @@ }; bless $self, $class; $self->initialState('<xml></xml>'); - if ($self->{returnFieldName}) or $self->{answerBox} ) { # backward compatibility + if ($self->{returnFieldName} or $self->{answerBox} ) { # backward compatibility warn "use answerBoxAlias instead of returnFieldName or answerBox"; $self->{answerBox}=''; $self->{returnFieldName}=''; |
From: Mike G. v. a. <we...@ma...> - 2009-03-10 21:00:20
|
Log Message: ----------- finish the conversion to setConfigAlias from configAlias Modified Files: -------------- webwork2/htdocs/js: ww_applet_support.js Revision Data ------------- Index: ww_applet_support.js =================================================================== RCS file: /webwork/cvs/system/webwork2/htdocs/js/ww_applet_support.js,v retrieving revision 1.7 retrieving revision 1.8 diff -Lhtdocs/js/ww_applet_support.js -Lhtdocs/js/ww_applet_support.js -u -r1.7 -r1.8 --- htdocs/js/ww_applet_support.js +++ htdocs/js/ww_applet_support.js @@ -252,14 +252,14 @@ var appletName = this.appletName; var applet = getApplet(appletName); - var configAlias = this.configAlias; - debug_add(" Calling " + appletName +"."+ configAlias +"( " + Base64.decode(this.base64_config) + " ) " ); + var setConfigAlias = this.setConfigAlias; + debug_add(" Calling " + appletName +"."+ setConfigAlias +"( " + Base64.decode(this.base64_config) + " ) " ); try { - if ( this.methodDefined(configAlias) ) { - applet[configAlias](Base64.decode(this.base64_config)); + if ( this.methodDefined(setConfigAlias) ) { + applet[setConfigAlias](Base64.decode(this.base64_config)); } } catch(e) { - var msg = "Error in configuring " + appletName + " using command " + configAlias + " : " + e ; + var msg = "Error in configuring " + appletName + " using command " + setConfigAlias + " : " + e ; alert(msg); } }; |
From: Mike G. v. a. <we...@ma...> - 2009-03-10 20:59:26
|
Log Message: ----------- complete the conversion from configAlias to setConfigAlias Modified Files: -------------- pg/lib: Applet.pm Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.18 retrieving revision 1.19 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.18 -r1.19 --- lib/Applet.pm +++ lib/Applet.pm @@ -268,13 +268,15 @@ initialState => '', # initial state. (I'm considering storing everything as ascii and converting on the fly to base64 when needed.) getStateAlias => 'getXML', setStateAlias => 'setXML', - configAlias => '', + configAlias => '', # deprecated getConfigAlias => 'getConfig', setConfigAlias => 'setConfig', initializeActionAlias => 'setXML', submitActionAlias => 'getXML', - submitActionScript => '', # script executed on submitting the WW question - answerBox => 'answerBox', + submitActionScript => '', # script executed on submitting the WW question + answerBoxAlias => 'answerBox', + answerBox => '', # deprecated + returnFieldName => '', # deprecated headerText => DEFAULT_HEADER_TEXT(), objectText => '', debug => 0, @@ -282,6 +284,11 @@ }; bless $self, $class; $self->initialState('<xml></xml>'); + if ($self->{returnFieldName}) or $self->{answerBox} ) { # backward compatibility + warn "use answerBoxAlias instead of returnFieldName or answerBox"; + $self->{answerBox}=''; + $self->{returnFieldName}=''; + } if ($self->{configAlias}) { # backward compatibility warn "use setConfigAlias instead of configAlias"; $self->{configAlias}=''; |
From: dpvc v. a. <we...@ma...> - 2009-03-10 14:19:23
|
Log Message: ----------- Fix the context::Fraction::Real object so that new() and make() will handle being passed a fraction as a string (since Value::makeValue() will pass that to context::Fraction::Real->make() when it is given a fraction as a string). Modified Files: -------------- pg/macros: contextFraction.pl Revision Data ------------- Index: contextFraction.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextFraction.pl,v retrieving revision 1.3 retrieving revision 1.4 diff -Lmacros/contextFraction.pl -Lmacros/contextFraction.pl -u -r1.3 -r1.4 --- macros/contextFraction.pl +++ macros/contextFraction.pl @@ -499,12 +499,25 @@ # Allow Real to convert Fractions to Reals # sub new { - my $self = shift; my $class = ref($self) || $self; - my $context = (Value::isContext($_[0]) ? shift : $self->context); - my $x = shift; $x = $x->eval if scalar(@_) == 0 && Value::classMatch($x,'Fraction'); + my $self = shift; my $context = (Value::isContext($_[0]) ? shift : $self->context); + my $x = shift; + $x = $context->Package("Formula")->new($context,$x)->eval if ref($x) eq "" && $x =~ m!/!; + $x = $x->eval if scalar(@_) == 0 && Value::classMatch($x,'Fraction'); $self->SUPER::new($context,$x,@_); } +# +# Since the signed number pattern now include fractions, we need to make sure +# we handle them when a real is made and it looks like a fraction +# +sub make { + my $self = shift; my $context = (Value::isContext($_[0]) ? shift : $self->context); + my $x = shift; + $x = $context->Package("Formula")->new($context,$x)->eval if ref($x) eq "" && $x =~ m!/!; + $x = $x->eval if scalar(@_) == 0 && Value::classMatch($x,'Fraction'); + $self->SUPER::make($context,$x,@_); +} + ########################################################################### ########################################################################### # |
From: Mike G. v. a. <we...@ma...> - 2009-03-10 12:21:29
|
Log Message: ----------- replaced configAlias by setConfigAlias receivedFieldName replaced by answerBoxName Modified Files: -------------- pg/lib: Applet.pm Revision Data ------------- Index: Applet.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Applet.pm,v retrieving revision 1.17 retrieving revision 1.18 diff -Llib/Applet.pm -Llib/Applet.pm -u -r1.17 -r1.18 --- lib/Applet.pm +++ lib/Applet.pm @@ -110,7 +110,7 @@ submitAction() -- calls the submit action of the applets - initializeWWquestion() -- calls the initialize action of the applets + initializeWWquestion() -- calls the initialize action of the applets getQE(name) -- gets an HTML element of the question by name or by id. Be sure to keep all names and ids @@ -126,7 +126,10 @@ TEXT(qq!<script> listQuestionElements() </script>!); ENDDOCUMENT(); to obtain a list of all of the HTML elements in the question - + + ---------------------------------------------------------------------------- + + List of accessor methods made available by the FlashApplet class: Usage: $current_value = $applet->method(new_value or empty) These can also be set when creating the class -- for exampe: @@ -160,13 +163,17 @@ it is usually stored in base64 encoded format. base64_config base64 encode version of the contents of config - configAlias (default: config ) names the applet command called with the contents of $self->config + configAlias (default: setConfig ) names the applet command called with the contents of $self->config to configure the applet. The parameters are passed to the applet in plain text using <xml> The outer tags must be <xml> ..... </xml> - state state consists of those customizable attributes of the applet which change - as the applet is used. It is stored by the calling .pg question so that - when revisiting the question the applet - will be restored to the same state it was left in when the question was last + setConfigAlias (default: setConfig) -- a synonym for configAlias + getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used + mainly for debugging. In principal the configuration remains the same for a given instance + of the applet -- i.e. for the homework question for a single student. The state however + will change depending on the interactions between the student and the applet. + initialState the state consists of those customizable attributes of the applet which change + as the applet is used by the student. It is stored by the calling .pg question so that + when revisiting the question the applet will be restored to the same state it was left in when the question was last viewed. getStateAlias (default: getState) alias for command called to read the current state of the applet. @@ -186,9 +193,64 @@ =cut +=head4 More details + +There are three different "images" of the applet. The first is the java or flash applet itself. The object that actually does the work. +The second is a perl image of the applet -- henceforth the perlApplet -- which is configured in the .pg file and allows a WeBWorK question +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 +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 +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 +the PG rendering process. + +The perlApplet is initialized by $newApplet = new flashApplet( appletName=>'myApplet',..... ); The jsApplet is automatically defined in +ww_applet_list["myApplet"] by copying the instance variables of $newApplet to a corresponding javaScript object. So $newApplet->{appletName} +corresponds to ww_applet_list["myApplet"].appletName. (This paragraph is not yet fully implemented :-(). + +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 +to a base64 constant and then converted back to text form when it is read by an javaScript subroutine. + +=cut + +=head4 Requirements for applets + +The following methods are desirable in an applet that preserves state in a WW question. None of them are required. + setState(str) (default: setXML) + -- set the current state of the applet from an xml string + -- should be able to accept an empty string or a string of + the form <XML>.....</XML> without creating errors + -- can be designed to receive other forms of input if it is + coordinated with the WW question. + getState() (default: getXML) + -- return the current state of the applet in an xml string. + -- an empty string or a string of the form <XML>.....</XML> + are the standard responses. + -- can be designed to return other strings if it is + coordinated with the WW question. + setConfig(str) (default: setConfig) + -- If the applet allows configuration this configures the applet + from an xml string + -- should be able to accept an empty string or a string of the + form <XML>.....</XML> without creating errors + -- can be designed to receive other forms of input if it is + coordinated with the WW question. + getConfig (default: getConfig) + -- This returns a string defining the configuration of the + applet in an xml string + -- an empty string or a string of the form <XML>.....</XML> + are the standard responses. + -- can be designed to return other strings if it is + coordinated with the WW question. + -- this method is used for debugging to ensure that + the configuration was set as expected. + getAnswer (default: getAnswer) + -- Returns a string (usually NOT xml) which is the + response that the student is submitting to answer + the WW question. +=cut + sub new { my $class = shift; my $self = { @@ -200,11 +262,15 @@ width => 550, height => 400, bgcolor => "#869ca7", - base64_state => undef, # this is an state to use for initializing the first occurence of the question. + base64_state => undef, # this is a state to use for initializing the first occurence of the question. base64_config => undef, # this is the initial (and final?) configuration +# configuration => '', # configuration defining the applet + initialState => '', # initial state. (I'm considering storing everything as ascii and converting on the fly to base64 when needed.) getStateAlias => 'getXML', setStateAlias => 'setXML', - configAlias => 'config', + configAlias => '', + getConfigAlias => 'getConfig', + setConfigAlias => 'setConfig', initializeActionAlias => 'setXML', submitActionAlias => 'getXML', submitActionScript => '', # script executed on submitting the WW question @@ -215,7 +281,11 @@ @_, }; bless $self, $class; - $self->state('<xml></xml>'); + $self->initialState('<xml></xml>'); + if ($self->{configAlias}) { # backward compatibility + warn "use setConfigAlias instead of configAlias"; + $self->{configAlias}=''; + } $self->config('<xml></xml>'); return $self; } @@ -279,15 +349,21 @@ } sub configAlias { my $self = shift; - $self->{configAlias} = shift ||$self->{configAlias}; # replace the current contents if non-empty - $self->{configAlias}; + $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty + $self->{setConfigAlias}; } -sub returnFieldName { +sub setConfigAlias { my $self = shift; - $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty - $self->{answerBox}; + $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty + $self->{setConfigAlias}; } -sub answerBox { +sub getConfigAlias { + my $self = shift; + $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty + $self->{getConfigAlias}; +} + +sub answerBoxName { my $self = shift; $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty $self->{answerBox}; @@ -336,6 +412,24 @@ sub appletId { appletName(@_); } + +sub initialState { + my $self = shift; + my $str = shift; + $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty + $self->{initialState}; +} + +sub config { + my $self = shift; + my $str = shift; + $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty + $self->{base64_config} =~ s/\n//g; + decode_base64($self->{base64_config}); +} +####################### +# soon to be deprecated? +####################### sub state { my $self = shift; my $str = shift; @@ -343,25 +437,28 @@ $self->{base64_state} =~ s/\n//g; decode_base64($self->{base64_state}); } - sub base64_state{ my $self = shift; $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty $self->{base64_state}; } -sub config { - my $self = shift; - my $str = shift; - $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty - $self->{base64_config} =~ s/\n//g; - decode_base64($self->{base64_config}); -} + sub base64_config { my $self = shift; $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty $self->{base64_config} =$self->{base64_config}; $self->{base64_config}; } + +sub returnFieldName { + my $self = shift; + warn "use answerBoxName instead of returnFieldName"; +} +sub answerBox { + my $self = shift; + warn "use answerBoxName instead of AnswerBox"; +} +######################### #FIXME # need to be able to adjust header material @@ -377,7 +474,9 @@ my $submitActionScript = $self->submitActionScript; my $setStateAlias = $self->setStateAlias; my $getStateAlias = $self->getStateAlias; - my $configAlias = $self->configAlias; + + my $setConfigAlias = $self->setConfigAlias; + my $getConfigAlias = $self->getConfigAlias; my $base64_config = $self->base64_config; my $debugMode = ($self->debug) ? "1": "0"; my $returnFieldName = $self->{returnFieldName}; @@ -441,6 +540,7 @@ </script> <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> //upload functions stored in /opt/webwork/webwork2/htdocs/js ... + </script> <script language="JavaScript"> @@ -463,7 +563,8 @@ ww_applet_list["$appletName"].base64_config = "$base64_config"; ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; - ww_applet_list["$appletName"].configAlias = "$configAlias"; + ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; + ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; ww_applet_list["$appletName"].initializeActionAlias = "$initializeAction"; ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; ww_applet_list["$appletName"].submitActionScript = "$submitActionScript"; |
From: Mike G. v. a. <we...@ma...> - 2009-03-10 12:20:07
|
Log Message: ----------- Added some comments about how to replace this functionality by using Contexts. Modified Files: -------------- pg/macros: PGasu.pl Revision Data ------------- Index: PGasu.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/PGasu.pl,v retrieving revision 1.8 retrieving revision 1.9 diff -Lmacros/PGasu.pl -Lmacros/PGasu.pl -u -r1.8 -r1.9 --- macros/PGasu.pl +++ macros/PGasu.pl @@ -118,6 +118,11 @@ This is useful if you want students to report the value of sin(pi/4), but you don't want to allow "sin(pi/4)" as the answer. +A similar effect can be accomplished with Contexts() by undefining +the trig functions. +See http://webwork.maa.org/wiki/Modifying_contexts_%28advanced%29#.282.29_Functions + + =cut # ^function no_trig_fun @@ -203,6 +208,10 @@ Second argument is optional, and tells us whether yes or no Third argument is the error message to produce (if any). +A similar effect can be accomplished with Contexts() by undefining +the trig functions. +See http://webwork.maa.org/wiki/Modifying_contexts_%28advanced%29 + =cut |