From 7c74d798add699bd618d262ac5b6653ac6b26a85 Mon Sep 17 00:00:00 2001 From: Kyle Fiedler Date: Thu, 3 May 2012 16:14:47 -0400 Subject: [PATCH 01/25] Styles for new layout to the amplifier --- static/css/application.css | 243 +++++++++++----------- templates/sass/courseware/_amplifier.scss | 90 ++++---- 2 files changed, 177 insertions(+), 156 deletions(-) diff --git a/static/css/application.css b/static/css/application.css index 4d3d26e40c..cf8d6f3ebe 100644 --- a/static/css/application.css +++ b/static/css/application.css @@ -117,7 +117,7 @@ input, select { font-weight: 800; font-style: italic; } -.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.wiki-wrapper section.wiki-body header:after, html body section.main-content:after, html body section.outside-app:after, div.header-wrapper header:after, div.header-wrapper header hgroup:after, div.header-wrapper header nav ul:after, footer:after, li.calc-main div#calculator_wrapper form:after, li.calc-main div#calculator_wrapper form div.input-wrapper:after, div.leanModal_box#enroll ol:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls div#slider:after, section.course-content nav.sequence-bottom ul:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls:after, div.book-wrapper section.book nav ul:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.profile-wrapper section.course-info header:after, div.profile-wrapper section.course-info > ol > li:after, div#wiki_panel div#wiki_create_form:after, div.wiki-wrapper section.wiki-body:after, ul.badge-list li.badge:after { +.clearfix:after, .topbar:after, nav.sequence-nav:after, div.book-wrapper section.book nav:after, div.wiki-wrapper section.wiki-body header:after, html body section.main-content:after, html body section.outside-app:after, div.header-wrapper header:after, div.header-wrapper header hgroup:after, div.header-wrapper header nav ul:after, footer:after, li.calc-main div#calculator_wrapper form:after, li.calc-main div#calculator_wrapper form div.input-wrapper:after, div.leanModal_box#enroll ol:after, div.course-wrapper section.course-content .problem-set:after, div.course-wrapper section.course-content section.problems-wrapper:after, div.course-wrapper section.course-content div#seq_content:after, div.course-wrapper section.course-content ol.vert-mod > li:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls:after, section.course-content div.video-subtitles div.video-wrapper section.video-controls div#slider:after, section.course-content nav.sequence-bottom ul:after, section.tool-wrapper:after, section.tool-wrapper div#controlls-container:after, section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper:after, section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders:after, div.book-wrapper section.book nav ul:after, div.info-wrapper section.updates > ol > li:after, div.info-wrapper section.handouts ol li:after, div.profile-wrapper section.course-info header:after, div.profile-wrapper section.course-info > ol > li:after, div#wiki_panel div#wiki_create_form:after, div.wiki-wrapper section.wiki-body:after, ul.badge-list li.badge:after { content: "."; display: block; height: 0; @@ -3908,30 +3908,125 @@ section.tool-wrapper div#controlls-container { padding: 22.652px; vertical-align: top; width: 48.641%; } -section.tool-wrapper div#controlls-container div.graph-controls { +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper { padding: 0 0 22.652px; margin-bottom: 22.652px; - border-bottom: 1px solid #05232b; + border-bottom: 1px solid #021014; -webkit-box-shadow: 0 1px 0 #083e4b; -moz-box-shadow: 0 1px 0 #083e4b; box-shadow: 0 1px 0 #083e4b; } -section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper { - margin-right: 5.587%; - width: 29.609%; - float: left; } -section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper { - padding-top: 11.326px; - width: 64.804%; - float: left; } -section.tool-wrapper div#controlls-container div.graph-controls select#musicTypeSelect { +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton { + display: block; + border: 1px solid #3d5962; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 0 #939da0; + -moz-box-shadow: inset 0 1px 0 0 #939da0; + box-shadow: inset 0 1px 0 0 #939da0; + color: white; + display: inline; + font-size: 11px; + font-weight: bold; + background-color: #637c84; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #637c84), color-stop(100%, #43626b)); + background-image: -webkit-linear-gradient(top, #637c84, #43626b); + background-image: -moz-linear-gradient(top, #637c84, #43626b); + background-image: -ms-linear-gradient(top, #637c84, #43626b); + background-image: -o-linear-gradient(top, #637c84, #43626b); + background-image: linear-gradient(top, #637c84, #43626b); + padding: 6px 18px 7px; + text-shadow: 0 1px 0 #31505a; + -webkit-background-clip: padding-box; + font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; + float: left; } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:hover { + -webkit-box-shadow: inset 0 1px 0 0 #778589; + -moz-box-shadow: inset 0 1px 0 0 #778589; + box-shadow: inset 0 1px 0 0 #778589; + cursor: pointer; + background-color: #5c6c71; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5c6c71), color-stop(100%, #3e5961)); + background-image: -webkit-linear-gradient(top, #5c6c71, #3e5961); + background-image: -moz-linear-gradient(top, #5c6c71, #3e5961); + background-image: -ms-linear-gradient(top, #5c6c71, #3e5961); + background-image: -o-linear-gradient(top, #5c6c71, #3e5961); + background-image: linear-gradient(top, #5c6c71, #3e5961); } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:active { + border: 1px solid #3d5962; + -webkit-box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee; + -moz-box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee; + box-shadow: inset 0 0 8px 4px #395057, inset 0 0 8px 4px #395057, 0 1px 1px 0 #eeeeee; } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton:active { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"] { + border: 1px solid #030d15; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 0 #215f8a; + -moz-box-shadow: inset 0 1px 0 0 #215f8a; + box-shadow: inset 0 1px 0 0 #215f8a; + color: white; + display: inline; + font-size: 11px; + font-weight: bold; + background-color: #0f3550; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0f3550), color-stop(100%, #041623)); + background-image: -webkit-linear-gradient(top, #0f3550, #041623); + background-image: -moz-linear-gradient(top, #0f3550, #041623); + background-image: -ms-linear-gradient(top, #0f3550, #041623); + background-image: -o-linear-gradient(top, #0f3550, #041623); + background-image: linear-gradient(top, #0f3550, #041623); + padding: 6px 18px 7px; + text-shadow: 0 1px 0 #000203; + -webkit-background-clip: padding-box; + font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:hover { + -webkit-box-shadow: inset 0 1px 0 0 #174362; + -moz-box-shadow: inset 0 1px 0 0 #174362; + box-shadow: inset 0 1px 0 0 #174362; + cursor: pointer; + background-color: #0c2739; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0c2739), color-stop(100%, #030d15)); + background-image: -webkit-linear-gradient(top, #0c2739, #030d15); + background-image: -moz-linear-gradient(top, #0c2739, #030d15); + background-image: -ms-linear-gradient(top, #0c2739, #030d15); + background-image: -o-linear-gradient(top, #0c2739, #030d15); + background-image: linear-gradient(top, #0c2739, #030d15); } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:active { + border: 1px solid #030d15; + -webkit-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; + -moz-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; + box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; } +section.tool-wrapper div#controlls-container div.graph-controls div.music-wrapper input#playButton[value="Stop"]:active { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; } +section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper { + zoom: 1; + margin-bottom: 22.652px; } +section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:before, section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after { + content: ""; + display: table; } +section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper:after { + clear: both; } +section.tool-wrapper div#controlls-container div.graph-controls div.inputs-wrapper select#musicTypeSelect { display: block; - margin-bottom: 11.326px; font: 16px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - width: 100%; } + float: right; + margin-bottom: 0; } section.tool-wrapper div#controlls-container div.graph-controls div#graph-output, section.tool-wrapper div#controlls-container div.graph-controls div#graph-listen { display: block; - margin-bottom: 11.326px; - text-align: right; } + text-align: right; + float: left; + margin-bottom: 0; } section.tool-wrapper div#controlls-container div.graph-controls div#graph-output p, section.tool-wrapper div#controlls-container div.graph-controls div#graph-listen p { display: -moz-inline-box; -moz-box-orient: vertical; @@ -3961,104 +4056,9 @@ section.tool-wrapper div#controlls-container div.graph-controls div#graph-output margin-bottom: 0; } section.tool-wrapper div#controlls-container div.graph-controls div#graph-output ul li input, section.tool-wrapper div#controlls-container div.graph-controls div#graph-listen ul li input { margin-right: 5px; } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton { - display: block; - border: 1px solid #b01613; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - -ms-border-radius: 3px; - -o-border-radius: 3px; - border-radius: 3px; - -webkit-box-shadow: inset 0 1px 0 0 #e07977; - -moz-box-shadow: inset 0 1px 0 0 #e07977; - box-shadow: inset 0 1px 0 0 #e07977; - color: white; - display: inline; - font-size: 11px; - font-weight: bold; - background-color: #dc322f; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dc322f), color-stop(100%, #be1815)); - background-image: -webkit-linear-gradient(top, #dc322f, #be1815); - background-image: -moz-linear-gradient(top, #dc322f, #be1815); - background-image: -ms-linear-gradient(top, #dc322f, #be1815); - background-image: -o-linear-gradient(top, #dc322f, #be1815); - background-image: linear-gradient(top, #dc322f, #be1815); - padding: 6px 18px 7px; - text-shadow: 0 1px 0 #a30f0c; - -webkit-background-clip: padding-box; - font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; - color: #47221a; - text-shadow: 0 1px 0 #e04845; - -webkit-box-shadow: inset 0 1px 0 #e35d5b; - -moz-box-shadow: inset 0 1px 0 #e35d5b; - box-shadow: inset 0 1px 0 #e35d5b; } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton:hover { - -webkit-box-shadow: inset 0 1px 0 0 #d84f4c; - -moz-box-shadow: inset 0 1px 0 0 #d84f4c; - box-shadow: inset 0 1px 0 0 #d84f4c; - cursor: pointer; - background-color: #ca2a28; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ca2a28), color-stop(100%, #af1714)); - background-image: -webkit-linear-gradient(top, #ca2a28, #af1714); - background-image: -moz-linear-gradient(top, #ca2a28, #af1714); - background-image: -ms-linear-gradient(top, #ca2a28, #af1714); - background-image: -o-linear-gradient(top, #ca2a28, #af1714); - background-image: linear-gradient(top, #ca2a28, #af1714); } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton:active { - border: 1px solid #b01613; - -webkit-box-shadow: inset 0 0 8px 4px #a11614, inset 0 0 8px 4px #a11614, 0 1px 1px 0 #eeeeee; - -moz-box-shadow: inset 0 0 8px 4px #a11614, inset 0 0 8px 4px #a11614, 0 1px 1px 0 #eeeeee; - box-shadow: inset 0 0 8px 4px #a11614, inset 0 0 8px 4px #a11614, 0 1px 1px 0 #eeeeee; } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton:active { - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton[value="Stop"] { - border: 1px solid #030d15; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - -ms-border-radius: 3px; - -o-border-radius: 3px; - border-radius: 3px; - -webkit-box-shadow: inset 0 1px 0 0 #215f8a; - -moz-box-shadow: inset 0 1px 0 0 #215f8a; - box-shadow: inset 0 1px 0 0 #215f8a; - color: white; - display: inline; - font-size: 11px; - font-weight: bold; - background-color: #0f3550; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0f3550), color-stop(100%, #041623)); - background-image: -webkit-linear-gradient(top, #0f3550, #041623); - background-image: -moz-linear-gradient(top, #0f3550, #041623); - background-image: -ms-linear-gradient(top, #0f3550, #041623); - background-image: -o-linear-gradient(top, #0f3550, #041623); - background-image: linear-gradient(top, #0f3550, #041623); - padding: 6px 18px 7px; - text-shadow: 0 1px 0 #000203; - -webkit-background-clip: padding-box; - font: bold 14px "Open Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton[value="Stop"]:hover { - -webkit-box-shadow: inset 0 1px 0 0 #174362; - -moz-box-shadow: inset 0 1px 0 0 #174362; - box-shadow: inset 0 1px 0 0 #174362; - cursor: pointer; - background-color: #0c2739; - background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0c2739), color-stop(100%, #030d15)); - background-image: -webkit-linear-gradient(top, #0c2739, #030d15); - background-image: -moz-linear-gradient(top, #0c2739, #030d15); - background-image: -ms-linear-gradient(top, #0c2739, #030d15); - background-image: -o-linear-gradient(top, #0c2739, #030d15); - background-image: linear-gradient(top, #0c2739, #030d15); } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton[value="Stop"]:active { - border: 1px solid #030d15; - -webkit-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; - -moz-box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; - box-shadow: inset 0 0 8px 4px #010507, inset 0 0 8px 4px #010507, 0 1px 1px 0 #eeeeee; } -section.tool-wrapper div#controlls-container div.graph-controls input#playButton[value="Stop"]:active { - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; } +section.tool-wrapper div#controlls-container div.graph-controls div#graph-listen { + margin-top: 8px; + margin-right: 20px; } section.tool-wrapper div#controlls-container label { -webkit-border-radius: 2px; -moz-border-radius: 2px; @@ -4079,6 +4079,13 @@ section.tool-wrapper div#controlls-container label[for="vcCheckbox"], section.to color: #e1a600; } section.tool-wrapper div#controlls-container label[for="vlCheckbox"], section.tool-wrapper div#controlls-container label[for="vlRadioButton"] { color: #a26784; } +section.tool-wrapper div#controlls-container div.schematic-sliders div.top-sliders { + padding: 0 0 22.652px; + margin-bottom: 22.652px; + border-bottom: 1px solid #021014; + -webkit-box-shadow: 0 1px 0 #083e4b; + -moz-box-shadow: 0 1px 0 #083e4b; + box-shadow: 0 1px 0 #083e4b; } section.tool-wrapper div#controlls-container div.schematic-sliders div.slider-label { margin-bottom: 11.326px; font-weight: bold; @@ -4094,10 +4101,14 @@ section.tool-wrapper div#controlls-container div.schematic-sliders div.slider.ui -moz-box-shadow: none; box-shadow: none; } section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle { - background-color: #dc322f; + background: #637c84 url("/static/images/amplifier-slider-handle.png") center no-repeat; + border: 1px solid #000b0d; + -webkit-box-shadow: inset 0 1px 0 #8ba1a8; + -moz-box-shadow: inset 0 1px 0 #8ba1a8; + box-shadow: inset 0 1px 0 #8ba1a8; margin-top: -0.3em; } section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle:hover, section.tool-wrapper div#controlls-container div.schematic-sliders div.slider .ui-slider-handle:active { - background-color: #e04845; } + background-color: #6e8992; } div.book-wrapper section.book-sidebar { -webkit-box-sizing: border-box; diff --git a/templates/sass/courseware/_amplifier.scss b/templates/sass/courseware/_amplifier.scss index e515d49b22..69d87420d2 100644 --- a/templates/sass/courseware/_amplifier.scss +++ b/templates/sass/courseware/_amplifier.scss @@ -84,35 +84,52 @@ section.tool-wrapper { width: flex-grid(4.5, 9); div.graph-controls { - padding: 0 0 lh(); - margin-bottom: lh(); - border-bottom: 1px solid darken(#073642, 5%); - @include box-shadow(0 1px 0 lighten(#073642, 2%)); - @extend .clearfix; div.music-wrapper { - margin-right: flex-gutter(4.5); - width: flex-grid(1.5, 4.5); - float: left; + padding: 0 0 lh(); + margin-bottom: lh(); + border-bottom: 1px solid darken(#073642, 10%); + @include box-shadow(0 1px 0 lighten(#073642, 2%)); + @extend .clearfix; + + input#playButton { + display: block; + @include button(simple, lighten( #586e75, 5% )); + font: bold 14px $body-font-family; + float: left; + + &:active { + @include box-shadow(none); + } + + &[value="Stop"] { + @include button(simple, darken(#268bd2, 30%)); + font: bold 14px $body-font-family; + + &:active { + @include box-shadow(none); + } + } + } } div.inputs-wrapper { - padding-top: lh(.5); - width: flex-grid(3, 4.5); - float: left; - } + @include clearfix; + margin-bottom: lh(); - select#musicTypeSelect { - display: block; - margin-bottom: lh(.5); - font: 16px $body-font-family; - width: 100%; + select#musicTypeSelect { + display: block; + font: 16px $body-font-family; + float: right; + margin-bottom: 0; + } } div#graph-output, div#graph-listen { display: block; - margin-bottom: lh(.5); text-align: right; + float: left; + margin-bottom: 0; p { @include inline-block(); @@ -134,26 +151,9 @@ section.tool-wrapper { } } - input#playButton { - display: block; - @include button(simple, #dc322f); - font: bold 14px $body-font-family; - color: #47221a; - text-shadow: 0 1px 0 lighten(#dc322f, 5%); - @include box-shadow(inset 0 1px 0 lighten(#dc322f, 10%)); - - &:active { - @include box-shadow(none); - } - - &[value="Stop"] { - @include button(simple, darken(#268bd2, 30%)); - font: bold 14px $body-font-family; - - &:active { - @include box-shadow(none); - } - } + div#graph-listen { + margin-top: 8px; + margin-right: 20px; } } @@ -190,6 +190,14 @@ section.tool-wrapper { div.schematic-sliders { + div.top-sliders { + padding: 0 0 lh(); + margin-bottom: lh(); + border-bottom: 1px solid darken(#073642, 10%); + @include box-shadow(0 1px 0 lighten(#073642, 2%)); + @extend .clearfix; + } + div.slider-label { margin-bottom: lh(0.5); font-weight: bold; @@ -208,11 +216,13 @@ section.tool-wrapper { } .ui-slider-handle { - background-color: #dc322f; + background: lighten( #586e75, 5% ) url('/static/images/amplifier-slider-handle.png') center no-repeat; + border: 1px solid darken(#002b36, 8%); + @include box-shadow(inset 0 1px 0 lighten( #586e75, 20% )); margin-top: -.3em; &:hover, &:active { - background-color: lighten(#dc322f, 5%); + background-color: lighten( #586e75, 10% ); } } } From 752a62523796511b44e595514a6a966736806344 Mon Sep 17 00:00:00 2001 From: Bridger Maxwell Date: Tue, 17 Apr 2012 00:17:12 -0400 Subject: [PATCH 02/25] Added histogram graph for courseware administrators. --- djangoapps/courseware/module_render.py | 11 ++++++-- templates/courseware.html | 5 ++++ templates/staff_problem_histogram.js | 38 ++++++++++++++++++++++++++ templates/staff_problem_info.html | 4 +-- 4 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 templates/staff_problem_histogram.js diff --git a/djangoapps/courseware/module_render.py b/djangoapps/courseware/module_render.py index 38f9e0211b..d10d13637a 100644 --- a/djangoapps/courseware/module_render.py +++ b/djangoapps/courseware/module_render.py @@ -144,12 +144,17 @@ def render_x_module(user, request, xml_module, module_object_preload): module_object_preload.append(smod) # Grab content content = instance.get_html() + init_js = instance.get_init_js() + destory_js = instance.get_destroy_js() if user.is_staff: content=content+render_to_string("staff_problem_info.html", {'xml':etree.tostring(xml_module), - 'histogram':grade_histogram(module_id)}) + 'module_id' : module_id}) + init_js = init_js+render_to_string("staff_problem_histogram.js", {'histogram' : grade_histogram(module_id), + 'module_id' : module_id}) + content = {'content':content, - "destroy_js":instance.get_destroy_js(), - 'init_js':instance.get_init_js(), + "destroy_js":destory_js, + 'init_js':init_js, 'type':module_type} return content diff --git a/templates/courseware.html b/templates/courseware.html index f64060b0f6..2b5b14ed0d 100644 --- a/templates/courseware.html +++ b/templates/courseware.html @@ -2,7 +2,12 @@ <%block name="bodyclass">courseware <%block name="title">Courseware – MITx 6.002x +<%block name="headextra"> + + + <%block name="js_extra"> +##Is there a reason this isn't in header_extra? Is it important that the javascript is at the bottom of the generated document? From 14c1a18687a020d46e9e4a33655472aac5a815ea Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 4 May 2012 14:41:56 -0400 Subject: [PATCH 08/25] Re-raise an integrity error during user creation if it's not caused by something we know to check for --- djangoapps/student/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/djangoapps/student/views.py b/djangoapps/student/views.py index 89e57c836d..da9e58c486 100644 --- a/djangoapps/student/views.py +++ b/djangoapps/student/views.py @@ -181,8 +181,7 @@ def create_account(request, post_override=None): js['value']="An account with this e-mail already exists." return HttpResponse(json.dumps(js)) - js['value'] = "Unable to create your account" - return HttpResponse(json.dumps(js)) + raise r.register(u) From 9ac2c559a94a703f7d9b008fea7d78d1b22b528d Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 4 May 2012 10:20:25 -0400 Subject: [PATCH 09/25] Make local file uploads work in dev environment --- envs/common.py | 4 ++-- envs/dev.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/envs/common.py b/envs/common.py index 6a21fafc71..0f14637b78 100644 --- a/envs/common.py +++ b/envs/common.py @@ -135,13 +135,13 @@ STATIC_ROOT = ENV_ROOT / "staticfiles" # We don't run collectstatic -- this is t # FIXME: We should iterate through the courses we have, adding the static # contents for each of them. (Right now we just use symlinks.) -STATICFILES_DIRS = ( +STATICFILES_DIRS = [ PROJECT_ROOT / "static", ASKBOT_ROOT / "askbot" / "skins", # This is how you would use the textbook images locally # ("book", ENV_ROOT / "book_images") -) +] # Locale/Internationalization TIME_ZONE = 'America/New_York' # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name diff --git a/envs/dev.py b/envs/dev.py index 1a62eaf382..52796d1c42 100644 --- a/envs/dev.py +++ b/envs/dev.py @@ -73,7 +73,8 @@ DEBUG_TOOLBAR_PANELS = ( ############################ FILE UPLOADS (ASKBOT) ############################# DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' MEDIA_ROOT = ENV_ROOT / "uploads" -MEDIA_URL = "/discussion/upfiles/" +MEDIA_URL = "/static/uploads/" +STATICFILES_DIRS.append(("uploads", MEDIA_ROOT)) FILE_UPLOAD_TEMP_DIR = ENV_ROOT / "uploads" FILE_UPLOAD_HANDLERS = ( 'django.core.files.uploadhandler.MemoryFileUploadHandler', From 9d6878226f1bc5bf606ddc38194785ade344e570 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 4 May 2012 14:52:24 -0400 Subject: [PATCH 10/25] Remove the csrf domain from the default settings because we don't need it (we don't have requests going between multiple servers in the same domain). This will make it so that we can test servers from any url, rather than just a single url --- envs/aws.py | 3 +-- envs/common.py | 1 - settings.py | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/envs/aws.py b/envs/aws.py index 9ce621c2bd..de770a2399 100644 --- a/envs/aws.py +++ b/envs/aws.py @@ -24,7 +24,6 @@ with open(ENV_ROOT / "env.json") as env_file: ENV_TOKENS = json.load(env_file) SITE_NAME = ENV_TOKENS['SITE_NAME'] -CSRF_COOKIE_DOMAIN = ENV_TOKENS['CSRF_COOKIE_DOMAIN'] BOOK_URL = ENV_TOKENS['BOOK_URL'] MEDIA_URL = ENV_TOKENS['MEDIA_URL'] @@ -47,4 +46,4 @@ SECRET_KEY = AUTH_TOKENS['SECRET_KEY'] AWS_ACCESS_KEY_ID = AUTH_TOKENS["AWS_ACCESS_KEY_ID"] AWS_SECRET_ACCESS_KEY = AUTH_TOKENS["AWS_SECRET_ACCESS_KEY"] -DATABASES = AUTH_TOKENS['DATABASES'] \ No newline at end of file +DATABASES = AUTH_TOKENS['DATABASES'] diff --git a/envs/common.py b/envs/common.py index 0f14637b78..efb6885403 100644 --- a/envs/common.py +++ b/envs/common.py @@ -114,7 +114,6 @@ TEMPLATE_DEBUG = False # Site info SITE_ID = 1 SITE_NAME = "localhost:8000" -CSRF_COOKIE_DOMAIN = '127.0.0.1' HTTPS = 'on' ROOT_URLCONF = 'mitx.urls' IGNORABLE_404_ENDS = ('favicon.ico') diff --git a/settings.py b/settings.py index 84fbac2333..9a0a71cdbc 100644 --- a/settings.py +++ b/settings.py @@ -28,7 +28,6 @@ sys.path.append(BASE_DIR + "/mitx/lib") COURSEWARE_ENABLED = True ASKBOT_ENABLED = True -CSRF_COOKIE_DOMAIN = '127.0.0.1' # Defaults to be overridden EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' From 4e915d5268be73cf97f7cfd9bb23e02feb050dad Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Fri, 4 May 2012 16:29:44 -0400 Subject: [PATCH 11/25] Masquerading works --- requirements.txt | 2 +- settings.py | 2 ++ urls.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f589c7c732..cadd221efe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,4 @@ python-memcached django-celery path.py django_debug_toolbar - +django-masquerade diff --git a/settings.py b/settings.py index 9a0a71cdbc..f20f51ffb8 100644 --- a/settings.py +++ b/settings.py @@ -115,6 +115,7 @@ MIDDLEWARE_CLASSES = ( 'django.middleware.csrf.CsrfViewMiddleware', #'django.contrib.auth.middleware.AuthenticationMiddleware', 'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware', + 'masquerade.middleware.MasqueradeMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'track.middleware.TrackMiddleware', 'mitxmako.middleware.MakoMiddleware', @@ -145,6 +146,7 @@ INSTALLED_APPS = ( 'circuit', 'perfstats', 'util', + 'masquerade', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: diff --git a/urls.py b/urls.py index 329d500ea0..bbbc892abf 100644 --- a/urls.py +++ b/urls.py @@ -49,6 +49,7 @@ if settings.COURSEWARE_ENABLED: url(r'^courseware/$', 'courseware.views.index', name="courseware"), url(r'^info$', 'util.views.info'), url(r'^wiki/', include('simplewiki.urls')), + url(r'^masquerade/', include('masquerade.urls')), url(r'^courseware/(?P[^/]*)/(?P[^/]*)/(?P
[^/]*)/$', 'courseware.views.index', name="courseware_section"), url(r'^courseware/(?P[^/]*)/(?P[^/]*)/$', 'courseware.views.index', name="courseware_chapter"), url(r'^courseware/(?P[^/]*)/$', 'courseware.views.index', name="courseware_course"), From f9adfdbb50bb786a74dcb9ded5d4279e6a89cf27 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Mon, 7 May 2012 10:42:48 -0400 Subject: [PATCH 12/25] Videos now support annotations w/o verticals --- djangoapps/courseware/modules/video_module.py | 19 ++++++++++++------- templates/video.html | 8 ++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/djangoapps/courseware/modules/video_module.py b/djangoapps/courseware/modules/video_module.py index 2063c18953..a893d1f3bb 100644 --- a/djangoapps/courseware/modules/video_module.py +++ b/djangoapps/courseware/modules/video_module.py @@ -42,7 +42,8 @@ class Module(XModule): return render_to_string('video.html',{'streams':self.video_list(), 'id':self.item_id, 'position':self.position, - 'name':self.name}) + 'name':self.name, + 'annotations':self.annotations}) def get_init_js(self): '''JavaScript code to be run when problem is shown. Be aware @@ -52,19 +53,23 @@ class Module(XModule): log.debug(u"INIT POSITION {0}".format(self.position)) return render_to_string('video_init.js',{'streams':self.video_list(), 'id':self.item_id, - 'position':self.position}) + 'position':self.position})+self.annotations_init def get_destroy_js(self): - return "videoDestroy(\"{0}\");".format(self.item_id) + return "videoDestroy(\"{0}\");".format(self.item_id)+self.annotations_destroy def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None): XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function) - self.youtube = etree.XML(xml).get('youtube') - self.name = etree.XML(xml).get('name') + xmltree=etree.fromstring(xml) + self.youtube = xmltree.get('youtube') + self.name = xmltree.get('name') self.position = 0 if state != None: state = json.loads(state) if 'position' in state: self.position = int(float(state['position'])) - #log.debug("POSITION IN STATE") - #log.debug(u"LOAD POSITION {0}".format(self.position)) + + self.annotations=[(e.get("name"),self.render_function(e)) \ + for e in xmltree] + self.annotations_init="".join([e[1]['init_js'] for e in self.annotations if 'init_js' in e[1]]) + self.annotations_destroy="".join([e[1]['destroy_js'] for e in self.annotations if 'destroy_js' in e[1]]) diff --git a/templates/video.html b/templates/video.html index 563bfd5129..0d1f6c5641 100644 --- a/templates/video.html +++ b/templates/video.html @@ -122,3 +122,11 @@ }); + +
    +% for t in annotations: +
  1. + ${t[1]['content']} +
  2. +% endfor +
