diff --git a/webgoat-container/src/main/resources/static/css/main.css b/webgoat-container/src/main/resources/static/css/main.css
index 0bf116637..9b64cb031 100644
--- a/webgoat-container/src/main/resources/static/css/main.css
+++ b/webgoat-container/src/main/resources/static/css/main.css
@@ -152,7 +152,7 @@ img {
margin-left: 1.5em;*/
margin-right: 5px;
margin-top: -38px; /* << don't like doing this, but otherwise it does not line up correctly */
- color:#0F0
+ color:#88FB88 /* #0F0 */
}
/* ==========================================================================
@@ -963,8 +963,47 @@ cookie-container {
width: 30px;
}
+.attack-link, .page-link {
+ display: inline-block;
+ background-color: #555;
+ border-radius: 8px;
+ min-width: 20px;
+ text-align: center;
+ font-weight: bold;
+ padding-top:2px;
+}
+
+.attack-link.solved-true {
+ color:#88FB88;
+}
+
+.attack-link.solved-false {
+ color:#f2baba;
+}
+
+.attack-link.cur-page, .page-link.cur-page {
+ color:#fff;
+}
+
+.page-link {
+ color:#eee;
+}
+
+.page-link-wrapper {
+ display:inline-block;
+}
+
+.page-link-wrapper span {
+ margin: 3px;
+}
+
+.cur-page {
+ border-bottom: 2px solid #000;
+ color:#aaa;
+}
+
span.show-next-page, span.show-prev-page {
-font-size: 1.3em;
+ font-size: 1.3em;
}
.show-prev-page {
@@ -975,6 +1014,8 @@ font-size: 1.3em;
cursor:pointer;
}
+/* attack ... */
+
.attack-feedback {
font-weight:800;
}
@@ -1045,4 +1086,11 @@ font-size: 1.3em;
font-weight: bold;
font-size: 12px;
padding: 10px;
-}
\ No newline at end of file
+}
+
+/* temp override
+//TODO: come up with longer term solution for full-window viewing
+*/
+.col-md-8 {
+ width: auto !important
+}
diff --git a/webgoat-container/src/main/resources/static/js/goatApp/model/LessonContentModel.js b/webgoat-container/src/main/resources/static/js/goatApp/model/LessonContentModel.js
index 395d31262..f26aad564 100644
--- a/webgoat-container/src/main/resources/static/js/goatApp/model/LessonContentModel.js
+++ b/webgoat-container/src/main/resources/static/js/goatApp/model/LessonContentModel.js
@@ -32,6 +32,7 @@ define(['jquery',
}
this.set('content',content);
this.set('lessonUrl',document.URL.replace(/\.lesson.*/,'.lesson'));
+ this.set('pageNum',document.URL.replace(/.*\.lesson\/(\d{1,4})$/,'$1'));
this.trigger('content:loaded',this,loadHelps);
},
diff --git a/webgoat-container/src/main/resources/static/js/goatApp/templates/paging_controls.html b/webgoat-container/src/main/resources/static/js/goatApp/templates/paging_controls.html
index 4e75fac0f..141c3f5af 100644
--- a/webgoat-container/src/main/resources/static/js/goatApp/templates/paging_controls.html
+++ b/webgoat-container/src/main/resources/static/js/goatApp/templates/paging_controls.html
@@ -1,5 +1,16 @@
\ No newline at end of file
diff --git a/webgoat-container/src/main/resources/static/js/goatApp/view/HelpControlsView.js b/webgoat-container/src/main/resources/static/js/goatApp/view/HelpControlsView.js
index 26f20f345..72610c84c 100644
--- a/webgoat-container/src/main/resources/static/js/goatApp/view/HelpControlsView.js
+++ b/webgoat-container/src/main/resources/static/js/goatApp/view/HelpControlsView.js
@@ -38,7 +38,7 @@ function($,_,Backbone) {
this.$el.find('#show-solution-button').unbind().on('click',_.bind(this.showSolution,this)).show();
}
- this.$el.find('#show-lesson-overview-button').unbind().on('click', _.bind(this.showLessonOverview, this)).show();
+ //this.$el.find('#show-lesson-overview-button').unbind().on('click', _.bind(this.showLessonOverview, this)).show();
this.$el.find('#restart-lesson-button').unbind().on('click',_.bind(this.restartLesson,this)).show();
},
diff --git a/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js b/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js
index 57beacd04..264ceb5c8 100644
--- a/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js
+++ b/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js
@@ -47,17 +47,17 @@ define(['jquery',
this.makeFormsAjax();
//this.ajaxifyAttackHref();
$(window).scrollTop(0); //work-around til we get the scroll down sorted out
- this.initPagination();
+ var startPageNum = this.model.get('pageNum');
+ this.initPagination(startPageNum);
},
- initPagination: function() {
+ initPagination: function(startPageNum) {
//get basic pagination info
- this.currentPage = 0;
this.$contentPages = this.$el.find('.lesson-page-wrapper');
- this.numPages = this.$contentPages.length;
- //
+ var currentPage = (!isNaN(startPageNum) && startPageNum && startPageNum < this.$contentPages) ? startPageNum : 0;
+ //init views & pagination
+ this.showCurContentPage(currentPage);
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'));
- //this.listenTo(this.paginationControlView,'page:set',this.navToPage);
},
getCurrentPage: function () {
@@ -163,8 +163,9 @@ define(['jquery',
},
navToPage: function (pageNum) {
- this.showCurContentPage(pageNum);
this.paginationControlView.setCurrentPage(pageNum);//provides validation
+ this.showCurContentPage(this.paginationControlView.currentPage);
+ this.paginationControlView.render();
this.paginationControlView.hideShowNavButtons();
var assignmentPath = this.findAssigmentEndpointOnPage(pageNum);
Backbone.trigger('navigatedToPage',{'pageNumber':pageNum, 'assignmentPath' : assignmentPath});
diff --git a/webgoat-container/src/main/resources/static/js/goatApp/view/PaginationControlView.js b/webgoat-container/src/main/resources/static/js/goatApp/view/PaginationControlView.js
index a6faddb6c..2cc744859 100644
--- a/webgoat-container/src/main/resources/static/js/goatApp/view/PaginationControlView.js
+++ b/webgoat-container/src/main/resources/static/js/goatApp/view/PaginationControlView.js
@@ -1,38 +1,99 @@
define(['jquery',
'underscore',
'backbone',
+ 'goatApp/model/LessonOverviewModel',
'text!templates/paging_controls.html'],
// 'css!css/paging-controls.css'],
function ($,
_,
Backbone,
+ LessonOverviewModel,
PaginationTemplate) {
return Backbone.View.extend({
template: PaginationTemplate,
el: '#lesson-page-controls',
initialize: function ($contentPages,baseLessonUrl) {
- this.numPages = $contentPages.length;
+ this.$contentPages = $contentPages;
+ this.model = new LessonOverviewModel();
+ this.listenTo(this.model, 'change add remove update reset', this.render);
+ this.numPages = this.$contentPages.length;
this.baseUrl = baseLessonUrl;
- this.parseLinks($contentPages);
+
this.initPagination();
- this.render();
- this.bindNavButtons();
+ //this.render();
+
+ this.model.fetch();
},
render: function () {
+ this.parseLinks();
var t = _.template(this.template);
- this.$el.html(t());
+ this.$el.html(t({'overview':this.lessonOverview}));
+ this.bindNavButtons();
this.hideShowNavButtons();
},
bindNavButtons: function() {
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').unbind().on('click',this.incrementPageView.bind(this));
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').unbind().on('click', this.decrementPageView.bind(this));
+ this.navButtonsBound = true;
},
- parseLinks: function($contentPages) {
+ parseLinks: function() {
+ var assignmentCount = this.$contentPages.find('.attack-container');
+ var solvedMap = {};
+ var pages = [];
+ // one pass on solved assignmets
+ _.each(this.model.toJSON(), function(assignment) {
+ if (assignment.solved) {
+ var key = assignment.assignment.path; //.replace(/\//g,'');
+ solvedMap[key] = assignment.assignment.name;
+ }
+ });
+ isAttackSolved = function (path) {
+ //strip
+ var newPath = path.replace(/^\/WebGoat/,'');
+ if (typeof solvedMap[newPath] !== 'undefined') {
+ return true;
+ }
+ return false;
+ };
+
+ var self = this;
+ var pages, pageClass, solved;
+ _.each(this.$contentPages,function(page,index) {
+ var curPageClass = (self.currentPage == index) ? ' cur-page' : '';
+
+ if ($(page).find('.attack-container').length < 1) { // no assignments [attacks]
+ pageClass = 'page-link';
+ pages.push({content:'content',pageClass:pageClass,curPageClass:curPageClass});
+ } else {
+ var $assignmentForms = $(page).find('.attack-container form');
+ // use for loop to avoid anonymous function scope hell
+ //var pageAssignments = {content:'attack',attacks:[]}
+ pageClass = 'attack-link'
+ var solvedClass = 'solved-true'
+ for (var i=0; i< $assignmentForms.length; i++) {
+ //normalize path
+ var action = $assignmentForms.attr('action');//.replace(/\//g,'');
+ if (action && isAttackSolved(action)) {
+ //pageClass = 'fa fa-check-square-o assignment-solved';
+ //pageAssignments.attacks.push({solved:true});
+ } else {
+ solvedClass = 'solved-false';
+
+ }
+ }
+ pages.push({solvedClass:solvedClass,content:'assignment',curPageClass:curPageClass,pageClass:pageClass});
+ }
+ });
+ //assign to the view
+ this.lessonOverview = {
+ baseUrl: this.baseUrl,
+ pages: pages
+ }
},
showPrevPageButton: function() {
@@ -75,7 +136,7 @@ define(['jquery',
this.hideNextPageButton();
this.showPrevPageButton;
}
- this.trigger('page:set',this,this.currentPage);
+ this.render();
},
decrementPageView: function() {
@@ -92,8 +153,7 @@ define(['jquery',
this.hidePrevPageButton();
this.showNextPageButton()
}
- this.trigger('page:set',this,this.currentPage);
-
+ this.render();
},
hideShowNavButtons: function () {
diff --git a/webgoat-container/src/main/resources/templates/main_new.html b/webgoat-container/src/main/resources/templates/main_new.html
index d45a737c1..e96256199 100644
--- a/webgoat-container/src/main/resources/templates/main_new.html
+++ b/webgoat-container/src/main/resources/templates/main_new.html
@@ -143,10 +143,7 @@
-
+