From 75e3c54d5430369b34307e7bbffa8d7892ef5ad6 Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 19 Jul 2016 17:58:10 -0700 Subject: [PATCH] Add concept map view to artisans. --- app/core/Router.coffee | 1 + app/templates/artisans/artisans-view.jade | 5 +- app/templates/artisans/concept-map-view.jade | 20 +++ app/views/artisans/LevelConceptMap.coffee | 168 +++++++++++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 app/templates/artisans/concept-map-view.jade create mode 100644 app/views/artisans/LevelConceptMap.coffee diff --git a/app/core/Router.coffee b/app/core/Router.coffee index b80e7f671..3b9359c98 100644 --- a/app/core/Router.coffee +++ b/app/core/Router.coffee @@ -51,6 +51,7 @@ module.exports = class CocoRouter extends Backbone.Router 'artisans/level-tasks': go('artisans/LevelTasksView') 'artisans/solution-problems': go('artisans/SolutionProblemsView') 'artisans/thang-tasks': go('artisans/ThangTasksView') + 'artisans/level-concepts': go('artisans/LevelConceptMap') 'beta': go('HomeView') diff --git a/app/templates/artisans/artisans-view.jade b/app/templates/artisans/artisans-view.jade index c2b5b3215..2f6321319 100644 --- a/app/templates/artisans/artisans-view.jade +++ b/app/templates/artisans/artisans-view.jade @@ -10,4 +10,7 @@ block content |Level Tasks div a(href="/artisans/solution-problems") - |Solution Problems \ No newline at end of file + |Solution Problems + div + a(href="/artisans/level-concepts") + |Level Concept Map \ No newline at end of file diff --git a/app/templates/artisans/concept-map-view.jade b/app/templates/artisans/concept-map-view.jade new file mode 100644 index 000000000..67156a7d8 --- /dev/null +++ b/app/templates/artisans/concept-map-view.jade @@ -0,0 +1,20 @@ +// DNT +extends /templates/base + +block content + #solution-problems-view + div + a(href='/artisans') + span.glyphicon.glyphicon-chevron-left + span Artisans Home + br + table.table.table-striped#level-table + tr + th Level Name + th Concepts Detected + for level in (view.parsedLevels || []) + tr + td(style="width:10%")= level.level.get('name') + td + for tag in (level.tags || []) + span.label.label-primary(style='margin-right: 10px; float: left; line-height: 20px; margin-bottom: 10px')= tag \ No newline at end of file diff --git a/app/views/artisans/LevelConceptMap.coffee b/app/views/artisans/LevelConceptMap.coffee new file mode 100644 index 000000000..97149d251 --- /dev/null +++ b/app/views/artisans/LevelConceptMap.coffee @@ -0,0 +1,168 @@ +RootView = require 'views/core/RootView' +template = require 'templates/artisans/concept-map-view' + +Level = require 'models/Level' +Campaign = require 'models/Campaign' + +CocoCollection = require 'collections/CocoCollection' +Campaigns = require 'collections/Campaigns' +Levels = require 'collections/Levels' +parser = new esper().realm.parser + +module.exports = class LevelConceptMap extends RootView + template: template + id: 'solution-problems-view' + excludedCampaigns = [ + # Misc. campaigns + 'picoctf', 'auditions' + + # Campaign-version campaigns + #'dungeon', 'forest', 'desert', 'mountain', 'glacier' + + # Test campaigns + 'dungeon-branching-test', 'forest-branching-test', 'desert-branching-test' + + # Course-version campaigns + #'intro', 'course-2', 'course-3', 'course-4', 'course-5', 'course-6' + ] + + includedLanguages = [ + 'javascript' + ] + + excludedLevelSnippets = [ + 'treasure', 'brawl', 'siege' + ] + + unloadedCampaigns: 0 + campaignLevels: {} + loadedLevels: {} + parsedLevels: [] + problemCount: 0 + + initialize: -> + @campaigns = new Campaigns([]) + @listenTo(@campaigns, 'sync', @onCampaignsLoaded) + @supermodel.trackRequest(@campaigns.fetch( + data: + project:'slug' + )) + + onCampaignsLoaded: (campCollection) -> + for campaign in campCollection.models + campaignSlug = campaign.get('slug') + continue if campaignSlug in excludedCampaigns + @unloadedCampaigns++ + + @campaignLevels[campaignSlug] = new Levels() + @listenTo(@campaignLevels[campaignSlug], 'sync', @onLevelsLoaded) + @supermodel.trackRequest(@campaignLevels[campaignSlug].fetchForCampaign(campaignSlug, + data: + project: 'thangs,name,slug,campaign' + )) + + onLevelsLoaded: (lvlCollection) -> + for level in lvlCollection.models + @loadedLevels[level.get('slug')] = level + if --@unloadedCampaigns is 0 + @onAllLevelsLoaded() + + onAllLevelsLoaded: -> + for levelSlug, level of @loadedLevels + unless level? + console.error 'Level Slug doesn\'t have associated Level', levelSlug + continue + + isBad = false + for word in excludedLevelSnippets + if levelSlug.indexOf(word) isnt -1 + isBad = true + continue if isBad + thangs = level.get 'thangs' + component = null + thangs = _.filter(thangs, (elem) -> + return _.findWhere(elem.components, (elem2) -> + if elem2.config?.programmableMethods? + component = elem2 + return true + ) + ) + + if thangs.length > 1 + console.warn 'Level has more than 1 programmableMethod Thangs', levelSlug + continue + + unless component? + console.error 'Level doesn\'t have programmableMethod Thang', levelSlug + continue + + plan = component.config.programmableMethods.plan + @parsedLevels.push + level: level + tags: @tagLevel _.find plan.solutions, (s) -> s.language is 'javascript' + + @renderSelectors '#level-table' + + tagLevel: (src) -> + return [] if not src?.source? + try + ast = parser(src.source) + catch e + return ['parse error: ' + e.message] + + tags = {} + process = (n) -> + return unless n? + switch n.type + when "Program", "BlockStatement" + process(n) for n in n.body + when "FunctionDeclaration" + tags['function-def'] = true + if n.params > 0 + tags['function-params:' + n.params.length] = true + process(n.body) + when "ExpressionStatement" + process(n.expression) + when "CallExpression" + process(n.callee) + when "MemberExpression" + if n.object?.name is 'hero' + tags["hero." + n.property.name] = true + when "WhileStatement" + if n.test.type is 'Literal' and n.test.value is true + tags['while-true'] = true + else + tags['while'] = true + process(n.test) + process(n.body) + when "ForStatement" + tags['for'] = true + process(n.init) + process(n.test) + process(n.update) + process(n.body) + when "IfStatement" + tags['if'] = true + process(n.test) + process(n.consequent) + process(n.alternate) + when "Literal" + if n.value is true + tags['true'] = true + else + tags['literal:' + typeof n.value] = true + when "BinaryExpression","LogicalExpression" + process(n.left) + process(n.right) + tags[n.operator] = true + when "AssignmentExpression" + tags['assign:' + n.operator] = true + process(n.right) + else + tags[n.type] = true + + + + process ast + Object.keys(tags) +