From edec1b5558ffa08e3af2aac0f2ac0cbd11673e95 Mon Sep 17 00:00:00 2001 From: Kyle Fiedler Date: Mon, 7 May 2012 15:26:28 -0400 Subject: [PATCH 13/25] added styles for tutorial headers and removing extra padding on bottom sequence nav --- static/css/application.css | 3 ++- templates/sass/courseware/_courseware.scss | 2 +- templates/sass/courseware/_sequence-nav.scss | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/static/css/application.css b/static/css/application.css index cf8d6f3ebe..c403a126ca 100644 --- a/static/css/application.css +++ b/static/css/application.css @@ -2811,7 +2811,7 @@ div.course-wrapper section.course-content ol.vert-mod > li { margin-bottom: 15px; padding: 0 0 15px; } div.course-wrapper section.course-content ol.vert-mod > li header { - margin-bottom: 0; } + margin-bottom: -16px; } div.course-wrapper section.course-content ol.vert-mod > li header h1 { margin: 0; } div.course-wrapper section.course-content ol.vert-mod > li header h2 { @@ -3761,6 +3761,7 @@ section.course-content nav.sequence-bottom { text-align: center; } section.course-content nav.sequence-bottom ul { background-color: #f2e7bf; + padding: 0 !important; background-color: #f2e7bf; border: 1px solid #e4d080; -webkit-border-radius: 3px; diff --git a/templates/sass/courseware/_courseware.scss b/templates/sass/courseware/_courseware.scss index 48cbcd64bb..1e0995561a 100644 --- a/templates/sass/courseware/_courseware.scss +++ b/templates/sass/courseware/_courseware.scss @@ -172,7 +172,7 @@ div.course-wrapper { header { @extend h1.top-header; - margin-bottom: 0; + margin-bottom: -16px; h1 { margin: 0; diff --git a/templates/sass/courseware/_sequence-nav.scss b/templates/sass/courseware/_sequence-nav.scss index 788db0518f..9aa6b03e0d 100644 --- a/templates/sass/courseware/_sequence-nav.scss +++ b/templates/sass/courseware/_sequence-nav.scss @@ -244,6 +244,7 @@ section.course-content { ul { @extend .clearfix; background-color: darken(#F6EFD4, 5%); + padding: 0 !important; background-color: darken($cream, 5%); border: 1px solid darken(#f6efd4, 20%); @include border-radius(3px); From 4084aaef188b04fd01c2e0dfdd4cb05d0b272dc3 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Mon, 30 Apr 2012 14:30:32 -0400 Subject: [PATCH 14/25] Make showanswer and rerandomize propogate downwards in course.xml --- djangoapps/courseware/content_parser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/djangoapps/courseware/content_parser.py b/djangoapps/courseware/content_parser.py index eb1678536d..967f7008c9 100644 --- a/djangoapps/courseware/content_parser.py +++ b/djangoapps/courseware/content_parser.py @@ -177,6 +177,8 @@ def course_xml_process(tree): propogate_downward_tag(tree, "due") propogate_downward_tag(tree, "graded") propogate_downward_tag(tree, "graceperiod") + propogate_downward_tag(tree, "showanswer") + propogate_downward_tag(tree, "rerandomize") return tree def course_file(user): From 171d40270fb47fd90933d3ae12b2439c8be1849f Mon Sep 17 00:00:00 2001 From: Kyle Fiedler Date: Mon, 7 May 2012 16:11:26 -0400 Subject: [PATCH 15/25] Fixed some of the minor css bugs --- static/css/application.css | 4 +++- templates/sass/courseware/_courseware.scss | 8 ++++++++ templates/sass/courseware/_sequence-nav.scss | 1 - 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/static/css/application.css b/static/css/application.css index c403a126ca..4e4b3cb832 100644 --- a/static/css/application.css +++ b/static/css/application.css @@ -2827,6 +2827,9 @@ div.course-wrapper section.course-content ol.vert-mod > li:last-child { div.course-wrapper section.course-content ol.vert-mod > li ul { list-style: disc outside none; padding-left: 1em; } +div.course-wrapper section.course-content ol.vert-mod > li nav.sequence-bottom ul { + list-style: none; + padding: 0; } div.course-wrapper section.course-content section.tutorials h2 { margin-bottom: 22.652px; } div.course-wrapper section.course-content section.tutorials ul { @@ -3761,7 +3764,6 @@ section.course-content nav.sequence-bottom { text-align: center; } section.course-content nav.sequence-bottom ul { background-color: #f2e7bf; - padding: 0 !important; background-color: #f2e7bf; border: 1px solid #e4d080; -webkit-border-radius: 3px; diff --git a/templates/sass/courseware/_courseware.scss b/templates/sass/courseware/_courseware.scss index 1e0995561a..39df9f955d 100644 --- a/templates/sass/courseware/_courseware.scss +++ b/templates/sass/courseware/_courseware.scss @@ -193,10 +193,18 @@ div.course-wrapper { padding-bottom: 0; } + ul { list-style: disc outside none; padding-left: 1em; } + + nav.sequence-bottom { + ul { + list-style: none; + padding: 0; + } + } } } diff --git a/templates/sass/courseware/_sequence-nav.scss b/templates/sass/courseware/_sequence-nav.scss index 9aa6b03e0d..788db0518f 100644 --- a/templates/sass/courseware/_sequence-nav.scss +++ b/templates/sass/courseware/_sequence-nav.scss @@ -244,7 +244,6 @@ section.course-content { ul { @extend .clearfix; background-color: darken(#F6EFD4, 5%); - padding: 0 !important; background-color: darken($cream, 5%); border: 1px solid darken(#f6efd4, 20%); @include border-radius(3px); From d22566a310dc9dcf768489f89ffcba929063bb71 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Mon, 7 May 2012 16:55:39 -0400 Subject: [PATCH 16/25] Added pyfilesystem to requirements.txt; needed for further hacking; want in common root --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index cadd221efe..6e13b88463 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ django-celery path.py django_debug_toolbar django-masquerade +pyfilesystem From 43a6534e75a6807021e7079a5f864aea25a2ed32 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Fri, 27 Apr 2012 17:38:45 -0400 Subject: [PATCH 17/25] Add Jasmine to do a JavaScript unit test --- requirements.txt | 1 + settings.py | 4 +++ templates/coffee/README.md | 59 ++++++++++++++++++++++++++++++++++++++ urls.py | 4 +++ 4 files changed, 68 insertions(+) create mode 100644 templates/coffee/README.md diff --git a/requirements.txt b/requirements.txt index 6e13b88463..8e701ce335 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,4 @@ path.py django_debug_toolbar django-masquerade pyfilesystem +django-jasmine diff --git a/settings.py b/settings.py index f20f51ffb8..0828f75595 100644 --- a/settings.py +++ b/settings.py @@ -147,6 +147,7 @@ INSTALLED_APPS = ( 'perfstats', 'util', 'masquerade', + 'django_jasmine', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: @@ -347,6 +348,7 @@ PROJECT_ROOT = os.path.dirname(__file__) TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.request', + 'django.core.context_processors.static', 'askbot.context.application_settings', #'django.core.context_processors.i18n', 'askbot.user_messages.context_processors.user_messages',#must be before auth @@ -683,3 +685,5 @@ if MAKO_MODULE_DIR == None: djcelery.setup_loader() +# Jasmine Settings +JASMINE_TEST_DIRECTORY = PROJECT_DIR+'/templates/coffee' diff --git a/templates/coffee/README.md b/templates/coffee/README.md new file mode 100644 index 0000000000..6c26529a5b --- /dev/null +++ b/templates/coffee/README.md @@ -0,0 +1,59 @@ +CoffeeScript +============ + +This folder contains the CoffeeScript file that will be compiled to the static +directory. By default, we're compile and merge all the files ending `.coffee` +into `static/js/application.js`. + +Install the Compiler +-------------------- + +CoffeeScript compiler are written in JavaScript. You'll need to install Node and +npm (Node Package Manager) to be able to install the CoffeeScript compiler. + +### Mac OS X + +Install Node via Homebrew, then use npm: + + brew install node + curl http://npmjs.org/install.sh | sh + npm install -g git://github.com/jashkenas/coffee-script.git + +(Note that we're using the edge version of CoffeeScript for now, as there was +some issue with directory watching in 1.3.1.) + +Try to run `coffee` and make sure you get a coffee prompt. + +### Debian/Ubuntu + +Conveniently, you can install Node via `apt-get`, then use npm: + + sudo apt-get install nodejs npm && + sudo npm install -g git://github.com/jashkenas/coffee-script.git + +Compiling +--------- + +Run this command in the `mitx` directory to easily make the compiler watch for +changes in your file, and join the result into `application.js`: + + coffee -j static/js/application.js -cw templates/coffee/src + +Please note that the compiler will not be able to detect the file that get added +after you've ran the command, so you'll need to restart the compiler if there's +a new CoffeeScript file. + +Testing +======= + +We're also using Jasmine to unit-testing the JavaScript files. All the specs are +written in CoffeeScript for the consistency. Because of the limitation of +`django-jasmine` plugin, we'll need to also running another compiler to compile +the test file. + +Using this command to compile the test files: + + coffee -cw templates/coffee/spec/*.coffee + +Then start the server in debug mode, navigate to http://127.0.0.1:8000/_jasmine +to see the test result. diff --git a/urls.py b/urls.py index bbbc892abf..6eda9953d5 100644 --- a/urls.py +++ b/urls.py @@ -77,6 +77,10 @@ if settings.ASKBOT_ENABLED: # url(r'^robots.txt$', include('robots.urls')), ) +if settings.DEBUG: + ## Jasmine + urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),) + urlpatterns = patterns(*urlpatterns) if settings.DEBUG: From 80aeaed5fe2940c586fce967d318f7ba666443e8 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Fri, 27 Apr 2012 17:38:58 -0400 Subject: [PATCH 18/25] Rewrite JavaScript on main page Both feedback form and calculator interaction now in its own class. --- static/js/application.js | 75 +++++++++++++++++ templates/coffee/files.json | 8 ++ templates/coffee/fixtures/calculator.html | 18 +++++ templates/coffee/fixtures/feedback_form.html | 7 ++ templates/coffee/spec/calculator_spec.coffee | 68 ++++++++++++++++ templates/coffee/spec/calculator_spec.js | 80 +++++++++++++++++++ .../coffee/spec/feedback_form_spec.coffee | 28 +++++++ templates/coffee/spec/feedback_form_spec.js | 35 ++++++++ templates/coffee/spec/helper.coffee | 1 + templates/coffee/spec/helper.js | 6 ++ templates/coffee/src/calculator.coffee | 20 +++++ templates/coffee/src/feedback_form.coffee | 10 +++ templates/coffee/src/main.coffee | 7 ++ templates/main.html | 72 +++-------------- 14 files changed, 376 insertions(+), 59 deletions(-) create mode 100644 static/js/application.js create mode 100644 templates/coffee/files.json create mode 100644 templates/coffee/fixtures/calculator.html create mode 100644 templates/coffee/fixtures/feedback_form.html create mode 100644 templates/coffee/spec/calculator_spec.coffee create mode 100644 templates/coffee/spec/calculator_spec.js create mode 100644 templates/coffee/spec/feedback_form_spec.coffee create mode 100644 templates/coffee/spec/feedback_form_spec.js create mode 100644 templates/coffee/spec/helper.coffee create mode 100644 templates/coffee/spec/helper.js create mode 100644 templates/coffee/src/calculator.coffee create mode 100644 templates/coffee/src/feedback_form.coffee create mode 100644 templates/coffee/src/main.coffee diff --git a/static/js/application.js b/static/js/application.js new file mode 100644 index 0000000000..1591b6fc44 --- /dev/null +++ b/static/js/application.js @@ -0,0 +1,75 @@ +// Generated by CoffeeScript 1.3.2-pre +(function() { + + window.Calculator = (function() { + + function Calculator() {} + + Calculator.bind = function() { + var calculator; + calculator = new Calculator; + $('.calc').click(calculator.toggle); + $('form#calculator').submit(calculator.calculate).submit(function(e) { + return e.preventDefault(); + }); + return $('div.help-wrapper a').hover(calculator.helpToggle).click(function(e) { + return e.preventDefault(); + }); + }; + + Calculator.prototype.toggle = function() { + $('li.calc-main').toggleClass('open'); + $('#calculator_wrapper #calculator_input').focus(); + return $('.calc').toggleClass('closed'); + }; + + Calculator.prototype.helpToggle = function() { + return $('.help').toggleClass('shown'); + }; + + Calculator.prototype.calculate = function() { + return $.getJSON('/calculate', { + equation: $('#calculator_input').val() + }, function(data) { + return $('#calculator_output').val(data.result); + }); + }; + + return Calculator; + + })(); + + window.FeedbackForm = (function() { + + function FeedbackForm() {} + + FeedbackForm.bind = function() { + return $('#feedback_button').click(function() { + var data; + data = { + subject: $('#feedback_subject').val(), + message: $('#feedback_message').val(), + url: window.location.href + }; + return $.post('/send_feedback', data, function() { + return $('#feedback_div').html('Feedback submitted. Thank you'); + }, 'json'); + }); + }; + + return FeedbackForm; + + })(); + + $(function() { + $.ajaxSetup({ + headers: { + 'X-CSRFToken': $.cookie('csrftoken') + } + }); + FeedbackForm.bind(); + Calculator.bind(); + return $("a[rel*=leanModal]").leanModal(); + }); + +}).call(this); diff --git a/templates/coffee/files.json b/templates/coffee/files.json new file mode 100644 index 0000000000..44494e8040 --- /dev/null +++ b/templates/coffee/files.json @@ -0,0 +1,8 @@ +{ + "js_files": [ + "/static/js/jquery-1.6.2.min.js" + ], + "static_files": [ + "js/application.js" + ] +} diff --git a/templates/coffee/fixtures/calculator.html b/templates/coffee/fixtures/calculator.html new file mode 100644 index 0000000000..61c6f5e153 --- /dev/null +++ b/templates/coffee/fixtures/calculator.html @@ -0,0 +1,18 @@ + diff --git a/templates/coffee/fixtures/feedback_form.html b/templates/coffee/fixtures/feedback_form.html new file mode 100644 index 0000000000..672663fe10 --- /dev/null +++ b/templates/coffee/fixtures/feedback_form.html @@ -0,0 +1,7 @@ +
+
+ + + +
+
diff --git a/templates/coffee/spec/calculator_spec.coffee b/templates/coffee/spec/calculator_spec.coffee new file mode 100644 index 0000000000..5c3fde5e2d --- /dev/null +++ b/templates/coffee/spec/calculator_spec.coffee @@ -0,0 +1,68 @@ +describe 'Calculator', -> + beforeEach -> + loadFixtures 'calculator.html' + @calculator = new Calculator + + describe 'bind', -> + beforeEach -> + Calculator.bind() + + it 'bind the calculator button', -> + expect($('.calc')).toHandleWith 'click', @calculator.toggle + + it 'bind the help button', -> + # These events are bind by $.hover() + expect($('div.help-wrapper a')).toHandleWith 'mouseenter', @calculator.helpToggle + expect($('div.help-wrapper a')).toHandleWith 'mouseleave', @calculator.helpToggle + + it 'prevent default behavior on help button', -> + $('div.help-wrapper a').click (e) -> + expect(e.isDefaultPrevented()).toBeTruthy() + $('div.help-wrapper a').click() + + it 'bind the calculator submit', -> + expect($('form#calculator')).toHandleWith 'submit', @calculator.calculate + + it 'prevent default behavior on form submit', -> + $('form#calculator').submit (e) -> + expect(e.isDefaultPrevented()).toBeTruthy() + e.preventDefault() + $('form#calculator').submit() + + describe 'toggle', -> + it 'toggle the calculator and focus the input', -> + spyOn $.fn, 'focus' + @calculator.toggle() + + expect($('li.calc-main')).toHaveClass('open') + expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled() + + it 'toggle the close button on the calculator button', -> + @calculator.toggle() + expect($('.calc')).toHaveClass('closed') + + @calculator.toggle() + expect($('.calc')).not.toHaveClass('closed') + + describe 'helpToggle', -> + it 'toggle the help overlay', -> + @calculator.helpToggle() + expect($('.help')).toHaveClass('shown') + + @calculator.helpToggle() + expect($('.help')).not.toHaveClass('shown') + + describe 'calculate', -> + beforeEach -> + $('#calculator_input').val '1+2' + spyOn($, 'getJSON').andCallFake (url, data, callback) -> + callback({ result: 3 }) + @calculator.calculate() + + it 'send data to /calculate', -> + expect($.getJSON).toHaveBeenCalledWith '/calculate', + equation: '1+2' + , jasmine.any(Function) + + it 'update the calculator output', -> + expect($('#calculator_output').val()).toEqual('3') diff --git a/templates/coffee/spec/calculator_spec.js b/templates/coffee/spec/calculator_spec.js new file mode 100644 index 0000000000..6e0f8a0dab --- /dev/null +++ b/templates/coffee/spec/calculator_spec.js @@ -0,0 +1,80 @@ +// Generated by CoffeeScript 1.3.2-pre +(function() { + + describe('Calculator', function() { + beforeEach(function() { + loadFixtures('calculator.html'); + return this.calculator = new Calculator; + }); + describe('bind', function() { + beforeEach(function() { + return Calculator.bind(); + }); + it('bind the calculator button', function() { + return expect($('.calc')).toHandleWith('click', this.calculator.toggle); + }); + it('bind the help button', function() { + expect($('div.help-wrapper a')).toHandleWith('mouseenter', this.calculator.helpToggle); + return expect($('div.help-wrapper a')).toHandleWith('mouseleave', this.calculator.helpToggle); + }); + it('prevent default behavior on help button', function() { + $('div.help-wrapper a').click(function(e) { + return expect(e.isDefaultPrevented()).toBeTruthy(); + }); + return $('div.help-wrapper a').click(); + }); + it('bind the calculator submit', function() { + return expect($('form#calculator')).toHandleWith('submit', this.calculator.calculate); + }); + return it('prevent default behavior on form submit', function() { + $('form#calculator').submit(function(e) { + expect(e.isDefaultPrevented()).toBeTruthy(); + return e.preventDefault(); + }); + return $('form#calculator').submit(); + }); + }); + describe('toggle', function() { + it('toggle the calculator and focus the input', function() { + spyOn($.fn, 'focus'); + this.calculator.toggle(); + expect($('li.calc-main')).toHaveClass('open'); + return expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled(); + }); + return it('toggle the close button on the calculator button', function() { + this.calculator.toggle(); + expect($('.calc')).toHaveClass('closed'); + this.calculator.toggle(); + return expect($('.calc')).not.toHaveClass('closed'); + }); + }); + describe('helpToggle', function() { + return it('toggle the help overlay', function() { + this.calculator.helpToggle(); + expect($('.help')).toHaveClass('shown'); + this.calculator.helpToggle(); + return expect($('.help')).not.toHaveClass('shown'); + }); + }); + return describe('calculate', function() { + beforeEach(function() { + $('#calculator_input').val('1+2'); + spyOn($, 'getJSON').andCallFake(function(url, data, callback) { + return callback({ + result: 3 + }); + }); + return this.calculator.calculate(); + }); + it('send data to /calculate', function() { + return expect($.getJSON).toHaveBeenCalledWith('/calculate', { + equation: '1+2' + }, jasmine.any(Function)); + }); + return it('update the calculator output', function() { + return expect($('#calculator_output').val()).toEqual('3'); + }); + }); + }); + +}).call(this); diff --git a/templates/coffee/spec/feedback_form_spec.coffee b/templates/coffee/spec/feedback_form_spec.coffee new file mode 100644 index 0000000000..191645b3d3 --- /dev/null +++ b/templates/coffee/spec/feedback_form_spec.coffee @@ -0,0 +1,28 @@ +describe 'FeedbackForm', -> + beforeEach -> + loadFixtures 'feedback_form.html' + + describe 'bind', -> + beforeEach -> + FeedbackForm.bind() + spyOn($, 'post').andCallFake (url, data, callback, format) -> + callback() + + it 'binds to the #feedback_button', -> + expect($('#feedback_button')).toHandle 'click' + + it 'post data to /send_feedback on click', -> + $('#feedback_subject').val 'Awesome!' + $('#feedback_message').val 'This site is really good.' + $('#feedback_button').click() + + expect($.post).toHaveBeenCalledWith '/send_feedback', { + subject: 'Awesome!' + message: 'This site is really good.' + url: window.location.href + }, jasmine.any(Function), 'json' + + it 'replace the form with a thank you message', -> + $('#feedback_button').click() + + expect($('#feedback_div').html()).toEqual 'Feedback submitted. Thank you' diff --git a/templates/coffee/spec/feedback_form_spec.js b/templates/coffee/spec/feedback_form_spec.js new file mode 100644 index 0000000000..2815cd73e5 --- /dev/null +++ b/templates/coffee/spec/feedback_form_spec.js @@ -0,0 +1,35 @@ +// Generated by CoffeeScript 1.3.2-pre +(function() { + + describe('FeedbackForm', function() { + beforeEach(function() { + return loadFixtures('feedback_form.html'); + }); + return describe('bind', function() { + beforeEach(function() { + FeedbackForm.bind(); + return spyOn($, 'post').andCallFake(function(url, data, callback, format) { + return callback(); + }); + }); + it('binds to the #feedback_button', function() { + return expect($('#feedback_button')).toHandle('click'); + }); + it('post data to /send_feedback on click', function() { + $('#feedback_subject').val('Awesome!'); + $('#feedback_message').val('This site is really good.'); + $('#feedback_button').click(); + return expect($.post).toHaveBeenCalledWith('/send_feedback', { + subject: 'Awesome!', + message: 'This site is really good.', + url: window.location.href + }, jasmine.any(Function), 'json'); + }); + return it('replace the form with a thank you message', function() { + $('#feedback_button').click(); + return expect($('#feedback_div').html()).toEqual('Feedback submitted. Thank you'); + }); + }); + }); + +}).call(this); diff --git a/templates/coffee/spec/helper.coffee b/templates/coffee/spec/helper.coffee new file mode 100644 index 0000000000..1f27e257c2 --- /dev/null +++ b/templates/coffee/spec/helper.coffee @@ -0,0 +1 @@ +jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/" diff --git a/templates/coffee/spec/helper.js b/templates/coffee/spec/helper.js new file mode 100644 index 0000000000..23b980d525 --- /dev/null +++ b/templates/coffee/spec/helper.js @@ -0,0 +1,6 @@ +// Generated by CoffeeScript 1.3.2-pre +(function() { + + jasmine.getFixtures().fixturesPath = "/_jasmine/fixtures/"; + +}).call(this); diff --git a/templates/coffee/src/calculator.coffee b/templates/coffee/src/calculator.coffee new file mode 100644 index 0000000000..7d62f5a794 --- /dev/null +++ b/templates/coffee/src/calculator.coffee @@ -0,0 +1,20 @@ +class window.Calculator + @bind: -> + calculator = new Calculator + $('.calc').click calculator.toggle + $('form#calculator').submit(calculator.calculate).submit (e) -> + e.preventDefault() + $('div.help-wrapper a').hover(calculator.helpToggle).click (e) -> + e.preventDefault() + + toggle: -> + $('li.calc-main').toggleClass 'open' + $('#calculator_wrapper #calculator_input').focus() + $('.calc').toggleClass 'closed' + + helpToggle: -> + $('.help').toggleClass 'shown' + + calculate: -> + $.getJSON '/calculate', { equation: $('#calculator_input').val() }, (data) -> + $('#calculator_output').val(data.result) diff --git a/templates/coffee/src/feedback_form.coffee b/templates/coffee/src/feedback_form.coffee new file mode 100644 index 0000000000..bbb5c09365 --- /dev/null +++ b/templates/coffee/src/feedback_form.coffee @@ -0,0 +1,10 @@ +class window.FeedbackForm + @bind: -> + $('#feedback_button').click -> + data = + subject: $('#feedback_subject').val() + message: $('#feedback_message').val() + url: window.location.href + $.post '/send_feedback', data, -> + $('#feedback_div').html 'Feedback submitted. Thank you' + ,'json' diff --git a/templates/coffee/src/main.coffee b/templates/coffee/src/main.coffee new file mode 100644 index 0000000000..dc8c4a0622 --- /dev/null +++ b/templates/coffee/src/main.coffee @@ -0,0 +1,7 @@ +$ -> + $.ajaxSetup + headers : { 'X-CSRFToken': $.cookie 'csrftoken' } + + Calculator.bind() + FeedbackForm.bind() + $("a[rel*=leanModal]").leanModal() diff --git a/templates/main.html b/templates/main.html index 7078ed64d3..59a1ed7bd0 100644 --- a/templates/main.html +++ b/templates/main.html @@ -9,6 +9,7 @@ +