-
+
@@ -12,6 +16,9 @@
% elif state == 'incomplete':
% endif
+ % if hidden:
+
+ % endif
(${state})
diff --git a/common/lib/capa/templates/textinput.html b/common/lib/capa/templates/textinput.html
index 0ba27c6938..7f2f563b81 100644
--- a/common/lib/capa/templates/textinput.html
+++ b/common/lib/capa/templates/textinput.html
@@ -8,11 +8,17 @@
% elif state == 'incomplete':
% endif
+ % if hidden:
+
+ % endif
diff --git a/common/lib/capa/templates/textinput_dynamath.html b/common/lib/capa/templates/textinput_dynamath.html
index 2fc44c9d3e..9009deb682 100644
--- a/common/lib/capa/templates/textinput_dynamath.html
+++ b/common/lib/capa/templates/textinput_dynamath.html
@@ -10,9 +10,16 @@
% elif state == 'incomplete':
+ % endif
+ % if hidden:
+
% endif
-
+
% if state == 'unsubmitted':
From edeb81ce6347d11d7da523dd7dc8bc62175a8af7 Mon Sep 17 00:00:00 2001
From: ichuang
Date: Wed, 4 Jul 2012 15:50:39 -0400
Subject: [PATCH 066/129] change 8.01x default chapter
---
lms/envs/dev_ike.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lms/envs/dev_ike.py b/lms/envs/dev_ike.py
index 642ecf22d7..c70be74352 100644
--- a/lms/envs/dev_ike.py
+++ b/lms/envs/dev_ike.py
@@ -71,7 +71,7 @@ COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x',
'xmlpath': '/8.01x/',
'github_url': 'https://github.com/MITx/8.01x',
'active': True,
- 'default_chapter' : 'MIT_8.011_Spring_2012',
+ 'default_chapter' : 'Mechanics_Online_Spring_2012',
'default_section' : 'Introduction_to_the_course',
},
'edx4edx': {'number' : 'edX.01',
From a5f3d8a9007d208d895c999ed422749754599853 Mon Sep 17 00:00:00 2001
From: ichuang
Date: Wed, 4 Jul 2012 16:06:07 -0400
Subject: [PATCH 067/129] fix handling of tail in inputtypes.math (needed
saxutils.escape)
---
common/lib/capa/inputtypes.py | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/common/lib/capa/inputtypes.py b/common/lib/capa/inputtypes.py
index 54445af769..d7c0799f75 100644
--- a/common/lib/capa/inputtypes.py
+++ b/common/lib/capa/inputtypes.py
@@ -22,10 +22,14 @@ Each input type takes the xml tree as 'element', the previous answer as 'value',
# status is currently the answer for the problem ID for the input element,
# but it will turn into a dict containing both the answer and any associated message for the problem ID for the input element.
+import logging
import re
import shlex # for splitting quoted strings
from lxml import etree
+import xml.sax.saxutils as saxutils
+
+log = logging.getLogger('mitx.' + __name__)
def get_input_xml_tags():
''' Eventually, this will be for all registered input types '''
@@ -299,8 +303,18 @@ def math(element, value, status, render_template, msg=''):
# isinline = True
# html = render_template("mathstring.html",{'mathstr':mathstr,'isinline':isinline,'tail':element.tail})
- html = '%s%s' % (mathstr,element.tail)
- xhtml = etree.XML(html)
+ html = '%s%s' % (mathstr,saxutils.escape(element.tail))
+ try:
+ xhtml = etree.XML(html)
+ except Exception as err:
+ if False: # TODO needs to be self.system.DEBUG - but can't access system
+ msg = "Error %s
" % str(err).replace('<','<')
+ msg += 'Failed to construct math expression from
%s
' % html.replace('<','<')
+ msg += ""
+ log.error(msg)
+ return etree.XML(msg)
+ else:
+ raise
# xhtml.tail = element.tail # don't forget to include the tail!
return xhtml
From 21734eb919ba93d9e80fa2b0dd0e2c86c55e5952 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 14:49:41 -0400
Subject: [PATCH 068/129] Add Backbone to the project
---
cms/static/js/backbone-min.js | 38 +++
cms/static/js/json2.js | 487 ++++++++++++++++++++++++++++++++
cms/static/js/underscore-min.js | 32 +++
cms/templates/base.html | 3 +
4 files changed, 560 insertions(+)
create mode 100644 cms/static/js/backbone-min.js
create mode 100644 cms/static/js/json2.js
create mode 100644 cms/static/js/underscore-min.js
diff --git a/cms/static/js/backbone-min.js b/cms/static/js/backbone-min.js
new file mode 100644
index 0000000000..c1c0d4fff2
--- /dev/null
+++ b/cms/static/js/backbone-min.js
@@ -0,0 +1,38 @@
+// Backbone.js 0.9.2
+
+// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Backbone may be freely distributed under the MIT license.
+// For all details and documentation:
+// http://backbonejs.org
+(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks=
+{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g=
+z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent=
+{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null==
+b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent:
+b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};
+a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error,
+h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t();
+return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending=
+{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||
+!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator);
+this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c=b))this.iframe=i('').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?i(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?i(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,
+this.interval));this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&(this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},
+stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a==this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,
+function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!m.started)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(s,"");this.fragment!=c&&(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace||
+this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},F=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(",");
+f.extend(v.prototype,k,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c&&i(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents();
+for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(F),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b2;a==null&&(a=[]);if(A&&
+a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,
+c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,
+a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
+function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};
+j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=
+i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&
+c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=
+function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"};
+b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,
+b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e /g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId=
+function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape||
+u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};
+b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d,
+this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
diff --git a/cms/templates/base.html b/cms/templates/base.html
index 12df2b7a28..97e4aa8526 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -24,6 +24,9 @@
<%block name="content">%block>
+
+
+
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
From 0e87ada0fdb605561c84c18c3f39d944be299ea3 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 14:50:11 -0400
Subject: [PATCH 069/129] Do nested search for CoffeeScript compilation
---
cms/envs/common.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 6edd6aa2b9..472a59d295 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -24,6 +24,7 @@ import tempfile
import os.path
import os
import errno
+import glob2
from path import path
############################ FEATURE CONFIGURATION #############################
@@ -183,8 +184,8 @@ for xmodule in XModuleDescriptor.load_classes() + [RawDescriptor]:
PIPELINE_JS = {
'main': {
- 'source_filenames': ['coffee/main.coffee', 'coffee/unit.coffee'],
- 'output_filename': 'js/main.js',
+ 'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/src/**/*.coffee')],
+ 'output_filename': 'js/application.js',
},
'module-js': {
'source_filenames': module_js_sources,
From b46f6a6d9c266cab9fd450b9452e203ef203e8d2 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 14:50:33 -0400
Subject: [PATCH 070/129] Section editing interface is now working
---
cms/static/coffee/src/main.coffee | 14 ++++++++++++++
cms/static/coffee/src/models/module.coffee | 3 +++
cms/static/coffee/src/models/week.coffee | 1 +
cms/static/coffee/src/views/course.coffee | 19 +++++++++++++++++++
cms/static/coffee/src/views/module.coffee | 9 +++++++++
.../coffee/src/views/module_edit.coffee | 7 +++++++
cms/static/coffee/src/views/week.coffee | 15 +++++++++++++++
cms/static/coffee/src/views/week_edit.coffee | 6 ++++++
cms/templates/index.html | 3 ---
cms/templates/widgets/navigation.html | 12 ++++++------
10 files changed, 80 insertions(+), 9 deletions(-)
create mode 100644 cms/static/coffee/src/main.coffee
create mode 100644 cms/static/coffee/src/models/module.coffee
create mode 100644 cms/static/coffee/src/models/week.coffee
create mode 100644 cms/static/coffee/src/views/course.coffee
create mode 100644 cms/static/coffee/src/views/module.coffee
create mode 100644 cms/static/coffee/src/views/module_edit.coffee
create mode 100644 cms/static/coffee/src/views/week.coffee
create mode 100644 cms/static/coffee/src/views/week_edit.coffee
diff --git a/cms/static/coffee/src/main.coffee b/cms/static/coffee/src/main.coffee
new file mode 100644
index 0000000000..5959edd2ea
--- /dev/null
+++ b/cms/static/coffee/src/main.coffee
@@ -0,0 +1,14 @@
+@CMS =
+ Models: {}
+ Views: {}
+
+ start: ->
+ new CMS.Views.Course el: $('section.main-container')
+
+_.extend CMS, Backbone.Events
+
+$ ->
+ $.ajaxSetup
+ headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
+
+ CMS.start()
diff --git a/cms/static/coffee/src/models/module.coffee b/cms/static/coffee/src/models/module.coffee
new file mode 100644
index 0000000000..aba2c4f2d6
--- /dev/null
+++ b/cms/static/coffee/src/models/module.coffee
@@ -0,0 +1,3 @@
+class CMS.Models.Module extends Backbone.Model
+ editUrl: ->
+ "/edit_item?id=#{@get('id')}"
diff --git a/cms/static/coffee/src/models/week.coffee b/cms/static/coffee/src/models/week.coffee
new file mode 100644
index 0000000000..03e9c5d6f1
--- /dev/null
+++ b/cms/static/coffee/src/models/week.coffee
@@ -0,0 +1 @@
+class CMS.Models.Week extends Backbone.Model
diff --git a/cms/static/coffee/src/views/course.coffee b/cms/static/coffee/src/views/course.coffee
new file mode 100644
index 0000000000..769612de72
--- /dev/null
+++ b/cms/static/coffee/src/views/course.coffee
@@ -0,0 +1,19 @@
+class CMS.Views.Course extends Backbone.View
+ initialize: ->
+ @$('#weeks > li').each (index, week) =>
+ new CMS.Views.Week el: week, height: @maxWeekHeight()
+
+ CMS.on('showContent', @showContent)
+
+ showContent: (subview) =>
+ $('body').addClass('content')
+ @$('.main-content').html(subview.el)
+ @$('.cal').css height: @contentHeight()
+ @$('>section').css minHeight: @contentHeight()
+
+ maxWeekHeight: ->
+ _.max($('#weeks > li').map -> $(this).height()) + 1
+
+ contentHeight: ->
+ padding = 29
+ $(window).height() - padding
diff --git a/cms/static/coffee/src/views/module.coffee b/cms/static/coffee/src/views/module.coffee
new file mode 100644
index 0000000000..5d7368778c
--- /dev/null
+++ b/cms/static/coffee/src/views/module.coffee
@@ -0,0 +1,9 @@
+class CMS.Views.Module extends Backbone.View
+ events:
+ "click .module-edit": "edit"
+
+ initialize: ->
+ @model = new CMS.Models.Module(id: @el.id)
+
+ edit: =>
+ CMS.trigger('showContent', new CMS.Views.ModuleEdit(model: @model))
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
new file mode 100644
index 0000000000..556424bd9c
--- /dev/null
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -0,0 +1,7 @@
+class CMS.Views.ModuleEdit extends Backbone.View
+ tagName: 'section'
+ className: 'edit-pane'
+
+ initialize: ->
+ CMS.trigger 'module.edit'
+ @$el.append($('').load(@model.editUrl()))
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
new file mode 100644
index 0000000000..f80d63de52
--- /dev/null
+++ b/cms/static/coffee/src/views/week.coffee
@@ -0,0 +1,15 @@
+class CMS.Views.Week extends Backbone.View
+ events:
+ 'click .module-edit': 'edit'
+
+ initialize: ->
+ @model = new CMS.Models.Week(id: @el.id)
+ @$el.height @options.height
+ @$('.editable').inlineEdit()
+ @$('.editable-textarea').inlineEdit(control: 'textarea')
+
+ @$('#modules .module').each ->
+ new CMS.Views.Module el: this
+
+ edit: =>
+ CMS.trigger('showContent', new CMS.Views.WeekEdit(model: @model))
diff --git a/cms/static/coffee/src/views/week_edit.coffee b/cms/static/coffee/src/views/week_edit.coffee
new file mode 100644
index 0000000000..0deab707a5
--- /dev/null
+++ b/cms/static/coffee/src/views/week_edit.coffee
@@ -0,0 +1,6 @@
+class CMS.Views.WeekEdit extends Backbone.View
+ tagName: 'section'
+ className: 'edit-pane'
+
+ initialize: ->
+ CMS.trigger 'week.edit'
diff --git a/cms/templates/index.html b/cms/templates/index.html
index 6bc04dc8a2..92b5cc296c 100644
--- a/cms/templates/index.html
+++ b/cms/templates/index.html
@@ -7,9 +7,6 @@
<%include file="widgets/navigation.html"/>
diff --git a/cms/templates/widgets/navigation.html b/cms/templates/widgets/navigation.html
index ea158d305a..372f298a8b 100644
--- a/cms/templates/widgets/navigation.html
+++ b/cms/templates/widgets/navigation.html
@@ -34,11 +34,11 @@
-
+
% for week in weeks:
-
+
-
+
% if 'goals' in week.metadata:
% for goal in week.metadata['goals']:
@@ -50,10 +50,10 @@
-
+
% for module in week.get_children():
-
- ${module.name}
+
+ ${module.name}
handle
% endfor
From 7c044aa18a870f7bd7607a3c707616b6e2a4a23a Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 16:14:33 -0400
Subject: [PATCH 071/129] Correctly hide the content when cancel
---
cms/static/coffee/src/views/course.coffee | 7 +++++++
cms/static/coffee/src/views/module_edit.coffee | 8 +++++++-
cms/static/coffee/src/views/week.coffee | 15 ++++++++++++---
3 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/cms/static/coffee/src/views/course.coffee b/cms/static/coffee/src/views/course.coffee
index 769612de72..51413b1ecd 100644
--- a/cms/static/coffee/src/views/course.coffee
+++ b/cms/static/coffee/src/views/course.coffee
@@ -4,6 +4,7 @@ class CMS.Views.Course extends Backbone.View
new CMS.Views.Week el: week, height: @maxWeekHeight()
CMS.on('showContent', @showContent)
+ CMS.on('hideContent', @hideContent)
showContent: (subview) =>
$('body').addClass('content')
@@ -11,6 +12,12 @@ class CMS.Views.Course extends Backbone.View
@$('.cal').css height: @contentHeight()
@$('>section').css minHeight: @contentHeight()
+ hideContent: =>
+ $('body').removeClass('content')
+ @$('.main-content').empty()
+ @$('.cal').css height: ''
+ @$('>section').css minHeight: ''
+
maxWeekHeight: ->
_.max($('#weeks > li').map -> $(this).height()) + 1
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
index 556424bd9c..403b8277b3 100644
--- a/cms/static/coffee/src/views/module_edit.coffee
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -2,6 +2,12 @@ class CMS.Views.ModuleEdit extends Backbone.View
tagName: 'section'
className: 'edit-pane'
+ events:
+ 'click .cancel': 'cancel'
+
initialize: ->
CMS.trigger 'module.edit'
- @$el.append($('').load(@model.editUrl()))
+ @$el.append($("""
""").load(@model.editUrl()))
+
+ cancel: ->
+ CMS.trigger 'hideContent'
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index f80d63de52..d26249065c 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -3,13 +3,22 @@ class CMS.Views.Week extends Backbone.View
'click .module-edit': 'edit'
initialize: ->
- @model = new CMS.Models.Week(id: @el.id)
- @$el.height @options.height
+ @model = new CMS.Models.Week(id: @$el.data('id'))
+ @setHeight()
@$('.editable').inlineEdit()
@$('.editable-textarea').inlineEdit(control: 'textarea')
- @$('#modules .module').each ->
+ @$('.modules .module').each ->
new CMS.Views.Module el: this
+ CMS.on('showContent', @resetHeight)
+ CMS.on('hideContent', @setHeight)
+
edit: =>
CMS.trigger('showContent', new CMS.Views.WeekEdit(model: @model))
+
+ setHeight: =>
+ @$el.height(@options.height)
+
+ resetHeight: =>
+ @$el.height('')
From a7dc045f3622891371975bd65e0ec9f5e267ec39 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 16:15:00 -0400
Subject: [PATCH 072/129] External module loading
---
cms/static/coffee/src/models/module.coffee | 8 +++++++-
cms/static/coffee/src/views/module.coffee | 2 +-
cms/static/coffee/src/views/week_edit.coffee | 2 +-
cms/templates/widgets/navigation.html | 6 +++---
4 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/cms/static/coffee/src/models/module.coffee b/cms/static/coffee/src/models/module.coffee
index aba2c4f2d6..c3430d3938 100644
--- a/cms/static/coffee/src/models/module.coffee
+++ b/cms/static/coffee/src/models/module.coffee
@@ -1,3 +1,9 @@
class CMS.Models.Module extends Backbone.Model
+ initialize: ->
+ try
+ @module = new window[@get('type')](@get('id'))
+ catch TypeError
+ console.error "Unable to load #{@get('type')}." if console
+
editUrl: ->
- "/edit_item?id=#{@get('id')}"
+ "/edit_item?#{$.param(id: @get('id'))}"
diff --git a/cms/static/coffee/src/views/module.coffee b/cms/static/coffee/src/views/module.coffee
index 5d7368778c..f99422d79e 100644
--- a/cms/static/coffee/src/views/module.coffee
+++ b/cms/static/coffee/src/views/module.coffee
@@ -3,7 +3,7 @@ class CMS.Views.Module extends Backbone.View
"click .module-edit": "edit"
initialize: ->
- @model = new CMS.Models.Module(id: @el.id)
+ @model = new CMS.Models.Module(id: @$el.data('id'), type: @$el.data('type'))
edit: =>
CMS.trigger('showContent', new CMS.Views.ModuleEdit(model: @model))
diff --git a/cms/static/coffee/src/views/week_edit.coffee b/cms/static/coffee/src/views/week_edit.coffee
index 0deab707a5..10dd20f393 100644
--- a/cms/static/coffee/src/views/week_edit.coffee
+++ b/cms/static/coffee/src/views/week_edit.coffee
@@ -3,4 +3,4 @@ class CMS.Views.WeekEdit extends Backbone.View
className: 'edit-pane'
initialize: ->
- CMS.trigger 'week.edit'
+ CMS.trigger('week.edit')
diff --git a/cms/templates/widgets/navigation.html b/cms/templates/widgets/navigation.html
index 372f298a8b..dca9177860 100644
--- a/cms/templates/widgets/navigation.html
+++ b/cms/templates/widgets/navigation.html
@@ -36,7 +36,7 @@
% for week in weeks:
-
+
-
+
% for module in week.get_children():
-
+
${module.name}
handle
From 8a91616aaba5aec020455bb509edf4155e61ae81 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 17:13:18 -0400
Subject: [PATCH 073/129] Implement viewStack to support nested view
---
cms/static/coffee/src/main.coffee | 19 +++++++++++++++++++
cms/static/coffee/src/views/course.coffee | 4 ++--
cms/static/coffee/src/views/module.coffee | 2 +-
.../coffee/src/views/module_edit.coffee | 4 ++--
cms/static/coffee/src/views/week.coffee | 6 +++---
5 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/cms/static/coffee/src/main.coffee b/cms/static/coffee/src/main.coffee
index 5959edd2ea..ed27c8ab34 100644
--- a/cms/static/coffee/src/main.coffee
+++ b/cms/static/coffee/src/main.coffee
@@ -2,9 +2,28 @@
Models: {}
Views: {}
+ viewStack: []
+
start: ->
new CMS.Views.Course el: $('section.main-container')
+ replaceView: (view) ->
+ @viewStack = [view]
+ CMS.trigger('content.show', view)
+
+ pushView: (view) ->
+ @viewStack.push(view)
+ CMS.trigger('content.show', view)
+
+ popView: ->
+ @viewStack.pop()
+ if _.isEmpty(@viewStack)
+ CMS.trigger('content.hide')
+ else
+ view = _.last(@viewStack)
+ CMS.trigger('content.show', view)
+ view.delegateEvents()
+
_.extend CMS, Backbone.Events
$ ->
diff --git a/cms/static/coffee/src/views/course.coffee b/cms/static/coffee/src/views/course.coffee
index 51413b1ecd..9d32b04d26 100644
--- a/cms/static/coffee/src/views/course.coffee
+++ b/cms/static/coffee/src/views/course.coffee
@@ -3,8 +3,8 @@ class CMS.Views.Course extends Backbone.View
@$('#weeks > li').each (index, week) =>
new CMS.Views.Week el: week, height: @maxWeekHeight()
- CMS.on('showContent', @showContent)
- CMS.on('hideContent', @hideContent)
+ CMS.on('content.show', @showContent)
+ CMS.on('content.hide', @hideContent)
showContent: (subview) =>
$('body').addClass('content')
diff --git a/cms/static/coffee/src/views/module.coffee b/cms/static/coffee/src/views/module.coffee
index f99422d79e..63ecabe835 100644
--- a/cms/static/coffee/src/views/module.coffee
+++ b/cms/static/coffee/src/views/module.coffee
@@ -6,4 +6,4 @@ class CMS.Views.Module extends Backbone.View
@model = new CMS.Models.Module(id: @$el.data('id'), type: @$el.data('type'))
edit: =>
- CMS.trigger('showContent', new CMS.Views.ModuleEdit(model: @model))
+ CMS.replaceView(new CMS.Views.ModuleEdit(model: @model))
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
index 403b8277b3..9f002dae70 100644
--- a/cms/static/coffee/src/views/module_edit.coffee
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -4,10 +4,10 @@ class CMS.Views.ModuleEdit extends Backbone.View
events:
'click .cancel': 'cancel'
+ # 'click .module-edit', 'edit'
initialize: ->
- CMS.trigger 'module.edit'
@$el.append($("""""").load(@model.editUrl()))
cancel: ->
- CMS.trigger 'hideContent'
+ CMS.popView()
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index d26249065c..e07b159a46 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -11,11 +11,11 @@ class CMS.Views.Week extends Backbone.View
@$('.modules .module').each ->
new CMS.Views.Module el: this
- CMS.on('showContent', @resetHeight)
- CMS.on('hideContent', @setHeight)
+ CMS.on('content.show', @resetHeight)
+ CMS.on('content.hide', @setHeight)
edit: =>
- CMS.trigger('showContent', new CMS.Views.WeekEdit(model: @model))
+ CMS.replaceView(new CMS.Views.WeekEdit(model: @model))
setHeight: =>
@$el.height(@options.height)
From 5c85412dfae71328143235c983b17c434e05c269 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 17:30:54 -0400
Subject: [PATCH 074/129] Nested subview is working
---
cms/static/coffee/src/views/module_edit.coffee | 7 ++++++-
cms/templates/widgets/sequence-edit.html | 2 +-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
index 9f002dae70..d8a6acdcc3 100644
--- a/cms/static/coffee/src/views/module_edit.coffee
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -4,10 +4,15 @@ class CMS.Views.ModuleEdit extends Backbone.View
events:
'click .cancel': 'cancel'
- # 'click .module-edit', 'edit'
+ 'click .module-edit': 'editSubmodule'
initialize: ->
@$el.append($("""""").load(@model.editUrl()))
cancel: ->
CMS.popView()
+
+ editSubmodule: (event) =>
+ $el = $(event.target)
+ model = new CMS.Models.Module(id: $el.data('id'), type: $el.data('type'))
+ CMS.pushView(new CMS.Views.ModuleEdit(model: model))
diff --git a/cms/templates/widgets/sequence-edit.html b/cms/templates/widgets/sequence-edit.html
index 319e137638..bba45d8856 100644
--- a/cms/templates/widgets/sequence-edit.html
+++ b/cms/templates/widgets/sequence-edit.html
@@ -37,7 +37,7 @@
% for child in module.get_children():
- ${child.name}
+ ${child.name}
handle
%endfor
From 0f60459709aee6eec053eabb7916fbbbcf06b5a5 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Mon, 18 Jun 2012 14:15:23 -0400
Subject: [PATCH 075/129] Add @expect_json to help with parsing JSON request
---
common/djangoapps/util/json_request.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 common/djangoapps/util/json_request.py
diff --git a/common/djangoapps/util/json_request.py b/common/djangoapps/util/json_request.py
new file mode 100644
index 0000000000..4066cfc889
--- /dev/null
+++ b/common/djangoapps/util/json_request.py
@@ -0,0 +1,16 @@
+from functools import wraps
+import copy
+import json
+
+def expect_json(view_function):
+ @wraps(view_function)
+ def expect_json_with_cloned_request(request, *args, **kwargs):
+ if request.META['CONTENT_TYPE'] == "application/json":
+ cloned_request = copy.copy(request)
+ cloned_request.POST = cloned_request.POST.copy()
+ cloned_request.POST.update(json.loads(request.raw_post_data))
+ return view_function(cloned_request, *args, **kwargs)
+ else:
+ return view_function(request, *args, **kwargs)
+
+ return expect_json_with_cloned_request
From 29e69db0dc1b141f5d9d97aba7038e34efd7f0b1 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 28 Jun 2012 18:10:22 -0400
Subject: [PATCH 076/129] Implement HTML module save
---
cms/djangoapps/contentstore/views.py | 2 ++
cms/static/coffee/src/main.coffee | 2 ++
cms/static/coffee/src/models/module.coffee | 12 ++++++++++--
cms/static/coffee/src/views/module_edit.coffee | 9 ++++++++-
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py
index 76a904a403..9166763c87 100644
--- a/cms/djangoapps/contentstore/views.py
+++ b/cms/djangoapps/contentstore/views.py
@@ -2,6 +2,7 @@ from mitxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore
from django_future.csrf import ensure_csrf_cookie
from django.http import HttpResponse
+from util.json_request import expect_json
import json
from fs.osfs import OSFS
@@ -28,6 +29,7 @@ def edit_item(request):
})
+@expect_json
def save_item(request):
item_id = request.POST['id']
data = json.loads(request.POST['data'])
diff --git a/cms/static/coffee/src/main.coffee b/cms/static/coffee/src/main.coffee
index ed27c8ab34..9fa5f3a392 100644
--- a/cms/static/coffee/src/main.coffee
+++ b/cms/static/coffee/src/main.coffee
@@ -27,6 +27,8 @@
_.extend CMS, Backbone.Events
$ ->
+ Backbone.emulateHTTP = true
+
$.ajaxSetup
headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
diff --git a/cms/static/coffee/src/models/module.coffee b/cms/static/coffee/src/models/module.coffee
index c3430d3938..dbcc412d5c 100644
--- a/cms/static/coffee/src/models/module.coffee
+++ b/cms/static/coffee/src/models/module.coffee
@@ -1,9 +1,17 @@
class CMS.Models.Module extends Backbone.Model
- initialize: ->
+ url: '/save_item'
+ defaults:
+ data: '{}'
+
+ loadModule: (element) ->
try
- @module = new window[@get('type')](@get('id'))
+ @module = new window[@get('type')](element)
catch TypeError
console.error "Unable to load #{@get('type')}." if console
editUrl: ->
"/edit_item?#{$.param(id: @get('id'))}"
+
+ save: (args...) ->
+ @set(data: JSON.stringify(@module.save())) if @module
+ super(args...)
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
index d8a6acdcc3..7611d75fa4 100644
--- a/cms/static/coffee/src/views/module_edit.coffee
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -5,9 +5,16 @@ class CMS.Views.ModuleEdit extends Backbone.View
events:
'click .cancel': 'cancel'
'click .module-edit': 'editSubmodule'
+ 'click .save-update': 'save'
initialize: ->
- @$el.append($("""""").load(@model.editUrl()))
+ @$el.load @model.editUrl(), =>
+ @model.loadModule(@el)
+
+ save: (event) ->
+ event.preventDefault()
+ @model.save().success ->
+ console.log "Saved"
cancel: ->
CMS.popView()
From b533ab481a6470f843a2f397e5817d4274f2f252 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 29 Jun 2012 14:39:30 -0400
Subject: [PATCH 077/129] Remove old JavaScript files
---
cms/static/coffee/main.coffee | 90 -----------------------------------
cms/static/coffee/unit.coffee | 15 ------
2 files changed, 105 deletions(-)
delete mode 100644 cms/static/coffee/main.coffee
delete mode 100644 cms/static/coffee/unit.coffee
diff --git a/cms/static/coffee/main.coffee b/cms/static/coffee/main.coffee
deleted file mode 100644
index 8f7d7d7323..0000000000
--- a/cms/static/coffee/main.coffee
+++ /dev/null
@@ -1,90 +0,0 @@
-class @CMS
- @setHeight = =>
- windowHeight = $(this).height()
- @contentHeight = windowHeight - 29
-
- @bind = =>
- $('a.module-edit').click ->
- CMS.edit_item($(this).attr('id'))
- return false
- $(window).bind('resize', CMS.setHeight)
-
- @edit_item = (id) =>
- $.get('/edit_item', {id: id}, (data) =>
- $('#module-html').empty().append(data)
- CMS.bind()
- $('body.content .cal').css('height', @contentHeight)
- $('body').addClass('content')
- $('section.edit-pane').show()
- new Unit('unit-wrapper', id)
- )
-
-$ ->
- $.ajaxSetup
- headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
- $('section.main-content').children().hide()
- $('.editable').inlineEdit()
- $('.editable-textarea').inlineEdit({control: 'textarea'})
-
- heighest = 0
- $('.cal ol > li').each ->
- heighest = if $(this).height() > heighest then $(this).height() else heighest
-
- $('.cal ol > li').css('height',heighest + 'px')
-
- $('.add-new-section').click -> return false
-
- $('.new-week .close').click ->
- $(this).parents('.new-week').hide()
- $('p.add-new-week').show()
- return false
-
- $('.save-update').click ->
- $(this).parent().parent().hide()
- return false
-
- # $('html').keypress ->
- # $('.wip').css('visibility', 'visible')
-
- setHeight = ->
- windowHeight = $(this).height()
- contentHeight = windowHeight - 29
-
- $('section.main-content > section').css('min-height', contentHeight)
- $('body.content .cal').css('height', contentHeight)
-
- $('.edit-week').click ->
- $('body').addClass('content')
- $('body.content .cal').css('height', contentHeight)
- $('section.edit-pane').show()
- return false
-
- $('a.week-edit').click ->
- $('body').addClass('content')
- $('body.content .cal').css('height', contentHeight)
- $('section.edit-pane').show()
- return false
-
- $('a.sequence-edit').click ->
- $('body').addClass('content')
- $('body.content .cal').css('height', contentHeight)
- $('section.edit-pane').show()
- return false
-
- $('a.module-edit').click ->
- $('body.content .cal').css('height', contentHeight)
-
- $(document).ready(setHeight)
- $(window).bind('resize', setHeight)
-
- $('.video-new a').click ->
- $('section.edit-pane').show()
- return false
-
- $('.problem-new a').click ->
- $('section.edit-pane').show()
- return false
-
- CMS.setHeight()
- CMS.bind()
-
diff --git a/cms/static/coffee/unit.coffee b/cms/static/coffee/unit.coffee
deleted file mode 100644
index b81bc0df08..0000000000
--- a/cms/static/coffee/unit.coffee
+++ /dev/null
@@ -1,15 +0,0 @@
-class @Unit
- constructor: (@element_id, @module_id) ->
- @module = new window[$("##{@element_id}").attr('class')] 'module-html'
-
- $("##{@element_id} .save-update").click (event) =>
- event.preventDefault()
- $.post("save_item", {
- id: @module_id
- data: JSON.stringify(@module.save())
- })
-
- $("##{@element_id} .cancel").click (event) =>
- event.preventDefault()
- CMS.edit_item(@module_id)
-
From 82c68dd84548e3fa41cf87a8fd59de1b165cb436 Mon Sep 17 00:00:00 2001
From: Kyle Fiedler
Date: Thu, 5 Jul 2012 10:00:54 -0400
Subject: [PATCH 078/129] Removed table borders and declared inputs as inline
instead of inline-block
---
lms/static/sass/courseware/_problems.scss | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/lms/static/sass/courseware/_problems.scss b/lms/static/sass/courseware/_problems.scss
index cbcc2ab4bc..dc66b2e743 100644
--- a/lms/static/sass/courseware/_problems.scss
+++ b/lms/static/sass/courseware/_problems.scss
@@ -205,17 +205,17 @@ section.problem-set {
table {
margin-bottom: lh();
width: 100%;
- border: 1px solid #ddd;
+ // border: 1px solid #ddd;
border-collapse: collapse;
th {
- border-bottom: 2px solid #ccc;
+ // border-bottom: 2px solid #ccc;
font-weight: bold;
text-align: left;
}
td {
- border: 1px solid #ddd;
+ // border: 1px solid #ddd;
}
caption, th, td {
@@ -253,11 +253,12 @@ section.problem-set {
visibility: hidden;
}
- input[type="text"] {
- display: inline-block;
- width: 50%;
+ #{$all-text-inputs} {
+ display: inline;
+ width: auto;
}
+ // this supports a deprecated element and should be removed once the center tag is removed
center {
display: block;
margin: lh() 0;
From 83da714a50fc4285f36e53d0a441bb0be44e14db Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 5 Jul 2012 10:30:04 -0400
Subject: [PATCH 079/129] Add more docstring to import_from_github
---
cms/djangoapps/github_sync/__init__.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cms/djangoapps/github_sync/__init__.py b/cms/djangoapps/github_sync/__init__.py
index 178291f7db..d00949e56e 100644
--- a/cms/djangoapps/github_sync/__init__.py
+++ b/cms/djangoapps/github_sync/__init__.py
@@ -13,7 +13,8 @@ def import_from_github(repo_settings):
repo_settings is a dictionary with the following keys:
path: file system path to the local git repo
branch: name of the branch to track on github
- org: name of the
+ org: name of the organization to use in the imported course
+ course: name of the coures to use in the imported course
"""
repo_path = repo_settings['path']
From ab851c0b1ae7e528eecfce811bb6e3ebab1c712a Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 5 Jul 2012 11:54:43 -0400
Subject: [PATCH 080/129] Add tests for the core github_sync functionality
---
cms/djangoapps/github_sync/__init__.py | 31 ++++--
cms/djangoapps/github_sync/exceptions.py | 2 +
cms/djangoapps/github_sync/tests/__init__.py | 96 +++++++++++++++++++
cms/envs/test.py | 14 ++-
.../data/toy/{toy_course.xml => course.xml} | 0
requirements.txt | 1 +
test_root/.gitignore | 2 +
7 files changed, 137 insertions(+), 9 deletions(-)
create mode 100644 cms/djangoapps/github_sync/exceptions.py
create mode 100644 cms/djangoapps/github_sync/tests/__init__.py
rename common/test/data/toy/{toy_course.xml => course.xml} (100%)
create mode 100644 test_root/.gitignore
diff --git a/cms/djangoapps/github_sync/__init__.py b/cms/djangoapps/github_sync/__init__.py
index d00949e56e..c901ad37e7 100644
--- a/cms/djangoapps/github_sync/__init__.py
+++ b/cms/djangoapps/github_sync/__init__.py
@@ -1,10 +1,16 @@
-from git import Repo
-from contentstore import import_from_xml
-from fs.osfs import OSFS
+import logging
import os
-from xmodule.modulestore import Location
-from django.conf import settings
+from django.conf import settings
+from fs.osfs import OSFS
+from git import Repo, PushInfo
+
+from contentstore import import_from_xml
+from xmodule.modulestore import Location
+
+from .exceptions import GithubSyncError
+
+log = logging.getLogger(__name__)
def import_from_github(repo_settings):
"""
@@ -53,4 +59,17 @@ def export_to_github(course, repo_path, commit_message):
origin = git_repo.remotes.origin
if settings.MITX_FEATURES['GITHUB_PUSH']:
- origin.push()
+ push_infos = origin.push()
+ if len(push_infos) > 1:
+ log.error('Unexpectedly pushed multiple heads: {infos}'.format(
+ infos="\n".join(str(info.summary) for info in push_infos)
+ ))
+
+ if push_infos[0].flags & PushInfo.ERROR:
+ log.error('Failed push: flags={p.flags}, local_ref={p.local_ref}, '
+ 'remote_ref_string={p.remote_ref_string}, '
+ 'remote_ref={p.remote_ref}, old_commit={p.old_commit}, '
+ 'summary={p.summary})'.format(p=push_infos[0]))
+ raise GithubSyncError('Failed to push: {info}'.format(
+ info=str(push_infos[0].summary)
+ ))
diff --git a/cms/djangoapps/github_sync/exceptions.py b/cms/djangoapps/github_sync/exceptions.py
new file mode 100644
index 0000000000..9097ffc2a6
--- /dev/null
+++ b/cms/djangoapps/github_sync/exceptions.py
@@ -0,0 +1,2 @@
+class GithubSyncError(Exception):
+ pass
diff --git a/cms/djangoapps/github_sync/tests/__init__.py b/cms/djangoapps/github_sync/tests/__init__.py
new file mode 100644
index 0000000000..825fc68313
--- /dev/null
+++ b/cms/djangoapps/github_sync/tests/__init__.py
@@ -0,0 +1,96 @@
+from django.test import TestCase
+from path import path
+import shutil
+from github_sync import import_from_github, export_to_github, repo_path_from_location
+from git import Repo
+from django.conf import settings
+from xmodule.modulestore.django import modulestore
+from xmodule.modulestore import Location
+from override_settings import override_settings
+from github_sync.exceptions import GithubSyncError
+
+
+class GithubSyncTestCase(TestCase):
+
+ def setUp(self):
+ self.working_dir = path(settings.TEST_ROOT)
+ self.repo_dir = self.working_dir / 'local_repo'
+ self.remote_dir = self.working_dir / 'remote_repo'
+ shutil.copytree('common/test/data/toy', self.remote_dir)
+
+ remote = Repo.init(self.remote_dir)
+ remote.git.add(A=True)
+ remote.git.commit(m='Initial commit')
+ remote.git.config("receive.denyCurrentBranch", "ignore")
+
+ modulestore().collection.drop()
+
+ self.import_revision, self.import_course = import_from_github({
+ 'path': self.repo_dir,
+ 'origin': self.remote_dir,
+ 'branch': 'master',
+ 'org': 'org',
+ 'course': 'course'
+ })
+
+ def tearDown(self):
+ shutil.rmtree(self.repo_dir)
+ shutil.rmtree(self.remote_dir)
+
+ def test_initialize_repo(self):
+ """
+ Test that importing from github will create a repo if the repo doesn't already exist
+ """
+ self.assertEquals(1, len(Repo(self.repo_dir).head.reference.log()))
+
+ def test_import_contents(self):
+ """
+ Test that the import loads the correct course into the modulestore
+ """
+ self.assertEquals('Toy Course', self.import_course.metadata['display_name'])
+ self.assertIn(
+ Location('i4x://org/course/chapter/Overview'),
+ [child.location for child in self.import_course.get_children()])
+ self.assertEquals(1, len(self.import_course.get_children()))
+
+ @override_settings(MITX_FEATURES={'GITHUB_PUSH': False})
+ def test_export_no_pash(self):
+ """
+ Test that with the GITHUB_PUSH feature disabled, no content is pushed to the remote
+ """
+ export_to_github(self.import_course, self.repo_dir, 'Test no-push')
+ self.assertEquals(1, Repo(self.remote_dir).head.commit.count())
+
+ @override_settings(MITX_FEATURES={'GITHUB_PUSH': True})
+ def test_export_push(self):
+ """
+ Test that with GITHUB_PUSH enabled, content is pushed to the remote
+ """
+ self.import_course.metadata['display_name'] = 'Changed display name'
+ export_to_github(self.import_course, self.repo_dir, 'Test push')
+ self.assertEquals(2, Repo(self.remote_dir).head.commit.count())
+
+ @override_settings(MITX_FEATURES={'GITHUB_PUSH': True})
+ def test_export_conflict(self):
+ """
+ Test that if there is a conflict when pushing to the remote repo, nothing is pushed and an exception is raised
+ """
+ self.import_course.metadata['display_name'] = 'Changed display name'
+
+ remote = Repo(self.remote_dir)
+ remote.git.commit(allow_empty=True, m="Testing conflict commit")
+
+ self.assertRaises(GithubSyncError, export_to_github, self.import_course, self.repo_dir, 'Test push')
+ self.assertEquals(2, remote.head.reference.commit.count())
+ self.assertEquals("Testing conflict commit\n", remote.head.reference.commit.message)
+
+
+@override_settings(REPOS={'namea': {'path': 'patha', 'org': 'orga', 'course': 'coursea'},
+ 'nameb': {'path': 'pathb', 'org': 'orgb', 'course': 'courseb'}})
+class RepoPathLookupTestCase(TestCase):
+ def test_successful_lookup(self):
+ self.assertEquals('patha', repo_path_from_location('i4x://orga/coursea/course/foo'))
+ self.assertEquals('pathb', repo_path_from_location('i4x://orgb/courseb/course/foo'))
+
+ def test_failed_lookup(self):
+ self.assertEquals(None, repo_path_from_location('i4x://c/c/course/foo'))
diff --git a/cms/envs/test.py b/cms/envs/test.py
index 032de92953..927e2af987 100644
--- a/cms/envs/test.py
+++ b/cms/envs/test.py
@@ -17,10 +17,18 @@ for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
NOSE_ARGS += ['--cover-package', app]
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
+TEST_ROOT = 'test_root'
+
MODULESTORE = {
- 'host': 'localhost',
- 'db': 'mongo_base',
- 'collection': 'key_store',
+ 'default': {
+ 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore',
+ 'OPTIONS': {
+ 'default_class': 'xmodule.raw_module.RawDescriptor',
+ 'host': 'localhost',
+ 'db': 'test_xmodule',
+ 'collection': 'modulestore',
+ }
+ }
}
DATABASES = {
diff --git a/common/test/data/toy/toy_course.xml b/common/test/data/toy/course.xml
similarity index 100%
rename from common/test/data/toy/toy_course.xml
rename to common/test/data/toy/course.xml
diff --git a/requirements.txt b/requirements.txt
index ddf218af7c..571c530a2f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -29,3 +29,4 @@ django_nose
nosexcover
rednose
GitPython >= 0.3
+django-override-settings
diff --git a/test_root/.gitignore b/test_root/.gitignore
new file mode 100644
index 0000000000..b3e5512f73
--- /dev/null
+++ b/test_root/.gitignore
@@ -0,0 +1,2 @@
+local_repo
+remote_repo
From 386acbe1ff755d6cf11eb696c592dcf4cff55a3b Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 5 Jul 2012 12:15:49 -0400
Subject: [PATCH 081/129] Add tests of the github_sync service hook view
---
.../github_sync/tests/test_views.py | 53 +++++++++++++++++++
requirements.txt | 1 +
2 files changed, 54 insertions(+)
create mode 100644 cms/djangoapps/github_sync/tests/test_views.py
diff --git a/cms/djangoapps/github_sync/tests/test_views.py b/cms/djangoapps/github_sync/tests/test_views.py
new file mode 100644
index 0000000000..9e8095a67b
--- /dev/null
+++ b/cms/djangoapps/github_sync/tests/test_views.py
@@ -0,0 +1,53 @@
+import json
+from django.test.client import Client
+from django.test import TestCase
+from mock import patch, Mock
+from override_settings import override_settings
+from django.conf import settings
+
+
+@override_settings(REPOS={'repo': {'path': 'path', 'branch': 'branch'}})
+class PostReceiveTestCase(TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ @patch('github_sync.views.export_to_github')
+ @patch('github_sync.views.import_from_github')
+ def test_non_branch(self, import_from_github, export_to_github):
+ self.client.post('/github_service_hook', {'payload': json.dumps({
+ 'ref': 'refs/tags/foo'})
+ })
+ self.assertFalse(import_from_github.called)
+ self.assertFalse(export_to_github.called)
+
+ @patch('github_sync.views.export_to_github')
+ @patch('github_sync.views.import_from_github')
+ def test_non_watched_repo(self, import_from_github, export_to_github):
+ self.client.post('/github_service_hook', {'payload': json.dumps({
+ 'ref': 'refs/heads/branch',
+ 'repository': {'name': 'bad_repo'}})
+ })
+ self.assertFalse(import_from_github.called)
+ self.assertFalse(export_to_github.called)
+
+ @patch('github_sync.views.export_to_github')
+ @patch('github_sync.views.import_from_github')
+ def test_non_tracked_branch(self, import_from_github, export_to_github):
+ self.client.post('/github_service_hook', {'payload': json.dumps({
+ 'ref': 'refs/heads/non_branch',
+ 'repository': {'name': 'repo'}})
+ })
+ self.assertFalse(import_from_github.called)
+ self.assertFalse(export_to_github.called)
+
+ @patch('github_sync.views.export_to_github')
+ @patch('github_sync.views.import_from_github', return_value=(Mock(), Mock()))
+ def test_tracked_branch(self, import_from_github, export_to_github):
+ self.client.post('/github_service_hook', {'payload': json.dumps({
+ 'ref': 'refs/heads/branch',
+ 'repository': {'name': 'repo'}})
+ })
+ import_from_github.assert_called_with(settings.REPOS['repo'])
+ mock_revision, mock_course = import_from_github.return_value
+ export_to_github.assert_called_with(mock_course, 'path', "Changes from cms import of revision %s" % mock_revision)
+
diff --git a/requirements.txt b/requirements.txt
index 571c530a2f..d342c46859 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -30,3 +30,4 @@ nosexcover
rednose
GitPython >= 0.3
django-override-settings
+mock>=0.8, <0.9
From e9ee1566d6311de8a29c9aa0659f4f94a325c381 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 5 Jul 2012 12:48:18 -0400
Subject: [PATCH 082/129] Modularize capa and mitxmako so that xmodule can
properly depend on them
---
common/lib/capa/{ => capa}/__init__.py | 0
common/lib/capa/{ => capa}/calc.py | 0
common/lib/capa/{ => capa}/capa_problem.py | 0
common/lib/capa/{ => capa}/checker.py | 0
common/lib/capa/{ => capa}/correctmap.py | 0
common/lib/capa/{ => capa}/eia.py | 0
common/lib/capa/{ => capa}/inputtypes.py | 0
common/lib/capa/{ => capa}/responsetypes.py | 0
common/lib/capa/{ => capa}/templates/choicegroup.html | 0
common/lib/capa/{ => capa}/templates/imageinput.html | 0
common/lib/capa/{ => capa}/templates/jstextline.html | 0
common/lib/capa/{ => capa}/templates/mathstring.html | 0
common/lib/capa/{ => capa}/templates/schematicinput.html | 0
common/lib/capa/{ => capa}/templates/solutionspan.html | 0
common/lib/capa/{ => capa}/templates/textbox.html | 0
common/lib/capa/{ => capa}/templates/textinput.html | 0
.../lib/capa/{ => capa}/templates/textinput_dynamath.html | 0
common/lib/capa/{ => capa}/util.py | 0
common/lib/capa/setup.py | 8 ++++++++
common/lib/mitxmako/{ => mitxmako}/__init__.py | 0
common/lib/mitxmako/{ => mitxmako}/middleware.py | 0
common/lib/mitxmako/{ => mitxmako}/shortcuts.py | 0
common/lib/mitxmako/{ => mitxmako}/template.py | 0
common/lib/mitxmako/setup.py | 8 ++++++++
common/lib/xmodule/setup.py | 4 ++++
requirements.txt | 2 ++
26 files changed, 22 insertions(+)
rename common/lib/capa/{ => capa}/__init__.py (100%)
rename common/lib/capa/{ => capa}/calc.py (100%)
rename common/lib/capa/{ => capa}/capa_problem.py (100%)
rename common/lib/capa/{ => capa}/checker.py (100%)
rename common/lib/capa/{ => capa}/correctmap.py (100%)
rename common/lib/capa/{ => capa}/eia.py (100%)
rename common/lib/capa/{ => capa}/inputtypes.py (100%)
rename common/lib/capa/{ => capa}/responsetypes.py (100%)
rename common/lib/capa/{ => capa}/templates/choicegroup.html (100%)
rename common/lib/capa/{ => capa}/templates/imageinput.html (100%)
rename common/lib/capa/{ => capa}/templates/jstextline.html (100%)
rename common/lib/capa/{ => capa}/templates/mathstring.html (100%)
rename common/lib/capa/{ => capa}/templates/schematicinput.html (100%)
rename common/lib/capa/{ => capa}/templates/solutionspan.html (100%)
rename common/lib/capa/{ => capa}/templates/textbox.html (100%)
rename common/lib/capa/{ => capa}/templates/textinput.html (100%)
rename common/lib/capa/{ => capa}/templates/textinput_dynamath.html (100%)
rename common/lib/capa/{ => capa}/util.py (100%)
create mode 100644 common/lib/capa/setup.py
rename common/lib/mitxmako/{ => mitxmako}/__init__.py (100%)
rename common/lib/mitxmako/{ => mitxmako}/middleware.py (100%)
rename common/lib/mitxmako/{ => mitxmako}/shortcuts.py (100%)
rename common/lib/mitxmako/{ => mitxmako}/template.py (100%)
create mode 100644 common/lib/mitxmako/setup.py
diff --git a/common/lib/capa/__init__.py b/common/lib/capa/capa/__init__.py
similarity index 100%
rename from common/lib/capa/__init__.py
rename to common/lib/capa/capa/__init__.py
diff --git a/common/lib/capa/calc.py b/common/lib/capa/capa/calc.py
similarity index 100%
rename from common/lib/capa/calc.py
rename to common/lib/capa/capa/calc.py
diff --git a/common/lib/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py
similarity index 100%
rename from common/lib/capa/capa_problem.py
rename to common/lib/capa/capa/capa_problem.py
diff --git a/common/lib/capa/checker.py b/common/lib/capa/capa/checker.py
similarity index 100%
rename from common/lib/capa/checker.py
rename to common/lib/capa/capa/checker.py
diff --git a/common/lib/capa/correctmap.py b/common/lib/capa/capa/correctmap.py
similarity index 100%
rename from common/lib/capa/correctmap.py
rename to common/lib/capa/capa/correctmap.py
diff --git a/common/lib/capa/eia.py b/common/lib/capa/capa/eia.py
similarity index 100%
rename from common/lib/capa/eia.py
rename to common/lib/capa/capa/eia.py
diff --git a/common/lib/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py
similarity index 100%
rename from common/lib/capa/inputtypes.py
rename to common/lib/capa/capa/inputtypes.py
diff --git a/common/lib/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py
similarity index 100%
rename from common/lib/capa/responsetypes.py
rename to common/lib/capa/capa/responsetypes.py
diff --git a/common/lib/capa/templates/choicegroup.html b/common/lib/capa/capa/templates/choicegroup.html
similarity index 100%
rename from common/lib/capa/templates/choicegroup.html
rename to common/lib/capa/capa/templates/choicegroup.html
diff --git a/common/lib/capa/templates/imageinput.html b/common/lib/capa/capa/templates/imageinput.html
similarity index 100%
rename from common/lib/capa/templates/imageinput.html
rename to common/lib/capa/capa/templates/imageinput.html
diff --git a/common/lib/capa/templates/jstextline.html b/common/lib/capa/capa/templates/jstextline.html
similarity index 100%
rename from common/lib/capa/templates/jstextline.html
rename to common/lib/capa/capa/templates/jstextline.html
diff --git a/common/lib/capa/templates/mathstring.html b/common/lib/capa/capa/templates/mathstring.html
similarity index 100%
rename from common/lib/capa/templates/mathstring.html
rename to common/lib/capa/capa/templates/mathstring.html
diff --git a/common/lib/capa/templates/schematicinput.html b/common/lib/capa/capa/templates/schematicinput.html
similarity index 100%
rename from common/lib/capa/templates/schematicinput.html
rename to common/lib/capa/capa/templates/schematicinput.html
diff --git a/common/lib/capa/templates/solutionspan.html b/common/lib/capa/capa/templates/solutionspan.html
similarity index 100%
rename from common/lib/capa/templates/solutionspan.html
rename to common/lib/capa/capa/templates/solutionspan.html
diff --git a/common/lib/capa/templates/textbox.html b/common/lib/capa/capa/templates/textbox.html
similarity index 100%
rename from common/lib/capa/templates/textbox.html
rename to common/lib/capa/capa/templates/textbox.html
diff --git a/common/lib/capa/templates/textinput.html b/common/lib/capa/capa/templates/textinput.html
similarity index 100%
rename from common/lib/capa/templates/textinput.html
rename to common/lib/capa/capa/templates/textinput.html
diff --git a/common/lib/capa/templates/textinput_dynamath.html b/common/lib/capa/capa/templates/textinput_dynamath.html
similarity index 100%
rename from common/lib/capa/templates/textinput_dynamath.html
rename to common/lib/capa/capa/templates/textinput_dynamath.html
diff --git a/common/lib/capa/util.py b/common/lib/capa/capa/util.py
similarity index 100%
rename from common/lib/capa/util.py
rename to common/lib/capa/capa/util.py
diff --git a/common/lib/capa/setup.py b/common/lib/capa/setup.py
new file mode 100644
index 0000000000..cf66229b88
--- /dev/null
+++ b/common/lib/capa/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup, find_packages
+
+setup(
+ name="capa",
+ version="0.1",
+ packages=find_packages(exclude=["tests"]),
+ install_requires=['distribute'],
+)
diff --git a/common/lib/mitxmako/__init__.py b/common/lib/mitxmako/mitxmako/__init__.py
similarity index 100%
rename from common/lib/mitxmako/__init__.py
rename to common/lib/mitxmako/mitxmako/__init__.py
diff --git a/common/lib/mitxmako/middleware.py b/common/lib/mitxmako/mitxmako/middleware.py
similarity index 100%
rename from common/lib/mitxmako/middleware.py
rename to common/lib/mitxmako/mitxmako/middleware.py
diff --git a/common/lib/mitxmako/shortcuts.py b/common/lib/mitxmako/mitxmako/shortcuts.py
similarity index 100%
rename from common/lib/mitxmako/shortcuts.py
rename to common/lib/mitxmako/mitxmako/shortcuts.py
diff --git a/common/lib/mitxmako/template.py b/common/lib/mitxmako/mitxmako/template.py
similarity index 100%
rename from common/lib/mitxmako/template.py
rename to common/lib/mitxmako/mitxmako/template.py
diff --git a/common/lib/mitxmako/setup.py b/common/lib/mitxmako/setup.py
new file mode 100644
index 0000000000..535d86f90e
--- /dev/null
+++ b/common/lib/mitxmako/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup, find_packages
+
+setup(
+ name="mitxmako",
+ version="0.1",
+ packages=find_packages(exclude=["tests"]),
+ install_requires=['distribute'],
+)
diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py
index 77b0838ff2..1ce23bca90 100644
--- a/common/lib/xmodule/setup.py
+++ b/common/lib/xmodule/setup.py
@@ -8,6 +8,10 @@ setup(
package_data={
'xmodule': ['js/module/*']
},
+ requires=[
+ 'capa',
+ 'mitxmako'
+ ],
# See http://guide.python-distribute.org/creation.html#entry-points
# for a description of entry_points
diff --git a/requirements.txt b/requirements.txt
index d342c46859..6f63769ee3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -24,6 +24,8 @@ sympy
newrelic
glob2
pymongo
+-e common/lib/capa
+-e common/lib/mitxmako
-e common/lib/xmodule
django_nose
nosexcover
From ce4cea0e3efa116919014f0077fa3c85855dc910 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 5 Jul 2012 13:07:29 -0400
Subject: [PATCH 083/129] Don't fail if no NOSE_COVER_HTML_DIR is set
---
lms/envs/test.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lms/envs/test.py b/lms/envs/test.py
index 941b855f5c..aed49d43de 100644
--- a/lms/envs/test.py
+++ b/lms/envs/test.py
@@ -20,7 +20,8 @@ INSTALLED_APPS = [
# Nose Test Runner
INSTALLED_APPS += ['django_nose']
-NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html', '--cover-inclusive', '--cover-html-dir', os.environ['NOSE_COVER_HTML_DIR']]
+NOSE_ARGS = ['--cover-erase', '--with-xunit', '--with-xcoverage', '--cover-html',
+ '--cover-inclusive', '--cover-html-dir', os.environ.get('NOSE_COVER_HTML_DIR', 'cover_html')]
for app in os.listdir(PROJECT_ROOT / 'djangoapps'):
NOSE_ARGS += ['--cover-package', app]
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
From dbd82c4bc8a8c56de88adda994297d678f350487 Mon Sep 17 00:00:00 2001
From: Calen Pennington
Date: Thu, 5 Jul 2012 13:07:54 -0400
Subject: [PATCH 084/129] Install numpy before trying to install scipy from
requirements.txt
---
requirements.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/requirements.txt b/requirements.txt
index 6f63769ee3..efc8e48ddd 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,6 @@
django<1.4
pip
+numpy
scipy
matplotlib
markdown
From a9aa5d9ea0c62376622ab08066ad75133d484ac0 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 14:44:01 -0400
Subject: [PATCH 085/129] Update code base on changes in master
---
cms/static/coffee/src/views/week.coffee | 2 +-
cms/templates/widgets/navigation.html | 4 ++--
cms/templates/widgets/sequence-edit.html | 2 +-
common/lib/xmodule/xmodule/js/module/html.coffee | 6 +++---
common/lib/xmodule/xmodule/js/module/raw.coffee | 6 +++---
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index e07b159a46..f81a76c369 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -1,6 +1,6 @@
class CMS.Views.Week extends Backbone.View
events:
- 'click .module-edit': 'edit'
+ 'click .week-edit': 'edit'
initialize: ->
@model = new CMS.Models.Week(id: @$el.data('id'))
diff --git a/cms/templates/widgets/navigation.html b/cms/templates/widgets/navigation.html
index dca9177860..e67894d3e5 100644
--- a/cms/templates/widgets/navigation.html
+++ b/cms/templates/widgets/navigation.html
@@ -38,7 +38,7 @@
% for week in weeks:
-
+
% if 'goals' in week.metadata:
% for goal in week.metadata['goals']:
@@ -52,7 +52,7 @@
% for module in week.get_children():
-
+
${module.name}
handle
diff --git a/cms/templates/widgets/sequence-edit.html b/cms/templates/widgets/sequence-edit.html
index bba45d8856..0b0bfa5f5c 100644
--- a/cms/templates/widgets/sequence-edit.html
+++ b/cms/templates/widgets/sequence-edit.html
@@ -37,7 +37,7 @@
% for child in module.get_children():
- ${child.name}
+ ${child.name}
handle
%endfor
diff --git a/common/lib/xmodule/xmodule/js/module/html.coffee b/common/lib/xmodule/xmodule/js/module/html.coffee
index 5e072c27a3..2d2ab744c7 100644
--- a/common/lib/xmodule/xmodule/js/module/html.coffee
+++ b/common/lib/xmodule/xmodule/js/module/html.coffee
@@ -1,7 +1,7 @@
class @HTML
- constructor: (@id) ->
- @edit_box = $("##{@id} .edit-box")
- @preview = $("##{@id} .preview")
+ constructor: (@element) ->
+ @edit_box = $(".edit-box", @element)
+ @preview = $(".preview", @element)
@edit_box.on('input', =>
@preview.empty().append(@edit_box.val())
)
diff --git a/common/lib/xmodule/xmodule/js/module/raw.coffee b/common/lib/xmodule/xmodule/js/module/raw.coffee
index 1b9e05d6b6..920db47c92 100644
--- a/common/lib/xmodule/xmodule/js/module/raw.coffee
+++ b/common/lib/xmodule/xmodule/js/module/raw.coffee
@@ -1,7 +1,7 @@
class @Raw
- constructor: (@id) ->
- @edit_box = $("##{@id} .edit-box")
- @preview = $("##{@id} .preview")
+ constructor: (@element) ->
+ @edit_box = $(".edit-box", @element)
+ @preview = $(".preview", @element)
@edit_box.on('input', =>
@preview.empty().text(@edit_box.val())
)
From 8cef4f42214d3b0a8d9dc55c6d4aa3866b74f42c Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 15:25:37 -0400
Subject: [PATCH 086/129] Pass in the model into the view when create it
---
cms/static/coffee/src/views/module.coffee | 5 +----
cms/static/coffee/src/views/module_edit.coffee | 7 +++----
cms/static/coffee/src/views/week.coffee | 3 +--
3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/cms/static/coffee/src/views/module.coffee b/cms/static/coffee/src/views/module.coffee
index 63ecabe835..e8d7fd68ee 100644
--- a/cms/static/coffee/src/views/module.coffee
+++ b/cms/static/coffee/src/views/module.coffee
@@ -2,8 +2,5 @@ class CMS.Views.Module extends Backbone.View
events:
"click .module-edit": "edit"
- initialize: ->
- @model = new CMS.Models.Module(id: @$el.data('id'), type: @$el.data('type'))
-
edit: =>
- CMS.replaceView(new CMS.Views.ModuleEdit(model: @model))
+ CMS.replaceView(new CMS.Views.ModuleEdit(model: new CMS.Models.Module(id: @$el.data('id'), type: @$el.data('type'))))
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
index 7611d75fa4..987595ef23 100644
--- a/cms/static/coffee/src/views/module_edit.coffee
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -19,7 +19,6 @@ class CMS.Views.ModuleEdit extends Backbone.View
cancel: ->
CMS.popView()
- editSubmodule: (event) =>
- $el = $(event.target)
- model = new CMS.Models.Module(id: $el.data('id'), type: $el.data('type'))
- CMS.pushView(new CMS.Views.ModuleEdit(model: model))
+ editSubmodule: (event) ->
+ event.preventDefault()
+ CMS.pushView(new CMS.Views.ModuleEdit(model: new CMS.Models.Module(id: $(event.target).data('id'), type: $(event.target).data('type'))))
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index f81a76c369..d1ed4cc6c4 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -3,7 +3,6 @@ class CMS.Views.Week extends Backbone.View
'click .week-edit': 'edit'
initialize: ->
- @model = new CMS.Models.Week(id: @$el.data('id'))
@setHeight()
@$('.editable').inlineEdit()
@$('.editable-textarea').inlineEdit(control: 'textarea')
@@ -15,7 +14,7 @@ class CMS.Views.Week extends Backbone.View
CMS.on('content.hide', @setHeight)
edit: =>
- CMS.replaceView(new CMS.Views.WeekEdit(model: @model))
+ CMS.replaceView(new CMS.Views.WeekEdit(model: new CMS.Models.Week(id: @$el.data('id'))))
setHeight: =>
@$el.height(@options.height)
From 9cb24ccc77e138a7eb42021fe67974878e8d0f0b Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 16:23:04 -0400
Subject: [PATCH 087/129] Remove unneeded trigger
---
cms/static/coffee/src/views/week_edit.coffee | 3 ---
1 file changed, 3 deletions(-)
diff --git a/cms/static/coffee/src/views/week_edit.coffee b/cms/static/coffee/src/views/week_edit.coffee
index 10dd20f393..3082bc9fe2 100644
--- a/cms/static/coffee/src/views/week_edit.coffee
+++ b/cms/static/coffee/src/views/week_edit.coffee
@@ -1,6 +1,3 @@
class CMS.Views.WeekEdit extends Backbone.View
tagName: 'section'
className: 'edit-pane'
-
- initialize: ->
- CMS.trigger('week.edit')
From a86c84a4c515d53945a371681166354a9f0d2955 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 17:21:27 -0400
Subject: [PATCH 088/129] Use Backbone's `render` convention instead
---
cms/static/coffee/src/main.coffee | 2 +-
cms/static/coffee/src/views/course.coffee | 10 ++++++----
cms/static/coffee/src/views/week.coffee | 11 ++++++-----
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/cms/static/coffee/src/main.coffee b/cms/static/coffee/src/main.coffee
index 9fa5f3a392..5da9e9dfab 100644
--- a/cms/static/coffee/src/main.coffee
+++ b/cms/static/coffee/src/main.coffee
@@ -5,7 +5,7 @@
viewStack: []
start: ->
- new CMS.Views.Course el: $('section.main-container')
+ new CMS.Views.Course(el: $('section.main-container')).render()
replaceView: (view) ->
@viewStack = [view]
diff --git a/cms/static/coffee/src/views/course.coffee b/cms/static/coffee/src/views/course.coffee
index 9d32b04d26..86085ffff8 100644
--- a/cms/static/coffee/src/views/course.coffee
+++ b/cms/static/coffee/src/views/course.coffee
@@ -1,14 +1,16 @@
class CMS.Views.Course extends Backbone.View
initialize: ->
- @$('#weeks > li').each (index, week) =>
- new CMS.Views.Week el: week, height: @maxWeekHeight()
-
CMS.on('content.show', @showContent)
CMS.on('content.hide', @hideContent)
+ render: ->
+ @$('#weeks > li').each (index, week) =>
+ new CMS.Views.Week(el: week, height: @maxWeekHeight()).render()
+ return @
+
showContent: (subview) =>
$('body').addClass('content')
- @$('.main-content').html(subview.el)
+ @$('.main-content').html(subview.render().el)
@$('.cal').css height: @contentHeight()
@$('>section').css minHeight: @contentHeight()
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index d1ed4cc6c4..39b4110f7f 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -3,15 +3,16 @@ class CMS.Views.Week extends Backbone.View
'click .week-edit': 'edit'
initialize: ->
+ CMS.on('content.show', @resetHeight)
+ CMS.on('content.hide', @setHeight)
+
+ render: ->
@setHeight()
@$('.editable').inlineEdit()
@$('.editable-textarea').inlineEdit(control: 'textarea')
-
@$('.modules .module').each ->
- new CMS.Views.Module el: this
-
- CMS.on('content.show', @resetHeight)
- CMS.on('content.hide', @setHeight)
+ new CMS.Views.Module(el: this).render()
+ return @
edit: =>
CMS.replaceView(new CMS.Views.WeekEdit(model: new CMS.Models.Week(id: @$el.data('id'))))
From c94d6d1602f02b5bb849285cad0651e64f4e442b Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 17:22:18 -0400
Subject: [PATCH 089/129] No need to append `text` key on HTML module save
---
common/lib/xmodule/xmodule/js/module/html.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/lib/xmodule/xmodule/js/module/html.coffee b/common/lib/xmodule/xmodule/js/module/html.coffee
index 2d2ab744c7..f1497dbb09 100644
--- a/common/lib/xmodule/xmodule/js/module/html.coffee
+++ b/common/lib/xmodule/xmodule/js/module/html.coffee
@@ -6,4 +6,4 @@ class @HTML
@preview.empty().append(@edit_box.val())
)
- save: -> {text: @edit_box.val()}
+ save: -> @edit_box.val()
From f60af340ea8cd2b3015a028b6b618304c6176083 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 18:44:56 -0400
Subject: [PATCH 090/129] Add Jasmine suite to CMS
---
cms/envs/common.py | 14 ++
cms/static/coffee/files.json | 8 +
cms/static/js/jasmine-jquery.js | 315 ++++++++++++++++++++++++++++++++
cms/templates/jasmine/base.html | 66 +++++++
cms/urls.py | 11 +-
5 files changed, 412 insertions(+), 2 deletions(-)
create mode 100644 cms/static/coffee/files.json
create mode 100644 cms/static/js/jasmine-jquery.js
create mode 100644 cms/templates/jasmine/base.html
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 472a59d295..1d036d761a 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -58,6 +58,10 @@ MAKO_TEMPLATES['main'] = [
COMMON_ROOT / 'djangoapps' / 'pipeline_mako' / 'templates'
]
+TEMPLATE_DIRS = (
+ PROJECT_ROOT / "templates",
+)
+
MITX_ROOT_URL = ''
TEMPLATE_CONTEXT_PROCESSORS = (
@@ -68,6 +72,9 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.csrf', # necessary for csrf protection
)
+################################# Jasmine ###################################
+JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
+
################################# Middleware ###################################
# List of finder classes that know how to find static files in
# various locations.
@@ -190,6 +197,10 @@ PIPELINE_JS = {
'module-js': {
'source_filenames': module_js_sources,
'output_filename': 'js/modules.js',
+ },
+ 'spec': {
+ 'source_filenames': [pth.replace(PROJECT_ROOT / 'static/', '') for pth in glob2.glob(PROJECT_ROOT / 'static/coffee/spec/**/*.coffee')],
+ 'output_filename': 'js/spec.js'
}
}
@@ -233,4 +244,7 @@ INSTALLED_APPS = (
# For asset pipelining
'pipeline',
'staticfiles',
+
+ # For testing
+ 'django_jasmine',
)
diff --git a/cms/static/coffee/files.json b/cms/static/coffee/files.json
new file mode 100644
index 0000000000..d3a414edb4
--- /dev/null
+++ b/cms/static/coffee/files.json
@@ -0,0 +1,8 @@
+{
+ "js_files": [
+ "/static/js/jquery.min.js",
+ "/static/js/json2.js",
+ "/static/js/underscore-min.js",
+ "/static/js/backbone-min.js"
+ ]
+}
diff --git a/cms/static/js/jasmine-jquery.js b/cms/static/js/jasmine-jquery.js
new file mode 100644
index 0000000000..d516eb1080
--- /dev/null
+++ b/cms/static/js/jasmine-jquery.js
@@ -0,0 +1,315 @@
+var readFixtures = function() {
+ return jasmine.getFixtures().proxyCallTo_('read', arguments);
+};
+
+var preloadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('preload', arguments);
+};
+
+var loadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('load', arguments);
+};
+
+var setFixtures = function(html) {
+ jasmine.getFixtures().set(html);
+};
+
+var sandbox = function(attributes) {
+ return jasmine.getFixtures().sandbox(attributes);
+};
+
+var spyOnEvent = function(selector, eventName) {
+ jasmine.JQuery.events.spyOn(selector, eventName);
+};
+
+jasmine.getFixtures = function() {
+ return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures();
+};
+
+jasmine.Fixtures = function() {
+ this.containerId = 'jasmine-fixtures';
+ this.fixturesCache_ = {};
+ this.fixturesPath = 'spec/javascripts/fixtures';
+};
+
+jasmine.Fixtures.prototype.set = function(html) {
+ this.cleanUp();
+ this.createContainer_(html);
+};
+
+jasmine.Fixtures.prototype.preload = function() {
+ this.read.apply(this, arguments);
+};
+
+jasmine.Fixtures.prototype.load = function() {
+ this.cleanUp();
+ this.createContainer_(this.read.apply(this, arguments));
+};
+
+jasmine.Fixtures.prototype.read = function() {
+ var htmlChunks = [];
+
+ var fixtureUrls = arguments;
+ for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+ htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]));
+ }
+
+ return htmlChunks.join('');
+};
+
+jasmine.Fixtures.prototype.clearCache = function() {
+ this.fixturesCache_ = {};
+};
+
+jasmine.Fixtures.prototype.cleanUp = function() {
+ jQuery('#' + this.containerId).remove();
+};
+
+jasmine.Fixtures.prototype.sandbox = function(attributes) {
+ var attributesToSet = attributes || {};
+ return jQuery('
').attr(attributesToSet);
+};
+
+jasmine.Fixtures.prototype.createContainer_ = function(html) {
+ var container;
+ if(html instanceof jQuery) {
+ container = jQuery('
');
+ container.html(html);
+ } else {
+ container = '' + html + '
'
+ }
+ jQuery('body').append(container);
+};
+
+jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
+ if (typeof this.fixturesCache_[url] == 'undefined') {
+ this.loadFixtureIntoCache_(url);
+ }
+ return this.fixturesCache_[url];
+};
+
+jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
+ var url = this.makeFixtureUrl_(relativeUrl);
+ var request = new XMLHttpRequest();
+ request.open("GET", url + "?" + new Date().getTime(), false);
+ request.send(null);
+ this.fixturesCache_[relativeUrl] = request.responseText;
+};
+
+jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){
+ return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl;
+};
+
+jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments);
+};
+
+
+jasmine.JQuery = function() {};
+
+jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
+ return jQuery('
').append(html).html();
+};
+
+jasmine.JQuery.elementToString = function(element) {
+ var sample = $(element).get()[0]
+ if (sample == undefined || sample.cloneNode)
+ return jQuery('
').append($(element).clone()).html();
+ else
+ return element.toString();
+};
+
+jasmine.JQuery.matchersClass = {};
+
+(function(namespace) {
+ var data = {
+ spiedEvents: {},
+ handlers: []
+ };
+
+ namespace.events = {
+ spyOn: function(selector, eventName) {
+ var handler = function(e) {
+ data.spiedEvents[[selector, eventName]] = e;
+ };
+ jQuery(selector).bind(eventName, handler);
+ data.handlers.push(handler);
+ },
+
+ wasTriggered: function(selector, eventName) {
+ return !!(data.spiedEvents[[selector, eventName]]);
+ },
+
+ wasPrevented: function(selector, eventName) {
+ return data.spiedEvents[[selector, eventName]].isDefaultPrevented();
+ },
+
+ cleanUp: function() {
+ data.spiedEvents = {};
+ data.handlers = [];
+ }
+ }
+})(jasmine.JQuery);
+
+(function(){
+ var jQueryMatchers = {
+ toHaveClass: function(className) {
+ return this.actual.hasClass(className);
+ },
+
+ toBeVisible: function() {
+ return this.actual.is(':visible');
+ },
+
+ toBeHidden: function() {
+ return this.actual.is(':hidden');
+ },
+
+ toBeSelected: function() {
+ return this.actual.is(':selected');
+ },
+
+ toBeChecked: function() {
+ return this.actual.is(':checked');
+ },
+
+ toBeEmpty: function() {
+ return this.actual.is(':empty');
+ },
+
+ toExist: function() {
+ return $(document).find(this.actual).length;
+ },
+
+ toHaveAttr: function(attributeName, expectedAttributeValue) {
+ return hasProperty(this.actual.attr(attributeName), expectedAttributeValue);
+ },
+
+ toHaveProp: function(propertyName, expectedPropertyValue) {
+ return hasProperty(this.actual.prop(propertyName), expectedPropertyValue);
+ },
+
+ toHaveId: function(id) {
+ return this.actual.attr('id') == id;
+ },
+
+ toHaveHtml: function(html) {
+ return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html);
+ },
+
+ toHaveText: function(text) {
+ var trimmedText = $.trim(this.actual.text());
+ if (text && jQuery.isFunction(text.test)) {
+ return text.test(trimmedText);
+ } else {
+ return trimmedText == text;
+ }
+ },
+
+ toHaveValue: function(value) {
+ return this.actual.val() == value;
+ },
+
+ toHaveData: function(key, expectedValue) {
+ return hasProperty(this.actual.data(key), expectedValue);
+ },
+
+ toBe: function(selector) {
+ return this.actual.is(selector);
+ },
+
+ toContain: function(selector) {
+ return this.actual.find(selector).length;
+ },
+
+ toBeDisabled: function(selector){
+ return this.actual.is(':disabled');
+ },
+
+ toBeFocused: function(selector) {
+ return this.actual.is(':focus');
+ },
+
+ // tests the existence of a specific event binding
+ toHandle: function(eventName) {
+ var events = this.actual.data("events");
+ return events && events[eventName].length > 0;
+ },
+
+ // tests the existence of a specific event binding + handler
+ toHandleWith: function(eventName, eventHandler) {
+ var stack = this.actual.data("events")[eventName];
+ var i;
+ for (i = 0; i < stack.length; i++) {
+ if (stack[i].handler == eventHandler) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ var hasProperty = function(actualValue, expectedValue) {
+ if (expectedValue === undefined) {
+ return actualValue !== undefined;
+ }
+ return actualValue == expectedValue;
+ };
+
+ var bindMatcher = function(methodName) {
+ var builtInMatcher = jasmine.Matchers.prototype[methodName];
+
+ jasmine.JQuery.matchersClass[methodName] = function() {
+ if (this.actual
+ && (this.actual instanceof jQuery
+ || jasmine.isDomNode(this.actual))) {
+ this.actual = $(this.actual);
+ var result = jQueryMatchers[methodName].apply(this, arguments)
+ if (this.actual.get && !$.isWindow(this.actual.get()[0]))
+ this.actual = jasmine.JQuery.elementToString(this.actual)
+ return result;
+ }
+
+ if (builtInMatcher) {
+ return builtInMatcher.apply(this, arguments);
+ }
+
+ return false;
+ };
+ };
+
+ for(var methodName in jQueryMatchers) {
+ bindMatcher(methodName);
+ }
+})();
+
+beforeEach(function() {
+ this.addMatchers(jasmine.JQuery.matchersClass);
+ this.addMatchers({
+ toHaveBeenTriggeredOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been triggered on " + selector,
+ "Expected event " + this.actual + " not to have been triggered on " + selector
+ ];
+ };
+ return jasmine.JQuery.events.wasTriggered($(selector), this.actual);
+ }
+ });
+ this.addMatchers({
+ toHaveBeenPreventedOn: function(selector) {
+ this.message = function() {
+ return [
+ "Expected event " + this.actual + " to have been prevented on " + selector,
+ "Expected event " + this.actual + " not to have been prevented on " + selector
+ ];
+ };
+ return jasmine.JQuery.events.wasPrevented(selector, this.actual);
+ }
+ });
+});
+
+afterEach(function() {
+ jasmine.getFixtures().cleanUp();
+ jasmine.JQuery.events.cleanUp();
+});
diff --git a/cms/templates/jasmine/base.html b/cms/templates/jasmine/base.html
new file mode 100644
index 0000000000..610beda824
--- /dev/null
+++ b/cms/templates/jasmine/base.html
@@ -0,0 +1,66 @@
+
+
+
+
+ Jasmine Spec Runner
+
+ {% load staticfiles %}
+
+
+ {# core files #}
+
+
+
+
+ {# source files #}
+ {% for url in suite.js_files %}
+
+ {% endfor %}
+
+ {% load compressed %}
+ {# static files #}
+ {% compressed_js 'main' %}
+
+ {# spec files #}
+ {% compressed_js 'spec' %}
+
+
+
+
+Jasmine Spec Runner
+
+
+
+
+
diff --git a/cms/urls.py b/cms/urls.py
index 9d827c3fe3..d522ee23a1 100644
--- a/cms/urls.py
+++ b/cms/urls.py
@@ -1,12 +1,19 @@
-from django.conf.urls.defaults import patterns, url
+from django.conf import settings
+from django.conf.urls.defaults import patterns, include, url
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
-urlpatterns = patterns('',
+urlpatterns = ('',
url(r'^$', 'contentstore.views.index', name='index'),
url(r'^edit_item$', 'contentstore.views.edit_item', name='edit_item'),
url(r'^save_item$', 'contentstore.views.save_item', name='save_item'),
url(r'^temp_force_export$', 'contentstore.views.temp_force_export')
)
+
+if settings.DEBUG:
+ ## Jasmine
+ urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),)
+
+urlpatterns = patterns(*urlpatterns)
From d6c033d6751829e1db0cdb89dc6331db2dd142da Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 19:42:10 -0400
Subject: [PATCH 091/129] main.coffee/CMS module tested
---
cms/static/coffee/spec/helpers.coffee | 9 +++
cms/static/coffee/spec/main_spec.coffee | 89 +++++++++++++++++++++++++
cms/static/coffee/src/main.coffee | 2 +-
3 files changed, 99 insertions(+), 1 deletion(-)
create mode 100644 cms/static/coffee/spec/helpers.coffee
create mode 100644 cms/static/coffee/spec/main_spec.coffee
diff --git a/cms/static/coffee/spec/helpers.coffee b/cms/static/coffee/spec/helpers.coffee
new file mode 100644
index 0000000000..a5e24ddf81
--- /dev/null
+++ b/cms/static/coffee/spec/helpers.coffee
@@ -0,0 +1,9 @@
+# Stub jQuery.cookie
+@stubCookies =
+ csrftoken: 'stubCSRFToken'
+
+jQuery.cookie = (key, value) =>
+ if value?
+ @stubCookies[key] = value
+ else
+ @stubCookies[key]
diff --git a/cms/static/coffee/spec/main_spec.coffee b/cms/static/coffee/spec/main_spec.coffee
new file mode 100644
index 0000000000..006fdaa2ad
--- /dev/null
+++ b/cms/static/coffee/spec/main_spec.coffee
@@ -0,0 +1,89 @@
+describe "CMS", ->
+ beforeEach ->
+ CMS.unbind()
+
+ it "should iniitalize Models", ->
+ expect(CMS.Models).toBeDefined()
+
+ it "should initialize Views", ->
+ expect(CMS.Views).toBeDefined()
+
+ describe "start", ->
+ beforeEach ->
+ spyOn(CMS.Views, 'Course').andReturn(jasmine.createSpyObj("Course", ["render"]))
+ CMS.start()
+
+ it "create the Course", ->
+ expect(CMS.Views.Course).toHaveBeenCalled()
+ expect(CMS.Views.Course().render).toHaveBeenCalled()
+
+ describe "view stack", ->
+ beforeEach ->
+ @currentView = jasmine.createSpy("currentView")
+ CMS.viewStack = [@currentView]
+
+ describe "replaceView", ->
+ beforeEach ->
+ @newView = jasmine.createSpy("newView")
+ CMS.on "content.show", (@expectedView) =>
+ CMS.replaceView(@newView)
+
+ it "replace the views on the viewStack", ->
+ expect(CMS.viewStack).toEqual([@newView])
+
+ it "trigger content.show on CMS", ->
+ expect(@expectedView).toEqual(@newView)
+
+ describe "pushView", ->
+ beforeEach ->
+ @newView = jasmine.createSpy("newView")
+ CMS.on "content.show", (@expectedView) =>
+ CMS.pushView(@newView)
+
+ it "push new view onto viewStack", ->
+ expect(CMS.viewStack).toEqual([@currentView, @newView])
+
+ it "trigger content.show on CMS", ->
+ expect(@expectedView).toEqual(@newView)
+
+ describe "popView", ->
+ it "remove the current view from the viewStack", ->
+ CMS.popView()
+ expect(CMS.viewStack).toEqual([])
+
+ describe "when there's no view on the viewStack", ->
+ beforeEach ->
+ CMS.viewStack = [@currentView]
+ CMS.on "content.hide", => @eventTriggered = true
+ CMS.popView()
+
+ it "trigger content.hide on CMS", ->
+ expect(@eventTriggered).toBeTruthy
+
+ describe "when there's previous view on the viewStack", ->
+ beforeEach ->
+ @parentView = jasmine.createSpyObj("parentView", ["delegateEvents"])
+ CMS.viewStack = [@parentView, @currentView]
+ CMS.on "content.show", (@expectedView) =>
+ CMS.popView()
+
+ it "trigger content.show with the previous view on CMS", ->
+ expect(@expectedView).toEqual @parentView
+
+ it "re-bind events on the view", ->
+ expect(@parentView.delegateEvents).toHaveBeenCalled()
+
+describe "main helper", ->
+ beforeEach ->
+ @previousAjaxSettings = $.extend(true, {}, $.ajaxSettings)
+ window.stubCookies["csrftoken"] = "stubCSRFToken"
+ $(document).ready()
+
+ afterEach ->
+ $.ajaxSettings = @previousAjaxSettings
+
+ it "turn on Backbone emulateHTTP", ->
+ expect(Backbone.emulateHTTP).toBeTruthy()
+
+ it "setup AJAX CSRF token", ->
+ expect($.ajaxSettings.headers['X-CSRFToken']).toEqual("stubCSRFToken")
diff --git a/cms/static/coffee/src/main.coffee b/cms/static/coffee/src/main.coffee
index 5da9e9dfab..14433e7468 100644
--- a/cms/static/coffee/src/main.coffee
+++ b/cms/static/coffee/src/main.coffee
@@ -30,6 +30,6 @@ $ ->
Backbone.emulateHTTP = true
$.ajaxSetup
- headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
+ headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
CMS.start()
From 68bb8d5874683115e74bf9f59069abbaa04a1408 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 21:08:09 -0400
Subject: [PATCH 092/129] Patch `window.it` to raise error on pending tests
---
cms/static/coffee/spec/helpers.coffee | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/cms/static/coffee/spec/helpers.coffee b/cms/static/coffee/spec/helpers.coffee
index a5e24ddf81..374f68f2e8 100644
--- a/cms/static/coffee/spec/helpers.coffee
+++ b/cms/static/coffee/spec/helpers.coffee
@@ -7,3 +7,12 @@ jQuery.cookie = (key, value) =>
@stubCookies[key] = value
else
@stubCookies[key]
+
+# Path Jasmine's `it` method to raise an error when the test is not defined.
+# This is helpful when writing the specs first before writing the test.
+@it = (desc, func) ->
+ if func?
+ jasmine.getEnv().it(desc, func)
+ else
+ jasmine.getEnv().it desc, ->
+ throw "test is undefined"
From fe17c377833148b043c7e5763918710f4287ad5c Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 21:31:32 -0400
Subject: [PATCH 093/129] CMS.Models.Module tested
---
.../coffee/spec/models/module_spec.coffee | 65 +++++++++++++++++++
cms/static/coffee/src/models/module.coffee | 2 +-
2 files changed, 66 insertions(+), 1 deletion(-)
create mode 100644 cms/static/coffee/spec/models/module_spec.coffee
diff --git a/cms/static/coffee/spec/models/module_spec.coffee b/cms/static/coffee/spec/models/module_spec.coffee
new file mode 100644
index 0000000000..ff7c4e855d
--- /dev/null
+++ b/cms/static/coffee/spec/models/module_spec.coffee
@@ -0,0 +1,65 @@
+describe "CMS.Models.Module", ->
+ it "set the correct URL", ->
+ expect(new CMS.Models.Module().url).toEqual("/save_item")
+
+ it "set the correct default", ->
+ expect(new CMS.Models.Module().defaults).toEqual({data: ''})
+
+ describe "loadModule", ->
+ describe "when the module exists", ->
+ beforeEach ->
+ @fakeModule = jasmine.createSpy("fakeModuleObject")
+ window.FakeModule = jasmine.createSpy("FakeModule").andReturn(@fakeModule)
+ @module = new CMS.Models.Module(type: "FakeModule")
+ @stubElement = $('')
+ @module.loadModule(@stubElement)
+
+ afterEach ->
+ window.FakeModule = undefined
+
+ it "initialize the module", ->
+ expect(window.FakeModule).toHaveBeenCalledWith(@stubElement)
+ expect(@module.module).toEqual(@fakeModule)
+
+ describe "when the module does not exists", ->
+ beforeEach ->
+ @previousConsole = window.console
+ window.console = jasmine.createSpyObj("fakeConsole", ["error"])
+ @module = new CMS.Models.Module(type: "HTML")
+ @module.loadModule($('
'))
+
+ afterEach ->
+ window.console = @previousConsole
+
+ it "print out error to log", ->
+ expect(window.console.error).toHaveBeenCalledWith("Unable to load HTML.")
+
+
+ describe "editUrl", ->
+ it "construct the correct URL based on id", ->
+ expect(new CMS.Models.Module(id: "i4x://mit.edu/module/html_123").editUrl())
+ .toEqual("/edit_item?id=i4x%3A%2F%2Fmit.edu%2Fmodule%2Fhtml_123")
+
+ describe "save", ->
+ beforeEach ->
+ spyOn(Backbone.Model.prototype, "save")
+ @module = new CMS.Models.Module()
+
+ describe "when the module exists", ->
+ beforeEach ->
+ @module.module = jasmine.createSpyObj("FakeModule", ["save"])
+ @module.module.save.andReturn("module data")
+ @module.save()
+
+ it "set the data and call save on the module", ->
+ expect(@module.get("data")).toEqual("\"module data\"")
+
+ it "call save on the backbone model", ->
+ expect(Backbone.Model.prototype.save).toHaveBeenCalled()
+
+ describe "when the module does not exists", ->
+ beforeEach ->
+ @module.save()
+
+ it "call save on the backbone model", ->
+ expect(Backbone.Model.prototype.save).toHaveBeenCalled()
diff --git a/cms/static/coffee/src/models/module.coffee b/cms/static/coffee/src/models/module.coffee
index dbcc412d5c..257eca411e 100644
--- a/cms/static/coffee/src/models/module.coffee
+++ b/cms/static/coffee/src/models/module.coffee
@@ -1,7 +1,7 @@
class CMS.Models.Module extends Backbone.Model
url: '/save_item'
defaults:
- data: '{}'
+ data: ''
loadModule: (element) ->
try
From 8979b993efab730ccdae4da34b1a1f337f8bad08 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 21:33:02 -0400
Subject: [PATCH 094/129] Add blank spec for CMS.Models.Week
---
cms/static/coffee/spec/models/week_spec.coffee | 1 +
1 file changed, 1 insertion(+)
create mode 100644 cms/static/coffee/spec/models/week_spec.coffee
diff --git a/cms/static/coffee/spec/models/week_spec.coffee b/cms/static/coffee/spec/models/week_spec.coffee
new file mode 100644
index 0000000000..fa6b78e888
--- /dev/null
+++ b/cms/static/coffee/spec/models/week_spec.coffee
@@ -0,0 +1 @@
+describe "CMS.Models.Week", ->
From 4d29c311c76b2885cd686497814747fc3ef61da8 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 22:50:23 -0400
Subject: [PATCH 095/129] CMS.Views.WeekEdit tested
---
cms/static/coffee/spec/views/week_edit_spec.coffee | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 cms/static/coffee/spec/views/week_edit_spec.coffee
diff --git a/cms/static/coffee/spec/views/week_edit_spec.coffee b/cms/static/coffee/spec/views/week_edit_spec.coffee
new file mode 100644
index 0000000000..754474d77f
--- /dev/null
+++ b/cms/static/coffee/spec/views/week_edit_spec.coffee
@@ -0,0 +1,7 @@
+describe "CMS.Views.WeekEdit", ->
+ describe "defaults", ->
+ it "set the correct tagName", ->
+ expect(new CMS.Views.WeekEdit().tagName).toEqual("section")
+
+ it "set the correct className", ->
+ expect(new CMS.Views.WeekEdit().className).toEqual("edit-pane")
From 4d4a856c4bd9ef0f89c3243d01056e4ddde97f4a Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 22:50:46 -0400
Subject: [PATCH 096/129] CMS.Views.Module tested
---
.../coffee/spec/views/module_spec.coffee | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 cms/static/coffee/spec/views/module_spec.coffee
diff --git a/cms/static/coffee/spec/views/module_spec.coffee b/cms/static/coffee/spec/views/module_spec.coffee
new file mode 100644
index 0000000000..a42c06856c
--- /dev/null
+++ b/cms/static/coffee/spec/views/module_spec.coffee
@@ -0,0 +1,24 @@
+describe "CMS.Views.Module", ->
+ beforeEach ->
+ setFixtures """
+
+ """
+
+ describe "edit", ->
+ beforeEach ->
+ @view = new CMS.Views.Module(el: $("#module"))
+ spyOn(CMS, "replaceView")
+ spyOn(CMS.Views, "ModuleEdit")
+ .andReturn(@view = jasmine.createSpy("Views.ModuleEdit"))
+ spyOn(CMS.Models, "Module")
+ .andReturn(@model = jasmine.createSpy("Models.Module"))
+ $(".module-edit").click()
+
+ it "replace the main view with ModuleEdit view", ->
+ expect(CMS.replaceView).toHaveBeenCalledWith @view
+ expect(CMS.Views.ModuleEdit).toHaveBeenCalledWith model: @model
+ expect(CMS.Models.Module).toHaveBeenCalledWith
+ id: "i4x://mitx.edu/course/module"
+ type: "html"
From a77e7fe57b4b0f339eafe2cc3319f6299f5839d2 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 23:31:21 -0400
Subject: [PATCH 097/129] Update jasmine-jquery for newer features
---
cms/static/js/jasmine-jquery.js | 339 ++++++++++++++++++--------------
1 file changed, 195 insertions(+), 144 deletions(-)
diff --git a/cms/static/js/jasmine-jquery.js b/cms/static/js/jasmine-jquery.js
index d516eb1080..f1b2c138c6 100644
--- a/cms/static/js/jasmine-jquery.js
+++ b/cms/static/js/jasmine-jquery.js
@@ -1,315 +1,366 @@
var readFixtures = function() {
- return jasmine.getFixtures().proxyCallTo_('read', arguments);
-};
+ return jasmine.getFixtures().proxyCallTo_('read', arguments)
+}
var preloadFixtures = function() {
- jasmine.getFixtures().proxyCallTo_('preload', arguments);
-};
+ jasmine.getFixtures().proxyCallTo_('preload', arguments)
+}
var loadFixtures = function() {
- jasmine.getFixtures().proxyCallTo_('load', arguments);
-};
+ jasmine.getFixtures().proxyCallTo_('load', arguments)
+}
+
+var appendLoadFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
+}
var setFixtures = function(html) {
- jasmine.getFixtures().set(html);
-};
+ jasmine.getFixtures().proxyCallTo_('set', arguments)
+}
+
+var appendSetFixtures = function() {
+ jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
+}
var sandbox = function(attributes) {
- return jasmine.getFixtures().sandbox(attributes);
-};
+ return jasmine.getFixtures().sandbox(attributes)
+}
var spyOnEvent = function(selector, eventName) {
- jasmine.JQuery.events.spyOn(selector, eventName);
-};
+ jasmine.JQuery.events.spyOn(selector, eventName)
+}
jasmine.getFixtures = function() {
- return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures();
-};
+ return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures()
+}
jasmine.Fixtures = function() {
- this.containerId = 'jasmine-fixtures';
- this.fixturesCache_ = {};
- this.fixturesPath = 'spec/javascripts/fixtures';
-};
+ this.containerId = 'jasmine-fixtures'
+ this.fixturesCache_ = {}
+ this.fixturesPath = 'spec/javascripts/fixtures'
+}
jasmine.Fixtures.prototype.set = function(html) {
- this.cleanUp();
- this.createContainer_(html);
-};
+ this.cleanUp()
+ this.createContainer_(html)
+}
+
+jasmine.Fixtures.prototype.appendSet= function(html) {
+ this.addToContainer_(html)
+}
jasmine.Fixtures.prototype.preload = function() {
- this.read.apply(this, arguments);
-};
+ this.read.apply(this, arguments)
+}
jasmine.Fixtures.prototype.load = function() {
- this.cleanUp();
- this.createContainer_(this.read.apply(this, arguments));
-};
+ this.cleanUp()
+ this.createContainer_(this.read.apply(this, arguments))
+}
+
+jasmine.Fixtures.prototype.appendLoad = function() {
+ this.addToContainer_(this.read.apply(this, arguments))
+}
jasmine.Fixtures.prototype.read = function() {
- var htmlChunks = [];
+ var htmlChunks = []
- var fixtureUrls = arguments;
+ var fixtureUrls = arguments
for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
- htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]));
+ htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]))
}
- return htmlChunks.join('');
-};
+ return htmlChunks.join('')
+}
jasmine.Fixtures.prototype.clearCache = function() {
- this.fixturesCache_ = {};
-};
+ this.fixturesCache_ = {}
+}
jasmine.Fixtures.prototype.cleanUp = function() {
- jQuery('#' + this.containerId).remove();
-};
+ jQuery('#' + this.containerId).remove()
+}
jasmine.Fixtures.prototype.sandbox = function(attributes) {
- var attributesToSet = attributes || {};
- return jQuery('
').attr(attributesToSet);
-};
+ var attributesToSet = attributes || {}
+ return jQuery('
').attr(attributesToSet)
+}
jasmine.Fixtures.prototype.createContainer_ = function(html) {
- var container;
+ var container
if(html instanceof jQuery) {
- container = jQuery('
');
- container.html(html);
+ container = jQuery('
')
+ container.html(html)
} else {
container = '' + html + '
'
}
- jQuery('body').append(container);
-};
+ jQuery('body').append(container)
+}
+
+jasmine.Fixtures.prototype.addToContainer_ = function(html){
+ var container = jQuery('body').find('#'+this.containerId).append(html)
+ if(!container.length){
+ this.createContainer_(html)
+ }
+}
jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
- if (typeof this.fixturesCache_[url] == 'undefined') {
- this.loadFixtureIntoCache_(url);
+ if (typeof this.fixturesCache_[url] === 'undefined') {
+ this.loadFixtureIntoCache_(url)
}
- return this.fixturesCache_[url];
-};
+ return this.fixturesCache_[url]
+}
jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
- var url = this.makeFixtureUrl_(relativeUrl);
- var request = new XMLHttpRequest();
- request.open("GET", url + "?" + new Date().getTime(), false);
- request.send(null);
- this.fixturesCache_[relativeUrl] = request.responseText;
-};
+ var url = this.makeFixtureUrl_(relativeUrl)
+ var request = new XMLHttpRequest()
+ request.open("GET", url + "?" + new Date().getTime(), false)
+ request.send(null)
+ this.fixturesCache_[relativeUrl] = request.responseText
+}
jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){
- return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl;
-};
+ return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+}
jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
- return this[methodName].apply(this, passedArguments);
-};
+ return this[methodName].apply(this, passedArguments)
+}
-jasmine.JQuery = function() {};
+jasmine.JQuery = function() {}
jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
- return jQuery('
').append(html).html();
-};
+ return jQuery('
').append(html).html()
+}
jasmine.JQuery.elementToString = function(element) {
- var sample = $(element).get()[0]
- if (sample == undefined || sample.cloneNode)
- return jQuery('
').append($(element).clone()).html();
+ var domEl = $(element).get(0)
+ if (domEl == undefined || domEl.cloneNode)
+ return jQuery('
').append($(element).clone()).html()
else
- return element.toString();
-};
+ return element.toString()
+}
jasmine.JQuery.matchersClass = {};
-(function(namespace) {
+!function(namespace) {
var data = {
spiedEvents: {},
handlers: []
- };
+ }
namespace.events = {
spyOn: function(selector, eventName) {
var handler = function(e) {
- data.spiedEvents[[selector, eventName]] = e;
- };
- jQuery(selector).bind(eventName, handler);
- data.handlers.push(handler);
+ data.spiedEvents[[selector, eventName]] = e
+ }
+ jQuery(selector).bind(eventName, handler)
+ data.handlers.push(handler)
},
wasTriggered: function(selector, eventName) {
- return !!(data.spiedEvents[[selector, eventName]]);
+ return !!(data.spiedEvents[[selector, eventName]])
},
wasPrevented: function(selector, eventName) {
- return data.spiedEvents[[selector, eventName]].isDefaultPrevented();
+ return data.spiedEvents[[selector, eventName]].isDefaultPrevented()
},
cleanUp: function() {
- data.spiedEvents = {};
- data.handlers = [];
+ data.spiedEvents = {}
+ data.handlers = []
}
}
-})(jasmine.JQuery);
+}(jasmine.JQuery)
-(function(){
+!function(){
var jQueryMatchers = {
toHaveClass: function(className) {
- return this.actual.hasClass(className);
+ return this.actual.hasClass(className)
+ },
+
+ toHaveCss: function(css){
+ for (var prop in css){
+ if (this.actual.css(prop) !== css[prop]) return false
+ }
+ return true
},
toBeVisible: function() {
- return this.actual.is(':visible');
+ return this.actual.is(':visible')
},
toBeHidden: function() {
- return this.actual.is(':hidden');
+ return this.actual.is(':hidden')
},
toBeSelected: function() {
- return this.actual.is(':selected');
+ return this.actual.is(':selected')
},
toBeChecked: function() {
- return this.actual.is(':checked');
+ return this.actual.is(':checked')
},
toBeEmpty: function() {
- return this.actual.is(':empty');
+ return this.actual.is(':empty')
},
toExist: function() {
- return $(document).find(this.actual).length;
+ return $(document).find(this.actual).length
},
toHaveAttr: function(attributeName, expectedAttributeValue) {
- return hasProperty(this.actual.attr(attributeName), expectedAttributeValue);
+ return hasProperty(this.actual.attr(attributeName), expectedAttributeValue)
},
toHaveProp: function(propertyName, expectedPropertyValue) {
- return hasProperty(this.actual.prop(propertyName), expectedPropertyValue);
+ return hasProperty(this.actual.prop(propertyName), expectedPropertyValue)
},
toHaveId: function(id) {
- return this.actual.attr('id') == id;
+ return this.actual.attr('id') == id
},
toHaveHtml: function(html) {
- return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html);
+ return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html)
+ },
+
+ toContainHtml: function(html){
+ var actualHtml = this.actual.html()
+ var expectedHtml = jasmine.JQuery.browserTagCaseIndependentHtml(html)
+ return (actualHtml.indexOf(expectedHtml) >= 0)
},
toHaveText: function(text) {
- var trimmedText = $.trim(this.actual.text());
+ var trimmedText = $.trim(this.actual.text())
if (text && jQuery.isFunction(text.test)) {
- return text.test(trimmedText);
+ return text.test(trimmedText)
} else {
- return trimmedText == text;
+ return trimmedText == text
}
},
toHaveValue: function(value) {
- return this.actual.val() == value;
+ return this.actual.val() == value
},
toHaveData: function(key, expectedValue) {
- return hasProperty(this.actual.data(key), expectedValue);
+ return hasProperty(this.actual.data(key), expectedValue)
},
toBe: function(selector) {
- return this.actual.is(selector);
+ return this.actual.is(selector)
},
toContain: function(selector) {
- return this.actual.find(selector).length;
+ return this.actual.find(selector).length
},
toBeDisabled: function(selector){
- return this.actual.is(':disabled');
+ return this.actual.is(':disabled')
},
toBeFocused: function(selector) {
- return this.actual.is(':focus');
+ return this.actual.is(':focus')
},
- // tests the existence of a specific event binding
- toHandle: function(eventName) {
- var events = this.actual.data("events");
- return events && events[eventName].length > 0;
+ toHandle: function(event) {
+
+ var events = this.actual.data('events')
+
+ if(!events || !event || typeof event !== "string") {
+ return false
+ }
+
+ var namespaces = event.split(".")
+ var eventType = namespaces.shift()
+ var sortedNamespaces = namespaces.slice(0).sort()
+ var namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
+
+ if(events[eventType] && namespaces.length) {
+ for(var i = 0; i < events[eventType].length; i++) {
+ var namespace = events[eventType][i].namespace
+ if(namespaceRegExp.test(namespace)) {
+ return true
+ }
+ }
+ } else {
+ return events[eventType] && events[eventType].length > 0
+ }
},
// tests the existence of a specific event binding + handler
toHandleWith: function(eventName, eventHandler) {
- var stack = this.actual.data("events")[eventName];
- var i;
- for (i = 0; i < stack.length; i++) {
- if (stack[i].handler == eventHandler) {
- return true;
- }
+ var stack = this.actual.data("events")[eventName]
+ for (var i = 0; i < stack.length; i++) {
+ if (stack[i].handler == eventHandler) return true
}
- return false;
+ return false
}
- };
+ }
var hasProperty = function(actualValue, expectedValue) {
- if (expectedValue === undefined) {
- return actualValue !== undefined;
- }
- return actualValue == expectedValue;
- };
+ if (expectedValue === undefined) return actualValue !== undefined
+ return actualValue == expectedValue
+ }
var bindMatcher = function(methodName) {
- var builtInMatcher = jasmine.Matchers.prototype[methodName];
+ var builtInMatcher = jasmine.Matchers.prototype[methodName]
jasmine.JQuery.matchersClass[methodName] = function() {
if (this.actual
- && (this.actual instanceof jQuery
- || jasmine.isDomNode(this.actual))) {
- this.actual = $(this.actual);
- var result = jQueryMatchers[methodName].apply(this, arguments)
- if (this.actual.get && !$.isWindow(this.actual.get()[0]))
- this.actual = jasmine.JQuery.elementToString(this.actual)
- return result;
- }
+ && (this.actual instanceof jQuery
+ || jasmine.isDomNode(this.actual))) {
+ this.actual = $(this.actual)
+ var result = jQueryMatchers[methodName].apply(this, arguments)
+ var element;
+ if (this.actual.get && (element = this.actual.get()[0]) && !$.isWindow(element) && element.tagName !== "HTML")
+ this.actual = jasmine.JQuery.elementToString(this.actual)
+ return result
+ }
- if (builtInMatcher) {
- return builtInMatcher.apply(this, arguments);
- }
+ if (builtInMatcher) {
+ return builtInMatcher.apply(this, arguments)
+ }
- return false;
- };
- };
+ return false
+ }
+ }
for(var methodName in jQueryMatchers) {
- bindMatcher(methodName);
+ bindMatcher(methodName)
}
-})();
+}()
beforeEach(function() {
- this.addMatchers(jasmine.JQuery.matchersClass);
+ this.addMatchers(jasmine.JQuery.matchersClass)
this.addMatchers({
toHaveBeenTriggeredOn: function(selector) {
this.message = function() {
return [
"Expected event " + this.actual + " to have been triggered on " + selector,
"Expected event " + this.actual + " not to have been triggered on " + selector
- ];
- };
- return jasmine.JQuery.events.wasTriggered($(selector), this.actual);
+ ]
+ }
+ return jasmine.JQuery.events.wasTriggered($(selector), this.actual)
}
- });
+ })
this.addMatchers({
toHaveBeenPreventedOn: function(selector) {
this.message = function() {
return [
"Expected event " + this.actual + " to have been prevented on " + selector,
"Expected event " + this.actual + " not to have been prevented on " + selector
- ];
- };
- return jasmine.JQuery.events.wasPrevented(selector, this.actual);
+ ]
+ }
+ return jasmine.JQuery.events.wasPrevented(selector, this.actual)
}
- });
-});
+ })
+})
afterEach(function() {
- jasmine.getFixtures().cleanUp();
- jasmine.JQuery.events.cleanUp();
-});
+ jasmine.getFixtures().cleanUp()
+ jasmine.JQuery.events.cleanUp()
+})
From b11b9169065f3bbd0dbf58d1d334e322b3a9ce55 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Thu, 5 Jul 2012 23:31:50 -0400
Subject: [PATCH 098/129] CMS.Views.Course fixed and tested
---
.../coffee/spec/views/course_spec.coffee | 85 +++++++++++++++++++
cms/static/coffee/src/views/course.coffee | 6 +-
2 files changed, 88 insertions(+), 3 deletions(-)
create mode 100644 cms/static/coffee/spec/views/course_spec.coffee
diff --git a/cms/static/coffee/spec/views/course_spec.coffee b/cms/static/coffee/spec/views/course_spec.coffee
new file mode 100644
index 0000000000..f6a430ac2d
--- /dev/null
+++ b/cms/static/coffee/spec/views/course_spec.coffee
@@ -0,0 +1,85 @@
+describe "CMS.Views.Course", ->
+ beforeEach ->
+ setFixtures """
+
+ """
+ CMS.unbind()
+
+ describe "render", ->
+ beforeEach ->
+ spyOn(CMS.Views, "Week").andReturn(jasmine.createSpyObj("Week", ["render"]))
+ new CMS.Views.Course(el: $("#main-section")).render()
+
+ it "create week view for each week",->
+ expect(CMS.Views.Week.calls[0].args[0])
+ .toEqual({ el: $(".week-one").get(0), height: 101 })
+ expect(CMS.Views.Week.calls[1].args[0])
+ .toEqual({ el: $(".week-two").get(0), height: 101 })
+
+ describe "on content.show", ->
+ beforeEach ->
+ @view = new CMS.Views.Course(el: $("#main-section"))
+ @subView = jasmine.createSpyObj("subView", ["render"])
+ @subView.render.andReturn(el: "Subview Content")
+ spyOn(@view, "contentHeight").andReturn(100)
+ CMS.trigger("content.show", @subView)
+
+ afterEach ->
+ $("body").removeClass("content")
+
+ it "add content class to body", ->
+ expect($("body").attr("class")).toEqual("content")
+
+ it "replace content in .main-content", ->
+ expect($(".main-content")).toHaveHtml("Subview Content")
+
+ it "set height on calendar", ->
+ expect($(".cal")).toHaveCss(height: "100px")
+
+ it "set minimum height on all sections", ->
+ expect($("#main-section>section")).toHaveCss(minHeight: "100px")
+
+ describe "on content.hide", ->
+ beforeEach ->
+ $("body").addClass("content")
+ @view = new CMS.Views.Course(el: $("#main-section"))
+ $(".cal").css(height: 100)
+ $("#main-section>section").css(minHeight: 100)
+ CMS.trigger("content.hide")
+
+ afterEach ->
+ $("body").removeClass("content")
+
+ it "remove content class from body", ->
+ expect($("body").attr("class")).toEqual("")
+
+ it "remove content from .main-content", ->
+ expect($(".main-content")).toHaveHtml("")
+
+ it "reset height on calendar", ->
+ expect($(".cal")).not.toHaveCss(height: "100px")
+
+ it "reset minimum height on all sections", ->
+ expect($("#main-section>section")).not.toHaveCss(minHeight: "100px")
+
+ describe "maxWeekHeight", ->
+ it "return maximum height of the week element", ->
+ @view = new CMS.Views.Course(el: $("#main-section"))
+ expect(@view.maxWeekHeight()).toEqual(101)
+
+ describe "contentHeight", ->
+ beforeEach ->
+ $("body").append($('').height(100).hide())
+
+ afterEach ->
+ $("body>header#test").remove()
+
+ it "return the window height minus the header bar", ->
+ @view = new CMS.Views.Course(el: $("#main-section"))
+ expect(@view.contentHeight()).toEqual($(window).height() - 100)
diff --git a/cms/static/coffee/src/views/course.coffee b/cms/static/coffee/src/views/course.coffee
index 86085ffff8..2a5a012c07 100644
--- a/cms/static/coffee/src/views/course.coffee
+++ b/cms/static/coffee/src/views/course.coffee
@@ -21,8 +21,8 @@ class CMS.Views.Course extends Backbone.View
@$('>section').css minHeight: ''
maxWeekHeight: ->
- _.max($('#weeks > li').map -> $(this).height()) + 1
+ weekElementBorderSize = 1
+ _.max($('#weeks > li').map -> $(this).height()) + weekElementBorderSize
contentHeight: ->
- padding = 29
- $(window).height() - padding
+ $(window).height() - $('body>header').outerHeight()
From dd3ddeb9464c37d269bac3a16fd57269778f5bd5 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 00:05:08 -0400
Subject: [PATCH 099/129] CMS.Views.Week is tested
---
cms/static/coffee/spec/views/week_spec.coffee | 71 +++++++++++++++++++
1 file changed, 71 insertions(+)
create mode 100644 cms/static/coffee/spec/views/week_spec.coffee
diff --git a/cms/static/coffee/spec/views/week_spec.coffee b/cms/static/coffee/spec/views/week_spec.coffee
new file mode 100644
index 0000000000..f205a82752
--- /dev/null
+++ b/cms/static/coffee/spec/views/week_spec.coffee
@@ -0,0 +1,71 @@
+describe "CMS.Views.Week", ->
+ beforeEach ->
+ setFixtures """
+
+ """
+ CMS.unbind()
+
+ describe "render", ->
+ beforeEach ->
+ spyOn(CMS.Views, "Module").andReturn(jasmine.createSpyObj("Module", ["render"]))
+ $.fn.inlineEdit = jasmine.createSpy("$.fn.inlineEdit")
+ @view = new CMS.Views.Week(el: $("#week"), height: 100).render()
+
+ it "set the height of the element", ->
+ expect(@view.el).toHaveCss(height: "100px")
+
+ it "make .editable as inline editor", ->
+ expect($.fn.inlineEdit.calls[0].object.get(0))
+ .toEqual($(".editable").get(0))
+
+ it "make .editable-test as inline editor", ->
+ expect($.fn.inlineEdit.calls[1].object.get(0))
+ .toEqual($(".editable-textarea").get(0))
+
+ it "create module subview for each module", ->
+ expect(CMS.Views.Module.calls[0].args[0])
+ .toEqual({ el: $("#module-one").get(0) })
+ expect(CMS.Views.Module.calls[1].args[0])
+ .toEqual({ el: $("#module-two").get(0) })
+
+ describe "edit", ->
+ beforeEach ->
+ @view = new CMS.Views.Week(el: $("#week"), height: 100).render()
+ spyOn(CMS, "replaceView")
+ spyOn(CMS.Views, "WeekEdit")
+ .andReturn(@view = jasmine.createSpy("Views.WeekEdit"))
+ spyOn(CMS.Models, "Week")
+ .andReturn(@model = jasmine.createSpy("Models.Week"))
+ $(".week-edit").click()
+
+ it "replace the content with edit week view", ->
+ expect(CMS.replaceView).toHaveBeenCalledWith @view
+ expect(CMS.Views.WeekEdit).toHaveBeenCalledWith model: @model
+ expect(CMS.Models.Week).toHaveBeenCalledWith
+ id: "i4x://mitx.edu/course/week"
+
+ describe "on content.show", ->
+ beforeEach ->
+ @view = new CMS.Views.Week(el: $("#week"), height: 100).render()
+ @view.$el.height("")
+ @view.setHeight()
+
+ it "set the correct height", ->
+ expect(@view.el).toHaveCss(height: "100px")
+
+ describe "on content.hide", ->
+ beforeEach ->
+ @view = new CMS.Views.Week(el: $("#week"), height: 100).render()
+ @view.$el.height("100px")
+ @view.resetHeight()
+
+ it "remove height from the element", ->
+ expect(@view.el).not.toHaveCss(height: "100px")
From 9ba624683d51eb21e8533f10111a82a3c93d20f8 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 00:32:50 -0400
Subject: [PATCH 100/129] Update Views.ModuleEdit, also added test
---
.../coffee/spec/views/module_edit_spec.coffee | 81 +++++++++++++++++++
.../coffee/src/views/module_edit.coffee | 10 ++-
2 files changed, 88 insertions(+), 3 deletions(-)
create mode 100644 cms/static/coffee/spec/views/module_edit_spec.coffee
diff --git a/cms/static/coffee/spec/views/module_edit_spec.coffee b/cms/static/coffee/spec/views/module_edit_spec.coffee
new file mode 100644
index 0000000000..2aa97e01c5
--- /dev/null
+++ b/cms/static/coffee/spec/views/module_edit_spec.coffee
@@ -0,0 +1,81 @@
+describe "CMS.Views.ModuleEdit", ->
+ beforeEach ->
+ @stubModule = jasmine.createSpyObj("Module", ["editUrl", "loadModule"])
+ spyOn($.fn, "load")
+ setFixtures """
+
+ """
+ CMS.unbind()
+
+ describe "defaults", ->
+ it "set the correct tagName", ->
+ expect(new CMS.Views.ModuleEdit(model: @stubModule).tagName).toEqual("section")
+
+ it "set the correct className", ->
+ expect(new CMS.Views.ModuleEdit(model: @stubModule).className).toEqual("edit-pane")
+
+ describe "view creation", ->
+ beforeEach ->
+ @stubModule.editUrl.andReturn("/edit_item?id=stub_module")
+ new CMS.Views.ModuleEdit(el: $("#module-edit"), model: @stubModule)
+
+ it "load the edit from via ajax and pass to the model", ->
+ expect($.fn.load).toHaveBeenCalledWith("/edit_item?id=stub_module", jasmine.any(Function))
+ if $.fn.load.mostRecentCall
+ $.fn.load.mostRecentCall.args[1]()
+ expect(@stubModule.loadModule).toHaveBeenCalledWith($("#module-edit").get(0))
+
+ describe "save", ->
+ beforeEach ->
+ @stubJqXHR = jasmine.createSpy("stubJqXHR")
+ @stubJqXHR.success = jasmine.createSpy("stubJqXHR.success").andReturn(@stubJqXHR)
+ @stubJqXHR.error= jasmine.createSpy("stubJqXHR.success").andReturn(@stubJqXHR)
+ @stubModule.save = jasmine.createSpy("stubModule.save").andReturn(@stubJqXHR)
+ new CMS.Views.ModuleEdit(el: $("#module-edit"), model: @stubModule)
+ spyOn(window, "alert")
+ $(".save-update").click()
+
+ it "call save on the model", ->
+ expect(@stubModule.save).toHaveBeenCalled()
+
+ it "alert user on success", ->
+ @stubJqXHR.success.mostRecentCall.args[0]()
+ expect(window.alert).toHaveBeenCalledWith("Your changes have been saved.")
+
+ it "alert user on error", ->
+ @stubJqXHR.error.mostRecentCall.args[0]()
+ expect(window.alert).toHaveBeenCalledWith("There was an error saving your changes. Please try again.")
+
+ describe "cancel", ->
+ beforeEach ->
+ spyOn(CMS, 'popView')
+ @view = new CMS.Views.ModuleEdit(el: $("#module-edit"), model: @stubModule)
+ $(".cancel").click()
+
+ it "pop current view from viewStack", ->
+ expect(CMS.popView).toHaveBeenCalled()
+
+ describe "editSubmodule", ->
+ beforeEach ->
+ @view = new CMS.Views.ModuleEdit(el: $("#module-edit"), model: @stubModule)
+ spyOn(CMS, "pushView")
+ spyOn(CMS.Views, "ModuleEdit")
+ .andReturn(@view = jasmine.createSpy("Views.ModuleEdit"))
+ spyOn(CMS.Models, "Module")
+ .andReturn(@model = jasmine.createSpy("Models.Module"))
+ $(".module-edit").click()
+
+ it "push another module editing view into viewStack", ->
+ expect(CMS.pushView).toHaveBeenCalledWith @view
+ expect(CMS.Views.ModuleEdit).toHaveBeenCalledWith model: @model
+ expect(CMS.Models.Module).toHaveBeenCalledWith
+ id: "i4x://mitx.edu/course/module"
+ type: "html"
diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee
index 987595ef23..16968a9126 100644
--- a/cms/static/coffee/src/views/module_edit.coffee
+++ b/cms/static/coffee/src/views/module_edit.coffee
@@ -13,10 +13,14 @@ class CMS.Views.ModuleEdit extends Backbone.View
save: (event) ->
event.preventDefault()
- @model.save().success ->
- console.log "Saved"
+ @model.save().success(->
+ alert("Your changes have been saved.")
+ ).error(->
+ alert("There was an error saving your changes. Please try again.")
+ )
- cancel: ->
+ cancel: (event) ->
+ event.preventDefault()
CMS.popView()
editSubmodule: (event) ->
From 95cf25c1dcc1b0032862f048b9aa26e2de7e316d Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 00:34:54 -0400
Subject: [PATCH 101/129] Fix quote convention in tests
---
cms/static/coffee/spec/helpers.coffee | 2 +-
cms/static/coffee/spec/main_spec.coffee | 4 ++--
cms/static/coffee/spec/models/module_spec.coffee | 6 +++---
cms/static/coffee/spec/views/module_edit_spec.coffee | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/cms/static/coffee/spec/helpers.coffee b/cms/static/coffee/spec/helpers.coffee
index 374f68f2e8..91a411a8fc 100644
--- a/cms/static/coffee/spec/helpers.coffee
+++ b/cms/static/coffee/spec/helpers.coffee
@@ -1,6 +1,6 @@
# Stub jQuery.cookie
@stubCookies =
- csrftoken: 'stubCSRFToken'
+ csrftoken: "stubCSRFToken"
jQuery.cookie = (key, value) =>
if value?
diff --git a/cms/static/coffee/spec/main_spec.coffee b/cms/static/coffee/spec/main_spec.coffee
index 006fdaa2ad..78783ff9a0 100644
--- a/cms/static/coffee/spec/main_spec.coffee
+++ b/cms/static/coffee/spec/main_spec.coffee
@@ -10,7 +10,7 @@ describe "CMS", ->
describe "start", ->
beforeEach ->
- spyOn(CMS.Views, 'Course').andReturn(jasmine.createSpyObj("Course", ["render"]))
+ spyOn(CMS.Views, "Course").andReturn(jasmine.createSpyObj("Course", ["render"]))
CMS.start()
it "create the Course", ->
@@ -86,4 +86,4 @@ describe "main helper", ->
expect(Backbone.emulateHTTP).toBeTruthy()
it "setup AJAX CSRF token", ->
- expect($.ajaxSettings.headers['X-CSRFToken']).toEqual("stubCSRFToken")
+ expect($.ajaxSettings.headers["X-CSRFToken"]).toEqual("stubCSRFToken")
diff --git a/cms/static/coffee/spec/models/module_spec.coffee b/cms/static/coffee/spec/models/module_spec.coffee
index ff7c4e855d..43ebdf420a 100644
--- a/cms/static/coffee/spec/models/module_spec.coffee
+++ b/cms/static/coffee/spec/models/module_spec.coffee
@@ -3,7 +3,7 @@ describe "CMS.Models.Module", ->
expect(new CMS.Models.Module().url).toEqual("/save_item")
it "set the correct default", ->
- expect(new CMS.Models.Module().defaults).toEqual({data: ''})
+ expect(new CMS.Models.Module().defaults).toEqual({data: ""})
describe "loadModule", ->
describe "when the module exists", ->
@@ -11,7 +11,7 @@ describe "CMS.Models.Module", ->
@fakeModule = jasmine.createSpy("fakeModuleObject")
window.FakeModule = jasmine.createSpy("FakeModule").andReturn(@fakeModule)
@module = new CMS.Models.Module(type: "FakeModule")
- @stubElement = $('')
+ @stubElement = $("
")
@module.loadModule(@stubElement)
afterEach ->
@@ -26,7 +26,7 @@ describe "CMS.Models.Module", ->
@previousConsole = window.console
window.console = jasmine.createSpyObj("fakeConsole", ["error"])
@module = new CMS.Models.Module(type: "HTML")
- @module.loadModule($('
'))
+ @module.loadModule($("
"))
afterEach ->
window.console = @previousConsole
diff --git a/cms/static/coffee/spec/views/module_edit_spec.coffee b/cms/static/coffee/spec/views/module_edit_spec.coffee
index 2aa97e01c5..693353ff70 100644
--- a/cms/static/coffee/spec/views/module_edit_spec.coffee
+++ b/cms/static/coffee/spec/views/module_edit_spec.coffee
@@ -56,7 +56,7 @@ describe "CMS.Views.ModuleEdit", ->
describe "cancel", ->
beforeEach ->
- spyOn(CMS, 'popView')
+ spyOn(CMS, "popView")
@view = new CMS.Views.ModuleEdit(el: $("#module-edit"), model: @stubModule)
$(".cancel").click()
From 2a36fee493474b71794a8a22fe5955c9cc4b409f Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 00:38:26 -0400
Subject: [PATCH 102/129] Prevent default click event on links
---
cms/static/coffee/src/views/module.coffee | 3 ++-
cms/static/coffee/src/views/week.coffee | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/cms/static/coffee/src/views/module.coffee b/cms/static/coffee/src/views/module.coffee
index e8d7fd68ee..5407204706 100644
--- a/cms/static/coffee/src/views/module.coffee
+++ b/cms/static/coffee/src/views/module.coffee
@@ -2,5 +2,6 @@ class CMS.Views.Module extends Backbone.View
events:
"click .module-edit": "edit"
- edit: =>
+ edit: (event) =>
+ event.preventDefault()
CMS.replaceView(new CMS.Views.ModuleEdit(model: new CMS.Models.Module(id: @$el.data('id'), type: @$el.data('type'))))
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index 39b4110f7f..18072ddc4f 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -14,7 +14,8 @@ class CMS.Views.Week extends Backbone.View
new CMS.Views.Module(el: this).render()
return @
- edit: =>
+ edit: (event) =>
+ event.preventDefault()
CMS.replaceView(new CMS.Views.WeekEdit(model: new CMS.Models.Week(id: @$el.data('id'))))
setHeight: =>
From 74e01bb07ac4ef0d39c27d10ee02e9ab0ccaf634 Mon Sep 17 00:00:00 2001
From: ichuang
Date: Fri, 6 Jul 2012 09:49:08 -0400
Subject: [PATCH 103/129] fixed two bugs in inputtypes: textline with quotes
crashed problems, and choice without text caused error
---
common/lib/capa/inputtypes.py | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/common/lib/capa/inputtypes.py b/common/lib/capa/inputtypes.py
index d7c0799f75..66ac57c52d 100644
--- a/common/lib/capa/inputtypes.py
+++ b/common/lib/capa/inputtypes.py
@@ -166,7 +166,8 @@ def choicegroup(element, value, status, render_template, msg=''):
raise Exception("[courseware.capa.inputtypes.choicegroup] Error only tags should be immediate children of a , found %s instead" % choice.tag)
ctext = ""
ctext += ''.join([etree.tostring(x) for x in choice]) # TODO: what if choice[0] has math tags in it?
- ctext += choice.text # TODO: fix order?
+ if choice.text is not None:
+ ctext += choice.text # TODO: fix order?
choices[choice.get("name")] = ctext
context={'id':eid, 'value':value, 'state':status, 'type':type, 'choices':choices}
html = render_template("choicegroup.html", context)
@@ -187,9 +188,17 @@ def textline(element, value, status, render_template, msg=""):
count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size')
hidden = element.get('hidden','') # if specified, then textline is hidden and id is stored in div of name given by hidden
+ escapedict = {'"': '"'}
+ value = saxutils.escape(value,escapedict) # otherwise, answers with quotes in them crashes the system!
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg': msg, 'hidden': hidden}
html = render_template("textinput.html", context)
- return etree.XML(html)
+ try:
+ xhtml = etree.XML(html)
+ except Exception as err:
+ if True: # TODO needs to be self.system.DEBUG - but can't access system
+ log.debug('[inputtypes.textline] failed to parse XML for:\n%s' % html)
+ raise
+ return xhtml
#-----------------------------------------------------------------------------
From f71e54cc9b432213d971a4079345dca787dd210f Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 10:53:08 -0400
Subject: [PATCH 104/129] Removed unused Week Model
---
cms/static/coffee/spec/models/week_spec.coffee | 1 -
cms/static/coffee/spec/views/week_spec.coffee | 8 ++------
cms/static/coffee/src/models/week.coffee | 1 -
cms/static/coffee/src/views/week.coffee | 2 +-
4 files changed, 3 insertions(+), 9 deletions(-)
delete mode 100644 cms/static/coffee/spec/models/week_spec.coffee
delete mode 100644 cms/static/coffee/src/models/week.coffee
diff --git a/cms/static/coffee/spec/models/week_spec.coffee b/cms/static/coffee/spec/models/week_spec.coffee
deleted file mode 100644
index fa6b78e888..0000000000
--- a/cms/static/coffee/spec/models/week_spec.coffee
+++ /dev/null
@@ -1 +0,0 @@
-describe "CMS.Models.Week", ->
diff --git a/cms/static/coffee/spec/views/week_spec.coffee b/cms/static/coffee/spec/views/week_spec.coffee
index f205a82752..74b8c22fde 100644
--- a/cms/static/coffee/spec/views/week_spec.coffee
+++ b/cms/static/coffee/spec/views/week_spec.coffee
@@ -38,19 +38,15 @@ describe "CMS.Views.Week", ->
describe "edit", ->
beforeEach ->
- @view = new CMS.Views.Week(el: $("#week"), height: 100).render()
+ new CMS.Views.Week(el: $("#week"), height: 100).render()
spyOn(CMS, "replaceView")
spyOn(CMS.Views, "WeekEdit")
.andReturn(@view = jasmine.createSpy("Views.WeekEdit"))
- spyOn(CMS.Models, "Week")
- .andReturn(@model = jasmine.createSpy("Models.Week"))
$(".week-edit").click()
it "replace the content with edit week view", ->
expect(CMS.replaceView).toHaveBeenCalledWith @view
- expect(CMS.Views.WeekEdit).toHaveBeenCalledWith model: @model
- expect(CMS.Models.Week).toHaveBeenCalledWith
- id: "i4x://mitx.edu/course/week"
+ expect(CMS.Views.WeekEdit).toHaveBeenCalled()
describe "on content.show", ->
beforeEach ->
diff --git a/cms/static/coffee/src/models/week.coffee b/cms/static/coffee/src/models/week.coffee
deleted file mode 100644
index 03e9c5d6f1..0000000000
--- a/cms/static/coffee/src/models/week.coffee
+++ /dev/null
@@ -1 +0,0 @@
-class CMS.Models.Week extends Backbone.Model
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index 18072ddc4f..84a966bfef 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -16,7 +16,7 @@ class CMS.Views.Week extends Backbone.View
edit: (event) =>
event.preventDefault()
- CMS.replaceView(new CMS.Views.WeekEdit(model: new CMS.Models.Week(id: @$el.data('id'))))
+ CMS.replaceView(new CMS.Views.WeekEdit())
setHeight: =>
@$el.height(@options.height)
From 289599733d6bca9258743225d21e12aec49dde5f Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 11:33:00 -0400
Subject: [PATCH 105/129] Make it more obvious that the function is no-op
---
cms/static/coffee/spec/main_spec.coffee | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/cms/static/coffee/spec/main_spec.coffee b/cms/static/coffee/spec/main_spec.coffee
index 78783ff9a0..a9a84da007 100644
--- a/cms/static/coffee/spec/main_spec.coffee
+++ b/cms/static/coffee/spec/main_spec.coffee
@@ -25,7 +25,7 @@ describe "CMS", ->
describe "replaceView", ->
beforeEach ->
@newView = jasmine.createSpy("newView")
- CMS.on "content.show", (@expectedView) =>
+ CMS.on("content.show", (@expectedView) =>)
CMS.replaceView(@newView)
it "replace the views on the viewStack", ->
@@ -37,7 +37,7 @@ describe "CMS", ->
describe "pushView", ->
beforeEach ->
@newView = jasmine.createSpy("newView")
- CMS.on "content.show", (@expectedView) =>
+ CMS.on("content.show", (@expectedView) =>)
CMS.pushView(@newView)
it "push new view onto viewStack", ->
@@ -54,7 +54,7 @@ describe "CMS", ->
describe "when there's no view on the viewStack", ->
beforeEach ->
CMS.viewStack = [@currentView]
- CMS.on "content.hide", => @eventTriggered = true
+ CMS.on("content.hide", => @eventTriggered = true)
CMS.popView()
it "trigger content.hide on CMS", ->
@@ -64,7 +64,7 @@ describe "CMS", ->
beforeEach ->
@parentView = jasmine.createSpyObj("parentView", ["delegateEvents"])
CMS.viewStack = [@parentView, @currentView]
- CMS.on "content.show", (@expectedView) =>
+ CMS.on("content.show", (@expectedView) =>)
CMS.popView()
it "trigger content.show with the previous view on CMS", ->
From b8fd728e061d441ee313b959b38f8a20c93a6c00 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 11:33:37 -0400
Subject: [PATCH 106/129] Pass in element in CMS.start() instead
---
cms/static/coffee/spec/main_spec.coffee | 5 +++--
cms/static/coffee/src/main.coffee | 6 +++---
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/cms/static/coffee/spec/main_spec.coffee b/cms/static/coffee/spec/main_spec.coffee
index a9a84da007..c8f6976fed 100644
--- a/cms/static/coffee/spec/main_spec.coffee
+++ b/cms/static/coffee/spec/main_spec.coffee
@@ -10,11 +10,12 @@ describe "CMS", ->
describe "start", ->
beforeEach ->
+ @element = $("")
spyOn(CMS.Views, "Course").andReturn(jasmine.createSpyObj("Course", ["render"]))
- CMS.start()
+ CMS.start(@element)
it "create the Course", ->
- expect(CMS.Views.Course).toHaveBeenCalled()
+ expect(CMS.Views.Course).toHaveBeenCalledWith(el: @element)
expect(CMS.Views.Course().render).toHaveBeenCalled()
describe "view stack", ->
diff --git a/cms/static/coffee/src/main.coffee b/cms/static/coffee/src/main.coffee
index 14433e7468..b88bc7210b 100644
--- a/cms/static/coffee/src/main.coffee
+++ b/cms/static/coffee/src/main.coffee
@@ -4,8 +4,8 @@
viewStack: []
- start: ->
- new CMS.Views.Course(el: $('section.main-container')).render()
+ start: (el) ->
+ new CMS.Views.Course(el: el).render()
replaceView: (view) ->
@viewStack = [view]
@@ -32,4 +32,4 @@ $ ->
$.ajaxSetup
headers : { 'X-CSRFToken': $.cookie 'csrftoken' }
- CMS.start()
+ CMS.start($('section.main-container'))
From 07aae06d303bda709324c54675d3c2edc6acb972 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 11:52:10 -0400
Subject: [PATCH 107/129] Remove unnecessary fat arrow
---
cms/static/coffee/src/views/week.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cms/static/coffee/src/views/week.coffee b/cms/static/coffee/src/views/week.coffee
index 84a966bfef..8483b9d134 100644
--- a/cms/static/coffee/src/views/week.coffee
+++ b/cms/static/coffee/src/views/week.coffee
@@ -14,7 +14,7 @@ class CMS.Views.Week extends Backbone.View
new CMS.Views.Module(el: this).render()
return @
- edit: (event) =>
+ edit: (event) ->
event.preventDefault()
CMS.replaceView(new CMS.Views.WeekEdit())
From 9dc5cddeb75b32069dfe789af687fc3071d6a66e Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 12:07:21 -0400
Subject: [PATCH 108/129] Move vendored js files into js/vendor/
---
cms/static/coffee/files.json | 8 +++---
cms/static/js/{ => vendor}/backbone-min.js | 0
cms/static/js/{ => vendor}/jasmine-jquery.js | 0
cms/static/js/{ => vendor}/jquery.cookie.js | 0
.../js/{ => vendor}/jquery.inlineedit.js | 0
.../js/{ => vendor}/jquery.leanModal.min.js | 0
cms/static/js/{ => vendor}/jquery.min.js | 0
cms/static/js/{ => vendor}/jquery.tablednd.js | 0
cms/static/js/{ => vendor}/json2.js | 0
.../{ => vendor}/markitup/jquery.markitup.js | 0
.../markitup/sets/wiki/images/bold.png | Bin
.../markitup/sets/wiki/images/clean.png | Bin
.../markitup/sets/wiki/images/code.png | Bin
.../markitup/sets/wiki/images/h1.png | Bin
.../markitup/sets/wiki/images/h2.png | Bin
.../markitup/sets/wiki/images/h3.png | Bin
.../markitup/sets/wiki/images/h4.png | Bin
.../markitup/sets/wiki/images/h5.png | Bin
.../markitup/sets/wiki/images/image.png | Bin
.../markitup/sets/wiki/images/italic.png | Bin
.../markitup/sets/wiki/images/link.png | Bin
.../markitup/sets/wiki/images/list-bullet.png | Bin
.../sets/wiki/images/list-numeric.png | Bin
.../markitup/sets/wiki/images/picture.png | Bin
.../markitup/sets/wiki/images/preview.png | Bin
.../markitup/sets/wiki/images/quotes.png | Bin
.../markitup/sets/wiki/images/stroke.png | Bin
.../markitup/sets/wiki/images/url.png | Bin
.../js/{ => vendor}/markitup/sets/wiki/set.js | 0
.../{ => vendor}/markitup/sets/wiki/style.css | 0
.../markitup/skins/simple/images/handle.png | Bin
.../markitup/skins/simple/images/menu.png | Bin
.../markitup/skins/simple/images/submenu.png | Bin
.../markitup/skins/simple/style.css | 0
cms/static/js/{ => vendor}/underscore-min.js | 0
cms/templates/base.html | 24 +++++++++---------
cms/templates/jasmine/base.html | 2 +-
37 files changed, 17 insertions(+), 17 deletions(-)
rename cms/static/js/{ => vendor}/backbone-min.js (100%)
rename cms/static/js/{ => vendor}/jasmine-jquery.js (100%)
rename cms/static/js/{ => vendor}/jquery.cookie.js (100%)
rename cms/static/js/{ => vendor}/jquery.inlineedit.js (100%)
rename cms/static/js/{ => vendor}/jquery.leanModal.min.js (100%)
rename cms/static/js/{ => vendor}/jquery.min.js (100%)
rename cms/static/js/{ => vendor}/jquery.tablednd.js (100%)
rename cms/static/js/{ => vendor}/json2.js (100%)
rename cms/static/js/{ => vendor}/markitup/jquery.markitup.js (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/bold.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/clean.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/code.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/h1.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/h2.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/h3.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/h4.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/h5.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/image.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/italic.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/link.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/list-bullet.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/list-numeric.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/picture.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/preview.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/quotes.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/stroke.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/images/url.png (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/set.js (100%)
rename cms/static/js/{ => vendor}/markitup/sets/wiki/style.css (100%)
rename cms/static/js/{ => vendor}/markitup/skins/simple/images/handle.png (100%)
rename cms/static/js/{ => vendor}/markitup/skins/simple/images/menu.png (100%)
rename cms/static/js/{ => vendor}/markitup/skins/simple/images/submenu.png (100%)
rename cms/static/js/{ => vendor}/markitup/skins/simple/style.css (100%)
rename cms/static/js/{ => vendor}/underscore-min.js (100%)
diff --git a/cms/static/coffee/files.json b/cms/static/coffee/files.json
index d3a414edb4..b396bec944 100644
--- a/cms/static/coffee/files.json
+++ b/cms/static/coffee/files.json
@@ -1,8 +1,8 @@
{
"js_files": [
- "/static/js/jquery.min.js",
- "/static/js/json2.js",
- "/static/js/underscore-min.js",
- "/static/js/backbone-min.js"
+ "/static/js/vendor/jquery.min.js",
+ "/static/js/vendor/json2.js",
+ "/static/js/vendor/underscore-min.js",
+ "/static/js/vendor/backbone-min.js"
]
}
diff --git a/cms/static/js/backbone-min.js b/cms/static/js/vendor/backbone-min.js
similarity index 100%
rename from cms/static/js/backbone-min.js
rename to cms/static/js/vendor/backbone-min.js
diff --git a/cms/static/js/jasmine-jquery.js b/cms/static/js/vendor/jasmine-jquery.js
similarity index 100%
rename from cms/static/js/jasmine-jquery.js
rename to cms/static/js/vendor/jasmine-jquery.js
diff --git a/cms/static/js/jquery.cookie.js b/cms/static/js/vendor/jquery.cookie.js
similarity index 100%
rename from cms/static/js/jquery.cookie.js
rename to cms/static/js/vendor/jquery.cookie.js
diff --git a/cms/static/js/jquery.inlineedit.js b/cms/static/js/vendor/jquery.inlineedit.js
similarity index 100%
rename from cms/static/js/jquery.inlineedit.js
rename to cms/static/js/vendor/jquery.inlineedit.js
diff --git a/cms/static/js/jquery.leanModal.min.js b/cms/static/js/vendor/jquery.leanModal.min.js
similarity index 100%
rename from cms/static/js/jquery.leanModal.min.js
rename to cms/static/js/vendor/jquery.leanModal.min.js
diff --git a/cms/static/js/jquery.min.js b/cms/static/js/vendor/jquery.min.js
similarity index 100%
rename from cms/static/js/jquery.min.js
rename to cms/static/js/vendor/jquery.min.js
diff --git a/cms/static/js/jquery.tablednd.js b/cms/static/js/vendor/jquery.tablednd.js
similarity index 100%
rename from cms/static/js/jquery.tablednd.js
rename to cms/static/js/vendor/jquery.tablednd.js
diff --git a/cms/static/js/json2.js b/cms/static/js/vendor/json2.js
similarity index 100%
rename from cms/static/js/json2.js
rename to cms/static/js/vendor/json2.js
diff --git a/cms/static/js/markitup/jquery.markitup.js b/cms/static/js/vendor/markitup/jquery.markitup.js
similarity index 100%
rename from cms/static/js/markitup/jquery.markitup.js
rename to cms/static/js/vendor/markitup/jquery.markitup.js
diff --git a/cms/static/js/markitup/sets/wiki/images/bold.png b/cms/static/js/vendor/markitup/sets/wiki/images/bold.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/bold.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/bold.png
diff --git a/cms/static/js/markitup/sets/wiki/images/clean.png b/cms/static/js/vendor/markitup/sets/wiki/images/clean.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/clean.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/clean.png
diff --git a/cms/static/js/markitup/sets/wiki/images/code.png b/cms/static/js/vendor/markitup/sets/wiki/images/code.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/code.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/code.png
diff --git a/cms/static/js/markitup/sets/wiki/images/h1.png b/cms/static/js/vendor/markitup/sets/wiki/images/h1.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/h1.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/h1.png
diff --git a/cms/static/js/markitup/sets/wiki/images/h2.png b/cms/static/js/vendor/markitup/sets/wiki/images/h2.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/h2.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/h2.png
diff --git a/cms/static/js/markitup/sets/wiki/images/h3.png b/cms/static/js/vendor/markitup/sets/wiki/images/h3.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/h3.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/h3.png
diff --git a/cms/static/js/markitup/sets/wiki/images/h4.png b/cms/static/js/vendor/markitup/sets/wiki/images/h4.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/h4.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/h4.png
diff --git a/cms/static/js/markitup/sets/wiki/images/h5.png b/cms/static/js/vendor/markitup/sets/wiki/images/h5.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/h5.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/h5.png
diff --git a/cms/static/js/markitup/sets/wiki/images/image.png b/cms/static/js/vendor/markitup/sets/wiki/images/image.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/image.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/image.png
diff --git a/cms/static/js/markitup/sets/wiki/images/italic.png b/cms/static/js/vendor/markitup/sets/wiki/images/italic.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/italic.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/italic.png
diff --git a/cms/static/js/markitup/sets/wiki/images/link.png b/cms/static/js/vendor/markitup/sets/wiki/images/link.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/link.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/link.png
diff --git a/cms/static/js/markitup/sets/wiki/images/list-bullet.png b/cms/static/js/vendor/markitup/sets/wiki/images/list-bullet.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/list-bullet.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/list-bullet.png
diff --git a/cms/static/js/markitup/sets/wiki/images/list-numeric.png b/cms/static/js/vendor/markitup/sets/wiki/images/list-numeric.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/list-numeric.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/list-numeric.png
diff --git a/cms/static/js/markitup/sets/wiki/images/picture.png b/cms/static/js/vendor/markitup/sets/wiki/images/picture.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/picture.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/picture.png
diff --git a/cms/static/js/markitup/sets/wiki/images/preview.png b/cms/static/js/vendor/markitup/sets/wiki/images/preview.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/preview.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/preview.png
diff --git a/cms/static/js/markitup/sets/wiki/images/quotes.png b/cms/static/js/vendor/markitup/sets/wiki/images/quotes.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/quotes.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/quotes.png
diff --git a/cms/static/js/markitup/sets/wiki/images/stroke.png b/cms/static/js/vendor/markitup/sets/wiki/images/stroke.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/stroke.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/stroke.png
diff --git a/cms/static/js/markitup/sets/wiki/images/url.png b/cms/static/js/vendor/markitup/sets/wiki/images/url.png
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/images/url.png
rename to cms/static/js/vendor/markitup/sets/wiki/images/url.png
diff --git a/cms/static/js/markitup/sets/wiki/set.js b/cms/static/js/vendor/markitup/sets/wiki/set.js
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/set.js
rename to cms/static/js/vendor/markitup/sets/wiki/set.js
diff --git a/cms/static/js/markitup/sets/wiki/style.css b/cms/static/js/vendor/markitup/sets/wiki/style.css
similarity index 100%
rename from cms/static/js/markitup/sets/wiki/style.css
rename to cms/static/js/vendor/markitup/sets/wiki/style.css
diff --git a/cms/static/js/markitup/skins/simple/images/handle.png b/cms/static/js/vendor/markitup/skins/simple/images/handle.png
similarity index 100%
rename from cms/static/js/markitup/skins/simple/images/handle.png
rename to cms/static/js/vendor/markitup/skins/simple/images/handle.png
diff --git a/cms/static/js/markitup/skins/simple/images/menu.png b/cms/static/js/vendor/markitup/skins/simple/images/menu.png
similarity index 100%
rename from cms/static/js/markitup/skins/simple/images/menu.png
rename to cms/static/js/vendor/markitup/skins/simple/images/menu.png
diff --git a/cms/static/js/markitup/skins/simple/images/submenu.png b/cms/static/js/vendor/markitup/skins/simple/images/submenu.png
similarity index 100%
rename from cms/static/js/markitup/skins/simple/images/submenu.png
rename to cms/static/js/vendor/markitup/skins/simple/images/submenu.png
diff --git a/cms/static/js/markitup/skins/simple/style.css b/cms/static/js/vendor/markitup/skins/simple/style.css
similarity index 100%
rename from cms/static/js/markitup/skins/simple/style.css
rename to cms/static/js/vendor/markitup/skins/simple/style.css
diff --git a/cms/static/js/underscore-min.js b/cms/static/js/vendor/underscore-min.js
similarity index 100%
rename from cms/static/js/underscore-min.js
rename to cms/static/js/vendor/underscore-min.js
diff --git a/cms/templates/base.html b/cms/templates/base.html
index 97e4aa8526..eaad889675 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -11,8 +11,8 @@
% else:
% endif
-
-
+
+
<%block name="title">%block>
@@ -23,12 +23,12 @@
<%block name="content">%block>
-
-
-
-
-
-
+
+
+
+
+
+
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:js group='main'/>
% else:
@@ -36,10 +36,10 @@
% endif
<%static:js group='module-js'/>
-
-
-
-
+
+
+
+
diff --git a/cms/templates/jasmine/base.html b/cms/templates/jasmine/base.html
index 610beda824..0cbf63bb29 100644
--- a/cms/templates/jasmine/base.html
+++ b/cms/templates/jasmine/base.html
@@ -10,7 +10,7 @@
{# core files #}
-
+
{# source files #}
{% for url in suite.js_files %}
From 58fc2000c7ec6d4cfe53dda6999b244275420c08 Mon Sep 17 00:00:00 2001
From: Prem Sichanugrist
Date: Fri, 6 Jul 2012 12:13:32 -0400
Subject: [PATCH 109/129] Use `static.url` for static assets
---
cms/templates/base.html | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/cms/templates/base.html b/cms/templates/base.html
index eaad889675..dbae876eca 100644
--- a/cms/templates/base.html
+++ b/cms/templates/base.html
@@ -9,26 +9,26 @@
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:css group='base-style'/>
% else:
-
+
% endif
-
-
+
+
<%block name="title">%block>
- <%include file="widgets/header.html"/>
+ <%include file="widgets/header.html"/>
- <%block name="content">%block>
+ <%block name="content">%block>
-
-
-
-
-
-
+
+
+
+
+
+
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:js group='main'/>
% else:
@@ -36,10 +36,10 @@
% endif
<%static:js group='module-js'/>
-
-
-
-
+
+
+
+