diff --git a/src/main/webapp/WEB-INF/pages/main_new.jsp b/src/main/webapp/WEB-INF/pages/main_new.jsp index e4216e756..c949d03e1 100644 --- a/src/main/webapp/WEB-INF/pages/main_new.jsp +++ b/src/main/webapp/WEB-INF/pages/main_new.jsp @@ -27,12 +27,7 @@ - - - - - - + - - - - - - - - - - - - - - - + + WebGoat - - -
+ +
- +
@@ -134,30 +98,25 @@
-
- - - - - +
+
-
+

Hints

- - + +
-
-
- -
-
This should default to the "How to Work with Webgoat" lesson
@@ -176,10 +135,10 @@

Cookies

-
+ + @@ -187,25 +146,11 @@ {{value}} - - -
+
-->

Params

- - - - - - - - - - -
ParamValue
{{param.name}}{{param.value}}
-
@@ -214,44 +159,18 @@
- -
+

Lesson Parameters and Cookies

-
-
- -
-
+
-
-
-

Lesson Hints

-
-
-
-
-
-
-
+

Lesson Plan

-
+
@@ -271,7 +190,7 @@

Lesson Source Code

-
{{source}}
+
@@ -280,20 +199,8 @@
- -
- - -
- - + + diff --git a/src/main/webapp/js/goatApp/controller/LessonController.js b/src/main/webapp/js/goatApp/controller/LessonController.js index 95319f609..6ad17e019 100644 --- a/src/main/webapp/js/goatApp/controller/LessonController.js +++ b/src/main/webapp/js/goatApp/controller/LessonController.js @@ -1,40 +1,38 @@ define(['jquery', 'underscore', 'libs/backbone', - 'goatApp/model/LessonData' + 'goatApp/model/LessonContentData', + 'goatApp/view/LessonContentView' ], - function($,_,Backbone,LessonData) { + function($,_,Backbone,LessonContent) { 'use strict' - //private vars + + + var Controller = function(options) { + this.lessonView = options.lessonView; + this.lessonContent = new LessonContentData(); - var controller = function() { + _.extend(this,Backbone.Events); + this.start = function() { + this.listenTo(this.lessonContent,'contentLoaded',this.onContentLoaded); + } + + //load View, which can pull data this.loadLesson = function(scr,menu) { - var curLessonData = new LessonData({ + this.lessonContent.loadContent({ 'screen': encodeURIComponent(scr), 'menu': encodeURIComponent(menu), }); + + //this.registerListeners(); + }; + + this.onContentLoaded = function() { + //this.lessonView = new LessonContentView({content:LessonContent.content}); + //this.lessonView.render(); + console.debug('loading other stuff'); } + }; - - return controller; - - //var curScreen,curMenu; - - //return { - // 'screen':curScreen - // loadLesson called from the router to load the given lesson - /*loadLesson: function (src,curMenu) { - var curLesson = new LessonData({ - 'screen': encodeURIComponent(scr), - 'menu': encodeURIComponent(curMenu), - }); - - //set listeners - - }, - restartLesson: function () { - - } - //getters & setters*/ - //}; + return Controller; }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/controller/MenuController.js b/src/main/webapp/js/goatApp/controller/MenuController.js index e1cf6807f..02773ebd6 100644 --- a/src/main/webapp/js/goatApp/controller/MenuController.js +++ b/src/main/webapp/js/goatApp/controller/MenuController.js @@ -1,3 +1,4 @@ -define(['jquery','underscore','backbone','goatApp/model/goatMenu','goatApp/view/MenuView'], function($,_,Backbone,MenuData,MenuView) { +define(['jquery','underscore','backbone','goatApp/model/MenuData','goatApp/view/MenuView'], + function($,_,Backbone,MenuData,MenuView) { }); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/model/LessonContentData.js b/src/main/webapp/js/goatApp/model/LessonContentData.js new file mode 100644 index 000000000..dee0b67b0 --- /dev/null +++ b/src/main/webapp/js/goatApp/model/LessonContentData.js @@ -0,0 +1,22 @@ +define(['jquery', 'underscore','backbone'], function($,_,Backbone){ + + return Backbone.Model.extend({ + urlRoot:null, + defaults: { + items:null, + selectedItem:null + }, + initialize: function (options) { + this.baseUrlRoot = 'attack?Screen=';// + }, + loadData: function(options) { + this.urlRoot = this.baseUrlRoot + +options.screen + '&menu=' + options.menu; + var self = this; + this.fetch().then(function(content){ + alert('content loaded'); + self.content = content; + self.trigger('contentLoaded'); + }); + } + }); +}); \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/model/MenuData.js b/src/main/webapp/js/goatApp/model/MenuData.js new file mode 100644 index 000000000..67708c622 --- /dev/null +++ b/src/main/webapp/js/goatApp/model/MenuData.js @@ -0,0 +1,57 @@ +//var goatApp = goatApp || {}; + +define(['jquery','underscore','backbone'], function($,_,Backbone) { + +var menuData = Backbone.Model.extend({ + urlRoot:'/webgoat/service/lessonmenu.mvc', + defaults: { + items:null, + selectedItem:null + }, + initialize: function () { + var self = this; + this.fetch().then(function(menuItems){ + menuItems = goatUtils.enhanceMenuData(menuItems,this.selectedItem); + this.setDataItems(menuItems); + }); + }, + + update: function() { + var self = this; + this.fetch().then(function(menuItems) { + menuItems = goatUtils.enhanceMenuData(menuItems,this.selectedItem); + self.setDataItems(menuItems); + }); + }, + + setDataItems: function (data) { + this.items = data; + } + }); + +}); + +/* +var menuData = Backbone.Model.extend({ + urlRoot:'/webgoat/service/lessonmenu.mvc', + defaults: { + items:null, + selectedItem:null + }, + initialize: function () { + var self = this; + this.fetch().then(function(menuItems){ + menuItems = goatUtils.enhanceMenuData(menuItems,this.selectedItem); + self.items = menuItems; + }); + }, + + update: function() { + var self = this; + this.fetch().then(function(data) { + self.items = data; + self.render(0); + }); + } + }); +*/ \ No newline at end of file diff --git a/src/main/webapp/js/goatApp/support/goatUtil.js b/src/main/webapp/js/goatApp/support/goatUtil.js new file mode 100644 index 000000000..2e3e1c897 --- /dev/null +++ b/src/main/webapp/js/goatApp/support/goatUtil.js @@ -0,0 +1,189 @@ +goat.utils = { + //TODO add recursion to handle arr[i].children objects + // ... in case lower-level's need classes as well ... don't right now + addMenuClasses: function(arr) { + for (var i = 0; i < arr.length; i++) { + var menuItem = arr[i]; + //console.log(menuItem); + if (menuItem.type && menuItem.type === 'CATEGORY') { + menuItem.class = 'fa-angle-right pull-right'; + } + } + return arr; + }, + debugFormSubmission: false, + // pre-submit callback + showRequest: function(formData, jqForm, options) { + if (goat.utils.debugFormSubmission) { + // formData is an array; here we use $.param to convert it to a string to display it + // but the form plugin does this for you automatically when it submits the data + var queryString = $.param(formData); + + // jqForm is a jQuery object encapsulating the form element. To access the + // DOM element for the form do this: + // var formElement = jqForm[0]; + + alert('About to submit: \n\n' + queryString); + } + // here we could return false to prevent the form from being submitted; + // returning anything other than false will allow the form submit to continue + return true; + }, + // post-submit callback + showResponse: function(responseText, statusText, xhr, $form) { + // for normal html responses, the first argument to the success callback + // is the XMLHttpRequest object's responseText property + + // if the ajaxForm method was passed an Options Object with the dataType + // property set to 'xml' then the first argument to the success callback + // is the XMLHttpRequest object's responseXML property + + // if the ajaxForm method was passed an Options Object with the dataType + // property set to 'json' then the first argument to the success callback + // is the json data object returned by the server + if (goat.utils.debugFormSubmission) { + alert('status: ' + statusText + '\n\nresponseText: \n' + responseText + + '\n\nThe output div should have already been updated with the responseText.'); + } + // update lesson cookies and params + // make any embedded forms ajaxy + goat.utils.showLessonCookiesAndParams(); + // forms and links are now hooked with each standard lesson render (see Java class Screen.getContent()) + // but these are safe to call twice + goat.utils.makeFormsAjax(); + goat.utils.ajaxifyAttackHref(); //TODO find some way to hook scope for current menu. Likely needs larger refactor which is already started/stashed + //refresh menu + angular.element($('#leftside-navigation')).scope().renderMenu(); + }, + makeFormsAjax: function() { + // make all forms ajax forms + var options = { + target: '#lesson_content', // target element(s) to be updated with server response + beforeSubmit: goat.utils.showRequest, // pre-submit callback, comment out after debugging + success: goat.utils.showResponse // post-submit callback, comment out after debugging + + // other available options: + //url: url // override for form's 'action' attribute + //type: type // 'get' or 'post', override for form's 'method' attribute + //dataType: null // 'xml', 'script', or 'json' (expected server response type) + //clearForm: true // clear all form fields after successful submit + //resetForm: true // reset the form after successful submit + + // $.ajax options can be used here too, for example: + //timeout: 3000 + }; + //console.log("Hooking any lesson forms to make them ajax"); + $("form").ajaxForm(options); + }, + displayButton: function(id, show) { + if ($('#' + id)) { + if (show) { + $('#' + id).show(); + } else { + $('#' + id).hide(); + } + } + }, + showLessonCookiesAndParams: function() { + $.get(goatConstants.cookieService, {}, function(reply) { + $("#lesson_cookies").html(reply); + }, "html"); + }, + showLessonHints: function() { + $('.lessonHelp').hide(); + $('#lesson_hint').html(); + $('#lesson_hint_row').show(); + }, + showLessonSource: function(source) { + $('.lessonHelp').hide(); + //$('#lesson_source').html("
"+goat.lesson.lessonInfo.source+"
"); + $('#lesson_source_row').show(); + goat.utils.scrollToHelp(); + }, + showLessonSolution: function() { + $('.lessonHelp').hide(); + $('#lesson_solution').html(goat.lesson.lessonInfo.solution); + $('#lesson_solution_row').show(); + goat.utils.scrollToHelp(); + }, + showLessonPlan: function(plan) { + $('.lessonHelp').hide(); + $("#lesson_plan").html(goat.lesson.lessonInfo.plan); + $('#lesson_plan_row').show(); + goat.utils.scrollToHelp(); + }, + scrollToHelp: function() { + $('#leftside-navigation').height($('#main-content').height() + 15) + var target = $('#lessonHelpsWrapper'); + goat.utils.scrollEasy(target); + }, + scrollToTop: function() { + $('.lessonHelp').hide(); + var target = $('#container'); + goat.utils.scrollEasy(target); + }, + scrollEasy: function(target) { + $('html,body').animate({ + scrollTop: target.offset().top + }, 1000); + }, + scrapeParams: function(url) { + if (!url) { + return; + } + var params = url.split('?')[1].split('&'); + var paramsArr = []; + for (var i = 0; i < params.length; i++) { + var paramObj = {}; + paramObj.name = params[i].split('=')[0]; + paramObj.value = params[i].split('=')[1]; + paramsArr.push(paramObj); + } + return paramsArr; + }, + highlightCurrentLessonMenu: function(id) { + //TODO: move selectors in first two lines into goatConstants + $('ul li.selected').removeClass(goatConstants.selectedMenuClass) + $('ul li.selected a.selected').removeClass(goatConstants.selectedMenuClass) + $('#' + id).addClass(goatConstants.selectedMenuClass); + $('#' + id).parent().addClass(goatConstants.selectedMenuClass); + }, + makeId: function(lessonName) { + return lessonName.replace(/\s|\(|\)|\!|\:|\;|\@|\#|\$|\%|\^|\&|\*/g, '');//TODO move the replace routine into util function + }, + ajaxifyAttackHref: function() { + /* Jason I commented this implementation out + * I think we should show the attack link on the lessons that need it by modifying the lesson + * itself or we could add a new button up top for "show lesson link" + $.each($('a[href^="attack?"]'), + function(i,el) { + var url = $(el).attr('href'); + $(el).attr('href','#'); + $(el).attr('link',url); + //TODO pull currentMenuId + $(el).click( + function() { + var _url = $(el).attr('link'); + $.get(_url, {success:showResponse}); + } + ) + } + ); + */ + // alternate implementation + // unbind any bound events so we are safe to be called twice + $('#lesson_content a').unbind('click'); + $('#lesson_content a').bind('click', function(event) { + event.preventDefault(); + $.get(this.href, {}, function(response) { + $('#lesson_content').html(response); + }); + }); + } +}; + + +$(window).resize(function() { + //$('#leftside-navigation').css('height',$('div.panel-body').height()); + console.log($(window).height()); +}); \ 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 new file mode 100644 index 000000000..e0f89101a --- /dev/null +++ b/src/main/webapp/js/goatApp/view/LessonContentView.js @@ -0,0 +1,23 @@ +//LessonContentView +define(['jquery', + 'underscore', + 'backbone', + 'goatApp/model/LessonContentData'], +function($,_,Backbone,LessonData) { + var contentView = Backbone.View.extend({ + el:'#lessonContent', + initialize: function(options) { + //this.content = options.content; + this.lessonData = {}; + this.listenTo(this.lessonData,'sync',this.render); + }, + loadLesson: function(options) { + this.lessonData = new LessonData(options.screen,options.menu); + + }, + render: function() { + alert('render'); + this.$el.html(this.content); + } + }); +}); \ 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 091cd37cf..1e1872508 100644 --- a/src/main/webapp/js/goatApp/view/MenuView.js +++ b/src/main/webapp/js/goatApp/view/MenuView.js @@ -1,4 +1,4 @@ -define(['jquery','underscore','backbone','goatApp/model/goatMenu'], function($,_,Backbone,MenuData) { +define(['jquery','underscore','backbone','goatApp/model/MenuData'], function($,_,Backbone,MenuData) { return Backbone.View.extend({ el:'#menuContainer', diff --git a/src/main/webapp/js/goatApp/view/goatRouter.js b/src/main/webapp/js/goatApp/view/goatRouter.js index eb4f77e58..1b5fa441a 100644 --- a/src/main/webapp/js/goatApp/view/goatRouter.js +++ b/src/main/webapp/js/goatApp/view/goatRouter.js @@ -1,34 +1,44 @@ define(['jquery', 'underscore', 'backbone', - 'goatApp/controller/LessonController' - ], function ($,_,Backbone,LessonController) { - var GoatAppRouter = Backbone.Router.extend({ - routes: { - //#.... - 'welcome':'welcomeRoute', - 'attack/:scr/:menu':'attackRoute' // - }, - lessonController: new LessonController() - }); + 'goatApp/controller/LessonController', + 'goatApp/controller/MenuController', + 'goatApp/view/LessonContentView', + 'goatApp/view/MenuView' + ], function ($,_,Backbone,LessonController,MenuController,LessonView,MenuView) { - - - var init = function() { - goatRouter = new GoatAppRouter(); - - goatRouter.on('route:attackRoute', function(scr,menu) { - this.lessonController.loadLesson(scr,menu); + var lessonView = new LessonContentView(); + var menuView = new MenuView(); + var GoatAppRouter = Backbone.Router.extend({ + routes: { + //#.... + 'welcome':'welcomeRoute', + 'attack/:scr/:menu':'attackRoute' // + }, + lessoonController: lessoonController({ + lessonView:lessonView + }), + menuView: new MenuController({ + menuView:menuView + }); }); - goatRouter.on('route:welcomeRoute', function() { - alert('welcome route'); - }); - // init the history/router - Backbone.history.start(); - } - return { - init:init - }; + var init = function() { + goatRouter = new GoatAppRouter(); + + goatRouter.on('route:attackRoute', function(scr,menu) { + this.lessonController.loadLesson(scr,menu); + //update menu + }); + goatRouter.on('route:welcomeRoute', function() { + alert('welcome route'); + }); + // init the history/router + Backbone.history.start(); + } + + return { + init:init + }; }); \ No newline at end of file