Permalink
Browse files

Adding in my initial prototype.

  • Loading branch information...
0 parents commit b40264c4ca9c1f739cd8094b2136f72efdda12ac @jeresig jeresig committed May 9, 2011
Showing with 398 additions and 0 deletions.
  1. +15 −0 khan-exercise.css
  2. +231 −0 khan-exercise.js
  3. +85 −0 rate_problems_1.html
  4. +67 −0 writing_expressions_1.html
@@ -0,0 +1,15 @@
+html, body { font-family: Helvetica, Arial; }
+#vars, #problems, #hints, #next, #congrats, #oops { display: none; }
+p.question { font-weight: bold; }
+var { font-style: normal; }
+.hint_blue { color: blue; }
+.hint_orange { color: orange; }
+#congrats { color: green; }
+#oops { color: red; }
+#workarea { margin-left: 10px; }
+#hintsarea { margin-left: 30px; }
+#sidebar { float: right; }
+h1, form, #help { border: 1px solid #AAA; background: #F0F0F0; padding: 10px; margin: 10px; }
+form, #help { width: 250px; }
+h3 { color: #666; margin: 0; font-weight: normal; }
+code { font-family: Helvetica, Arial; }
@@ -0,0 +1,231 @@
+jQuery(function() {
+ // Inject the site markup, if it doesn't exist
+ injectSite();
+
+ // Generate the initial problem
+ makeProblem();
+
+ // Watch for a solution submission
+ jQuery("form").submit(function() {
+ // Get the solution to the problem
+ var solution = jQuery("#workarea").children().data("solution"),
+
+ // We get the answer differently if it's a text input or a radio
+ answer = jQuery("#solution").is("div") ?
+ jQuery("#solution input:checked").val() :
+ jQuery("#solution").val();
+
+ // Verify the solution
+ if ( answer === solution ) {
+ // Show a congratulations message
+ jQuery("#congrats").show().delay( 1000 ).fadeOut( 2000 );
+
+ // Toggle the navigation buttons
+ jQuery("#check").hide();
+ jQuery("#next").show();
+
+ // Otherwise show an error message
+ } else {
+ jQuery("#oops").show().delay( 1000 ).fadeOut( 2000 );
+ }
+
+ return false;
+ });
+
+ // Watch for when the next button is clicked
+ jQuery("#next").click(function() {
+ // Erase the old value
+ jQuery("#solution").val( "" );
+
+ // Toggle the navigation buttons
+ jQuery("#check").show();
+ jQuery("#next").hide();
+
+ // Wipe out any previous problem
+ jQuery("#workarea, #hintsarea").empty();
+
+ // Generate a new problem
+ makeProblem();
+
+ return false;
+ });
+
+ // Watch for when the "Get a Hint" button is clicked
+ jQuery("#gethint").click(function() {
+ // Show the first not shown hint
+ jQuery("#shown-hints > *:hidden:first").show();
+ });
+
+ // TODO: Loop through the <code> examples and convert them to nice math
+});
+
+function makeProblem() {
+ // Load all the variables from the page
+ jQuery("#vars").children().loadVAR();
+
+ // Get the problem we'll be using
+ var problem = jQuery("#problems").children().getRandom().clone();
+
+ // See if there's an original problem that we're inheriting from
+ if ( problem.data("type") ) {
+ // Clone it for manipulation
+ var original = jQuery("#" + problem.data("type")).clone();
+
+ // Go through the components of the sub-problem
+ problem.children().each(function() {
+ // Remove those parts from the original
+ original.children( "." + this.className ).remove();
+ // And add our new ones in, instead
+ original.append( problem );
+ });
+
+ problem = original;
+ }
+
+ // Replace all the variables with their values
+ problem.find("var").replaceVAR();
+
+ // Store the solution to the problem
+ problem.data( "solution", problem.find(".solution").remove().text() );
+
+ var choices = problem.find(".choices").remove();
+
+ if ( choices.length ) {
+ var radios = [],
+ // Figure out how many choices to show
+ num = parseFloat( choices.data("show") );
+
+ // Go through the possible wrong answers
+ var possible = choices.children().get();
+
+ // Figure out the solution to display
+ // If "none" is a possibility, make it a correct answer sometimes
+ if ( choices.data("none") ) {
+ radios.push( "None of the above." );
+
+ // The right answer is injected most of the time
+ if ( Math.random() > 1 / num ) {
+ radios.push( problem.data("solution") );
+
+ // But sometimes "None of the above." is the right answer
+ } else {
+ problem.data( "solution", "None of the above." );
+ }
+ }
+
+ // And add them in in a random order
+ while ( radios.length < num ) {
+ var item = possible.splice( Math.floor( possible.length * Math.random() ), 1 )[0];
+ radios.splice( Math.floor( radios.length * Math.random() ), 0, item );
+ }
+
+ jQuery("#solution").replaceWith( "<div id='solution'>" +
+ jQuery.map( radios, function( value ) {
+ value = value && value.nodeType ? jQuery(value).text() : value;
+ return "<input type='radio' name='solution' value='" + value + "'/> " + value + "<br/>";
+ }).join("") +
+ "</div>" );
+ }
+
+ // Add the problem into the page
+ jQuery("#workarea").append( problem );
+
+ // Clone the hints and add them into their area
+ var hints = jQuery("#hints").clone();
+
+ // Extract any problem-specific hints
+ problem.find(".hint").remove().children().each(function() {
+ // Replace the hint placeholders
+ hints.find("." + this.className).replaceWith( this );
+ });
+
+ hints
+ // Be sure to replace the vars with the correct values
+ .find("var").replaceVAR().end()
+
+ // Hide all the hints
+ .children().hide().end()
+
+ // And give it a new ID
+ .attr("id", "shown-hints")
+
+ // Add it in to the page
+ .appendTo("#hintsarea");
+}
+
+// Pick a random element from a set of elements
+jQuery.fn.getRandom = function() {
+ return this.eq( Math.floor( this.length * Math.random() ) );
+};
+
+(function() {
+ var VARS = {};
+
+ // Load the value associated with the variable
+ jQuery.fn.loadVAR = function() {
+ return this.each(function() {
+ VARS[ this.id ] = getVAR( this );
+ });
+ };
+
+ jQuery.fn.replaceVAR = function() {
+ return this.text( getVAR );
+ };
+
+ function getVAR( elem, text ) {
+ // If it's a list, grab a random one out of it
+ if ( elem.nodeName && elem.nodeName.toLowerCase() === "ul" ) {
+ return jQuery( elem ).children().getRandom().text();
+
+ // Otherwise we need to compute the value
+ } else {
+ var text = (elem.nodeName ? jQuery(elem).text() : text);
+
+ try {
+ // Use the methods provided by the library
+ with ( Util ) {
+ // And the methods from JavaScript's builtin Math methods
+ with ( Math ) {
+ // Use all the computed variables
+ with ( VARS ) {
+ return eval( "(" + text + ")" );
+ }
+ }
+ }
+ } catch( e ) {
+ if ( typeof console !== "undefined" ) {
+ console.error( text, e );
+ }
+ }
+ }
+ }
+
+ var Util = {
+ // A simple random number picker
+ rand: function( num ) {
+ return Math.round( num * Math.random() );
+ }
+ };
+})();
+
+function injectSite() {
+ jQuery("body").prepend(
+ '<h1>' + document.title + '</h1>' +
+ '<div id="sidebar">' +
+ '<form action="">' +
+ '<h3>Answer</h3>' +
+ '<br/><input type="text" id="solution"/>' +
+ '<input type="submit" id="check" value="Check Answer"/>' +
+ '<br/><input type="button" id="next" value="Next Problem"/>' +
+ '<p id="congrats">Congratulations! That answer is correct.</p>' +
+ '<p id="oops">Oops! That answer is not correct, please try again.</p>' +
+ '</form>' +
+ '<div id="help">' +
+ '<h3>Need Help?</h3>' +
+ '<br/><input type="button" id="gethint" value="Get a Hint"/>' +
+ '</div>' +
+ '</div>' +
+ '<div id="workarea"></div>' +
+ '<div id="hintsarea"></div>'
+ );
+}
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Rate Problems 1</title>
+ <!--
+ Original by Marcia Lee:
+ http://code.google.com/p/khanacademy/source/browse/trunk/javascript/exercises/rate_problems_1.js
+ -->
+ <link rel="stylesheet" href="khan-exercise.css"/>
+ <script src="http://code.jquery.com/jquery.js"></script>
+ <script src="khan-exercise.js"></script>
+</head>
+<body>
+ <div id="vars">
+ <var id="SPEED1">11 + rand(9)</var>
+ <var id="SPEED2">41 + rand(9)</var>
+ <var id="AVG">31 + rand(9)</var>
+ <var id="TIME">1 + rand(9)</var>
+ <var id="DIST">AVG * TIME</var>
+ <var id="DIST2">(SPEED1 * SPEED2 * TIME - DIST * SPEED2) / (SPEED1 - SPEED2)</var>
+ <var id="DIST1">DIST - DIST2</var>
+ <ul id="VEHICLE1">
+ <li>bike</li>
+ <li>bus</li>
+ <li>camel</li>
+ <li>elephant</li>
+ </ul>
+ <ul id="VEHICLE2">
+ <li>horse</li>
+ <li>moped</li>
+ <li>scooter</li>
+ <li>train</li>
+ </ul>
+ <var id="V1">VEHICLE1[0]</var>
+ <var id="V2">VEHICLE2[0]</var>
+ </div>
+
+ <div id="problems">
+ <div id="original" class="problem">
+ <div class="problem">
+ <p>Alice traveled by <var>VEHICLE1</var> at an average speed of <var>SPEED1</var> miles per hour.</p>
+ <p>Then, she traveled by <var>VEHICLE2</var> at an average speed of <var>SPEED2</var> miles per hour.</p>
+ <p>In total, she traveled <var>DIST</var> miles for <var>TIME</var> hour<var>TIME > 1 ? "s" : ""</var>.</p>
+ </div>
+ <p class="question">How many miles did Alice travel by <var>VEHICLE1</var>? (Round to the nearest mile.)</p>
+ <p class="solution"><var>round(DIST1)</var></p>
+ </div>
+ <div class="problem" data-type="original">
+ <p class="question">How many miles did Alice travel by <var>VEHICLE2</var>? (Round to the nearest mile.)</p>
+ <p class="solution"><var>round(DIST2)</var></p>
+ </div>
+ <div class="problem" data-type="original">
+ <p class="question">How many minutes did Alice travel by <var>VEHICLE1</var>? (Round to the nearest minute.)</p>
+ <p class="solution"><var>round(DIST1 / SPEED1 * 60)</var></p>
+ </div>
+ <div class="problem" data-type="original">
+ <p class="question">How many minutes did Alice travel by <var>VEHICLE2</var>? (Round to the nearest minute.)</p>
+ <p class="solution"><var>round(DIST2 / SPEED2 * 60)</var></p>
+ </div>
+ </div>
+
+ <div id="hints">
+ <p>Remember that <code>d = r * t</code>, or written another way, <code>t = d / r</code></p>
+ <div>
+ <p><code>d_<var>V1</var> =</code> distance that Alice traveled by <var>VEHICLE1</var></p>
+ <p><code>d_<var>V2</var> =</code> distance that Alice traveled by <var>VEHICLE2</var></p>
+ <p>Total distance: <code class="hint_orange">d_<var>V1</var> + d_<var>V2</var> = <var>DIST</var></code></p>
+ </div>
+ <p>Total time: <code class="hint_blue">t_<var>V1</var> + t_<var>V2</var> = <var>TIME</var></code></p>
+ <p><code class="hint_blue">t_<var>V1</var> = (d_<var>V1</var> / <var>SPEED1</var>)</code> and
+ <code class="hint_blue">t_<var>V2</var> = (d_<var>V2</var> / <var>SPEED2</var>)</code></p>
+ <p>Substitute the blue equations for:
+ <code>(d_<var>V1</var> / <var>SPEED1</var>) + (d_<var>V2</var> / <var>SPEED2</var>) = <var>TIME</var></code></p>
+ <p>Multiply the above equation by <var>-1 * SPEED1</var>:
+ <code class="hint_orange">-d_<var>V1</var> - (<var>SPEED1</var> / <var>SPEED2</var>) * d_<var>V2</var> = <var>-SPEED1 * TIME</var></code></p>
+ <p>Add the two orange equations for:
+ <code>(<var>SPEED2 - SPEED1</var> / <var>SPEED2</var>) * d_<var>V2</var> = <var>DIST - (SPEED1 * TIME)</var></code></p>
+ <p>Simplify and round to the nearest integer:
+ <code>d_<var>V2</var> = <var>round(DIST2)</var></code> miles
+ <code>d_<var>V1</var> = <var>round(DIST1)</var></code> miles
+ <code>t_<var>V1</var> = <var>round(DIST1 / SPEED1 * 60)</var></code> minutes
+ <code>t_<var>V2</var> = <var>round(DIST2 / SPEED2 * 60)</var></code> minutes</p>
+ </div>
+</body>
+</html>
Oops, something went wrong.

0 comments on commit b40264c

Please sign in to comment.