diff --git a/src/main/webapp/WEB-INF/pages/main_new.jsp b/src/main/webapp/WEB-INF/pages/main_new.jsp index f0ab6621c..3448a872e 100644 --- a/src/main/webapp/WEB-INF/pages/main_new.jsp +++ b/src/main/webapp/WEB-INF/pages/main_new.jsp @@ -98,29 +98,21 @@
- - -
-
+

Hints

- - + +
- - +
-
+
@@ -133,8 +125,8 @@

Cookies / Parameters


-
-
+
+

Cookies

-
+

Lesson Plan

-
+
-
+

Lesson Solution

-
+
-
+

Lesson Source Code

-
+
diff --git a/src/main/webapp/css/main.css b/src/main/webapp/css/main.css index 17f9fe8e7..1eb57dd5d 100644 --- a/src/main/webapp/css/main.css +++ b/src/main/webapp/css/main.css @@ -147,7 +147,7 @@ img { background-color: #16a086; } -.sidebar > div > ul > li > ul > li > span.lessonComplete { +.sidebar > div > ul > li > ul > li > span.lesson-complete { /*float: right; margin-left: 1.5em;*/ margin-right: 5px; @@ -192,6 +192,19 @@ img { .main-content-toggle-right { margin-right: 240px; } + +/*========================================================================== + lesson content / wrapper + ========================================================================= */ + +#lesson-content-wrapper { + padding:5px; +} + +#lesson-content-wrapper table td, #lesson-content-wrapper table th { + padding:3px !important; +} + /* ========================================================================== Buttons ========================================================================== */ @@ -719,11 +732,11 @@ fieldset[disabled] .btn-warning.active { margin-bottom:15px; } -cookieContainer { +cookie-container { margin-bottom:4px; } -.cookieTable tr td, .paramsTable tr td { +.cookie-table tr td, .params-table tr td { padding: 3px; max-width: 200px; font-size: x-small; @@ -820,11 +833,12 @@ cookieContainer { color: #e84c3d; } -.sidebar ul span.lessonComplete { +.sidebar ul span.lesson-complete { float: right; margin-left: -5px; /*margin-right: 5px;*/ padding-top: 15px; + display:inline-block; } #menu-container ul li.selected { @@ -840,12 +854,15 @@ cookieContainer { } /* HINTS */ +#lesson-hint-container { + display: none; +} #hintsViewTop{ display: none; background-color: #eee; } -#showPrevHintBtn, #showNextHintBtn { +#show-prev-hint, #show-next-hint { cursor: pointer; } diff --git a/src/main/webapp/js/goatApp/controller/LessonController.js b/src/main/webapp/js/goatApp/controller/LessonController.js index 5b7b4a505..959200343 100644 --- a/src/main/webapp/js/goatApp/controller/LessonController.js +++ b/src/main/webapp/js/goatApp/controller/LessonController.js @@ -50,12 +50,14 @@ define(['jquery', this.solutionView = {}; this.sourceView = {}; this.lessonHintView = {}; + this.screen = scr; + this.menu = menu; // }; this.onContentLoaded = function() { - //this.lessonView = new LessonContentView({content:LessonContent.content}); + this.helpControlsView = null; this.lessonView.model = this.lessonContent; this.lessonView.render(); @@ -64,22 +66,24 @@ define(['jquery', //load title view (initially hidden) << //TODO: currently handled via menu click but need to be able to handle via routed request //plan view (initially hidden) this.planView = new PlanView(); - this.listenTo(this.planView,'plan:loaded',this.areHelpsReady); + this.listenToOnce(this.planView,'plan:loaded',this.areHelpsReady); //solution view (initially hidden) this.solutionView = new SolutionView(); - this.listenTo(this.solutionView,'solution:loaded',this.areHelpsReady); + this.listenToOnce(this.solutionView,'solution:loaded',this.areHelpsReady); //source (initially hidden) this.sourceView = new SourceView(); - this.listenTo(this.sourceView,'source:loaded',this.areHelpsReady); + this.listenToOnce(this.sourceView,'source:loaded',this.areHelpsReady); //load help controls view (contextul to what helps are available) this.lessonHintView = new LessonHintView(); - this.listenTo(this.lessonHintView,'hints:loaded',this.areHelpsReady); + this.listenToOnce(this.lessonHintView,'hints:loaded',this.areHelpsReady); + // + this.hideShowHelps(null); }; this.areHelpsReady = function (curHelp) { this.addCurHelpState(curHelp); // check if all are ready - if (this.helpsLoaded['hints'] && this.helpsLoaded['plan'] && this.helpsLoaded['solution'] && this.helpsLoaded['source']) { + if (this.helpsLoaded['hints'] && this.helpsLoaded['plan'] && this.helpsLoaded['solution'] && this.helpsLoaded['source'] && !this.helpControlsView) { // this.helpControlsView = new HelpControlsView({ hasPlan:(this.planView.model.get('content') !== null), @@ -91,7 +95,7 @@ define(['jquery', // this.listenTo(this.helpControlsView,'plan:show',this.hideShowHelps); this.listenTo(this.helpControlsView,'solution:show',this.hideShowHelps); - this.listenTo(this.helpControlsView,'hints:show',this.showHints) + this.listenTo(this.helpControlsView,'hints:show',this.onShowHints) this.listenTo(this.helpControlsView,'source:show',this.hideShowHelps); this.listenTo(this.helpControlsView,'lesson:restart',this.restartLesson); } @@ -103,27 +107,38 @@ define(['jquery', this.hideShowHelps = function(showHelp) { var showId = '#lesson-' + showHelp + '-row'; + var contentId = '#lesson-' + showHelp + '-content'; $('.lesson-help').not(showId).hide(); + if (!showId) { + return; + } switch(showHelp) { case 'plan': - $(showId).html(this.planView.model.get('content')).show(); + $(contentId).html(this.planView.model.get('content')); break; case 'solution': - $(showId).html(this.solutionView.model.get('content')).show(); + $(showId).html(this.solutionView.model.get('content')); break; case 'source': - $(showId).html(this.sourceView.model.get('content')).show(); + $(contentId).html('
' + this.sourceView.model.get('content') + '
'); break; } + $(showId).show(); GoatUtils.scrollToHelp() - };; + }; - this.showHints = function() { - console.log('show Hints'); + this.onShowHints = function() { + this.lessonHintView.render(); }; this.restartLesson = function() { - console.log('restart lesson'); + self=this; + $.ajax({ + url:'service/restartlesson.mvc', + method:'GET' + }).then(function() { + self.loadLesson(self.screen,self.menu); + }); }; }; diff --git a/src/main/webapp/js/goatApp/controller/MenuController.js b/src/main/webapp/js/goatApp/controller/MenuController.js index abe675dde..a8c154b50 100644 --- a/src/main/webapp/js/goatApp/controller/MenuController.js +++ b/src/main/webapp/js/goatApp/controller/MenuController.js @@ -10,7 +10,7 @@ define(['jquery','underscore','backbone','goatApp/view/MenuView'], this.listenTo(this.menuView,'lesson:click',this.renderTitle); } - this.updateMenu = function() { + this.updateMenu = function(curLesson) { }, diff --git a/src/main/webapp/js/goatApp/model/HTMLContentModel.js b/src/main/webapp/js/goatApp/model/HTMLContentModel.js index 78803d463..fd5ac05f5 100644 --- a/src/main/webapp/js/goatApp/model/HTMLContentModel.js +++ b/src/main/webapp/js/goatApp/model/HTMLContentModel.js @@ -2,26 +2,24 @@ define(['jquery', 'underscore', 'backbone'], function($,_,Backbone) { - //TODO: make a base class to extend for items with 'traditional data' (e.g. LessonContentData, this ... others?) return Backbone.Model.extend({ //url:'service/lessonplan.mvc', fetch: function (options) { options = options || {}; return Backbone.Model.prototype.fetch.call(this, _.extend({ dataType: "html"}, options)); }, + loadData: function() { var self=this; this.fetch().then(function(data) { self.setContent(data); - self.onModelLoaded(); }); }, + setContent: function(content) { this.set('content',content); - this.trigger('loaded'); - }, - onModelLoaded: function() { this.checkNullModel(); + this.trigger('loaded'); } }); }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/model/LessonHintCollection.js b/src/main/webapp/js/goatApp/model/LessonHintCollection.js index dd64fea6d..24a59aab5 100644 --- a/src/main/webapp/js/goatApp/model/LessonHintCollection.js +++ b/src/main/webapp/js/goatApp/model/LessonHintCollection.js @@ -2,23 +2,31 @@ define(['jquery', 'underscore', 'backbone', 'goatApp/model/LessonHintModel'], - function($,_,Backbone,LessonHintModel) { + + function($, + _, + Backbone, + LessonHintModel) { + return Backbone.Collection.extend({ + model: LessonHintModel, + url:'service/hint.mvc', + initialize: function () { + var self = this; + this.fetch().then(function (data) { + this.models = data; + self.onDataLoaded(); + }); + }, - return Backbone.Collection.extend({ - model: LessonHintModel, - url:'service/hint.mvc', - initialize: function () { - var self = this; - this.fetch().then(function (data) { - this.models = data; - self.onDataLoaded(); - }); - }, - onDataLoaded:function() { - this.trigger('hints:loaded');//copied over as boiler-plate ... use this event trigger? - }, - checkNullModel:function() { - // - } - }); + onDataLoaded:function() { + this.trigger('loaded'); + }, + + checkNullModel:function() { + if (this.models[0].indexOf('There are no hints defined.') > -1) { + this.reset([]); + //return this.models; + } + } + }); }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/model/LessonPlanModel.js b/src/main/webapp/js/goatApp/model/LessonPlanModel.js index 88a3cc15a..7f23e8a46 100644 --- a/src/main/webapp/js/goatApp/model/LessonPlanModel.js +++ b/src/main/webapp/js/goatApp/model/LessonPlanModel.js @@ -9,10 +9,9 @@ define(['jquery', return HTMLContentModel.extend({ url:'service/lessonplan.mvc', checkNullModel: function() { - if (this.get('content').indexOf('Plan is not available for this lesson.') > -1) { + if (this.get('content').indexOf('Could not find lesson plan for') > -1) { this.set('content',null); } } - }); }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/model/LessonSolutionModel.js b/src/main/webapp/js/goatApp/model/LessonSolutionModel.js index ef249864d..b7b7561ce 100644 --- a/src/main/webapp/js/goatApp/model/LessonSolutionModel.js +++ b/src/main/webapp/js/goatApp/model/LessonSolutionModel.js @@ -9,7 +9,7 @@ define(['jquery', return HTMLContentModel.extend({ url:'service/solution.mvc', checkNullModel: function() { - if (this.get('content').indexOf('Solution is not available. Contact') === 0) { + if (this.get('content').indexOf('Could not find the solution file or solution file does not exist') === 0) { this.set('content',null); } } diff --git a/src/main/webapp/js/goatApp/model/LessonSourceModel.js b/src/main/webapp/js/goatApp/model/LessonSourceModel.js index 6e0b054a9..e6fc08625 100644 --- a/src/main/webapp/js/goatApp/model/LessonSourceModel.js +++ b/src/main/webapp/js/goatApp/model/LessonSourceModel.js @@ -10,7 +10,7 @@ define(['jquery', url:'service/source.mvc', checkNullModel: function () { //TODO: move this function into HTMLContentModel and make the string a property of this 'child' model - if (this.get('content').indexOf("No source listing found") > -1) { + if (this.get('content').indexOf("Could not find the source file or") > -1) { this.set('content',null); } } diff --git a/src/main/webapp/js/goatApp/view/GoatRouter.js b/src/main/webapp/js/goatApp/view/GoatRouter.js index 7d4dda3d8..d0ecb94c4 100644 --- a/src/main/webapp/js/goatApp/view/GoatRouter.js +++ b/src/main/webapp/js/goatApp/view/GoatRouter.js @@ -18,9 +18,11 @@ define(['jquery', 'welcome':'welcomeRoute', 'attack/:scr/:menu':'attackRoute' // }, + lessonController: new LessonController({ lessonView:lessonView }), + menuController: new MenuController({ menuView:menuView, titleView:titleView @@ -32,7 +34,6 @@ define(['jquery', this.menuController.initMenu(); goatRouter.on('route:attackRoute', function(scr,menu) { - console.log('attack route'); this.lessonController.loadLesson(scr,menu); this.menuController.updateMenu(scr,menu); //update menu @@ -42,7 +43,14 @@ define(['jquery', }); Backbone.history.start(); + this.listenTo('menu:reload',this.reloadMenu) + }, + + reloadMenu: function (curLesson) { + this.menuController.updateMenu(curLesson); } + + }); return GoatAppRouter; diff --git a/src/main/webapp/js/goatApp/view/HelpControlsView.js b/src/main/webapp/js/goatApp/view/HelpControlsView.js index 347ad8ae1..2c331e728 100644 --- a/src/main/webapp/js/goatApp/view/HelpControlsView.js +++ b/src/main/webapp/js/goatApp/view/HelpControlsView.js @@ -22,6 +22,8 @@ function($,_,Backbone) { this.hasHints = options.hasHints; }, render:function(title) { + this.$el.html(); + if (this.hasSource) { this.helpButtons.showSource.unbind().on('click',_.bind(this.showSource,this)); this.$el.append(this.helpButtons.showSource); @@ -38,7 +40,8 @@ function($,_,Backbone) { this.helpButtons.showHints.unbind().on('click',_.bind(this.showHints,this)); this.$el.append(this.helpButtons.showHints); } - // + + this.helpButtons.restartLesson.unbind().on('click',_.bind(this.restartLesson,this)); this.$el.append(this.helpButtons.restartLesson); }, @@ -56,6 +59,9 @@ function($,_,Backbone) { showHints: function() { this.trigger('hints:show','hints'); + }, + restartLesson: function() { + this.trigger('lesson:restart'); } }); }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/view/LessonContentView.js b/src/main/webapp/js/goatApp/view/LessonContentView.js index cdfda57d7..77592a742 100644 --- a/src/main/webapp/js/goatApp/view/LessonContentView.js +++ b/src/main/webapp/js/goatApp/view/LessonContentView.js @@ -6,7 +6,7 @@ define(['jquery', 'goatApp/model/LessonContentData'], function($,_,Backbone,JQueryForm,LessonData) { return Backbone.View.extend({ - el:'#lessonContentWrapper', //TODO << get this fixed up in DOM + el:'#lesson-content-wrapper', //TODO << get this fixed up in DOM initialize: function(options) { options = options || {}; }, diff --git a/src/main/webapp/js/goatApp/view/LessonHintView.js b/src/main/webapp/js/goatApp/view/LessonHintView.js index e61b086d5..63971b938 100644 --- a/src/main/webapp/js/goatApp/view/LessonHintView.js +++ b/src/main/webapp/js/goatApp/view/LessonHintView.js @@ -7,16 +7,65 @@ function($, Backbone, LessonHintCollection) { return Backbone.View.extend({ - el:'#lessonHelpWrapper .lessonHelp.lessonHint', - initialize: function() { - this.collection = new LessonHintCollection(); - this.listenTo(this.collection,'hints:loaded',this.onModelLoaded); + el:'#lesson-hint-container', + events: { + "click #show-next-hint": "showNextHint", + "click #show-prev-hint": "showPrevHint" }, - render:function(title) { + initialize: function() { + this.curHint=0; + this.collection = new LessonHintCollection(); + this.listenTo(this.collection,'loaded',this.onModelLoaded); }, + + render:function() { + if (this.$el.is(':visible')) { + this.$el.hide(350); + } else { + this.$el.show(350); + } + + if (this.collection.length > 0) { + this.hideShowPrevNextButtons(); + } + this.displayHint(this.curHint); + + }, + onModelLoaded: function() { this.trigger('hints:loaded',{'helpElement':'hints','value':true}) + }, + + showNextHint: function() { + this.curHint = (this.curHint < this.collection.length -1) ? this.curHint+1 : this.curHint; + this.hideShowPrevNextButtons(); + this.displayHint(this.curHint); + }, + + showPrevHint: function() { + this.curHint = (this.curHint > 0) ? this.curHint-1 : this.curHint; + this.hideShowPrevNextButtons(); + this.displayHint(this.curHint); + }, + + displayHint: function(curHint) { + this.$el.find('#lesson-hint-content').html(this.collection.models[curHint].get('hint')); + }, + + hideShowPrevNextButtons: function() { + if (this.curHint === this.collection.length -1) { + this.$el.find('#show-next-hint').css('visibility','hidden'); + } else { + this.$el.find('#show-next-hint').css('visibility','visible'); + } + + if (this.curHint === 0) { + this.$el.find('#show-prev-hint').css('visibility','hidden'); + } else { + this.$el.find('#show-prev-hint').css('visibility','visible'); + } } + }); }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/view/MenuView.js b/src/main/webapp/js/goatApp/view/MenuView.js index e4956ed63..5ea5cafd2 100644 --- a/src/main/webapp/js/goatApp/view/MenuView.js +++ b/src/main/webapp/js/goatApp/view/MenuView.js @@ -49,18 +49,24 @@ define(['jquery', for (var j=0; j < lessons.length;j++) { var lessonItem = $('
  • '); lessonName = lessons[j].name; + var lessonLink = $('',{href:lessons[j].link,text:lessonName,id:lessonName}); - lessonLink.click(_.bind(this.triggerTitleRender,this,lessonName)); + lessonLink.click(_.bind(this.titleRender,this,lessonName)); lessonItem.append(lessonLink); //check for lab/stages categoryLessonList.append(lessonItem); + if (lessons[j].complete) { + lessonItem.append($('',{class:'glyphicon glyphicon-check lesson-complete'})); + } var stages = lessons[j].children; for (k=0; k < stages.length; k++) { var stageName = stages[k].name; - var stageSpan = $(''); var stageLink = $('',{href:stages[k].link,text:stageName,id:GoatUtils.makeId(stageName)}); stageSpan.append(stageLink); categoryLessonList.append(stageSpan); + if (stages[j].complete) { + stageSpan.append($('',{class:'glyphicon glyphicon-check lesson-complete'})); + } } } category.append(categoryLessonList); @@ -74,14 +80,17 @@ define(['jquery', this.accordionMenu(this.openMenu); } }, - triggerTitleRender: function (title) { + + titleRender: function (title) { this.trigger('lesson:click',title); }, + expandCategory: function (id) { if (id) { this.accordionMenu(id); } }, + accordionMenu: function(id) { if (this.openMenu !== id) { this.$el.find('#' + id).slideDown(300);