mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
View web dev levels. Add proper victory modal game/webpage share links. Fix playing game dev levels. Add generic change transition to all web-dev pages.
This commit is contained in:
parent
0570644943
commit
224ad54bdd
17 changed files with 183 additions and 28 deletions
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -16,6 +16,12 @@
|
|||
|
||||
<script src="/javascripts/app/vendor/aether-html.js"></script>
|
||||
|
||||
<style>
|
||||
* {
|
||||
transition: 1s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
'play/ladder': go('ladder/MainLadderView')
|
||||
'play/level/:levelID': go('play/level/PlayLevelView')
|
||||
'play/game-dev-level/:levelID/:sessionID': go('play/level/PlayGameDevLevelView')
|
||||
'play/web-dev-level/:levelID/:sessionID': go('play/level/PlayWebDevLevelView')
|
||||
'play/spectate/:levelID': go('play/SpectateView')
|
||||
'play/:map': go('play/CampaignView')
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ module.exports = class LevelSession extends CocoModel
|
|||
generateSpellsObject: ->
|
||||
{createAetherOptions} = require 'lib/aether_utils'
|
||||
aetherOptions = createAetherOptions functionName: 'plan', codeLanguage: @get('codeLanguage')
|
||||
spellThang = aether: new Aether aetherOptions
|
||||
spells = "hero-placeholder/plan": thangs: {'Hero Placeholder': spellThang}, name: 'plan'
|
||||
spellThang = thang: {id: 'Hero Placeholder'}, aether: new Aether aetherOptions
|
||||
spells = "hero-placeholder/plan": thang: spellThang, name: 'plan'
|
||||
source = @get('code')['hero-placeholder'].plan
|
||||
try
|
||||
spellThang.aether.transpile source
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
padding-top: 0
|
||||
width: 750px
|
||||
|
||||
@media screen and ( max-height: 625px )
|
||||
margin-top: -50px
|
||||
|
||||
.modal-content
|
||||
position: relative
|
||||
margin-top: -251px
|
||||
|
@ -55,10 +58,14 @@
|
|||
top: 80px
|
||||
margin-top: 80px
|
||||
|
||||
@media screen and ( max-height: 650px )
|
||||
padding-top: 10px
|
||||
|
||||
.well-parchment
|
||||
margin-top: 20px
|
||||
|
||||
|
||||
@media screen and ( max-height: 675px )
|
||||
margin-top: 0
|
||||
|
||||
|
||||
html.no-borderimage
|
||||
|
|
|
@ -298,6 +298,33 @@
|
|||
height: 100%
|
||||
position: absolute
|
||||
|
||||
#share-level-container
|
||||
width: 709px
|
||||
height: 96px
|
||||
background: transparent url(/images/pages/play/level/modal/share_level_parchment.png)
|
||||
position: relative
|
||||
text-align: left
|
||||
padding: 12px 20px 0 20px
|
||||
text-align: center
|
||||
|
||||
.share-level-label
|
||||
color: rgb(103, 92, 76)
|
||||
text-transform: uppercase
|
||||
font-weight: bold
|
||||
font-family: $headings-font-family
|
||||
font-size: 18px
|
||||
margin-top: 13px
|
||||
line-height: 18px
|
||||
text-align: center
|
||||
|
||||
#share-level-input
|
||||
font-size: 12px
|
||||
margin-top: 8px
|
||||
|
||||
#share-level-btn
|
||||
width: 100%
|
||||
margin-top: 7px
|
||||
|
||||
|
||||
//- Footer - other stuff
|
||||
|
||||
|
|
|
@ -4,10 +4,18 @@
|
|||
color: black
|
||||
margin-bottom: 5px
|
||||
|
||||
p
|
||||
margin-top: 30px
|
||||
.next-level-description
|
||||
p
|
||||
margin-top: 30px
|
||||
|
||||
.course-title
|
||||
white-space: nowrap
|
||||
text-overflow: ellipsis
|
||||
overflow: hidden
|
||||
|
||||
#share-level-input
|
||||
font-size: 12px
|
||||
margin-top: 5px
|
||||
|
||||
#share-level-btn
|
||||
width: 100%
|
||||
|
|
18
app/styles/play/level/play-web-dev-level-view.sass
Normal file
18
app/styles/play/level/play-web-dev-level-view.sass
Normal file
|
@ -0,0 +1,18 @@
|
|||
#play-web-dev-level-view
|
||||
#web-surface-view
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
z-index: 0
|
||||
|
||||
#info-bar
|
||||
position: absolute
|
||||
right: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
height: 100px
|
||||
z-index: 1
|
||||
background-color: transparent
|
||||
text-align: center
|
|
@ -108,6 +108,23 @@ block modal-footer-content
|
|||
.total-count#gem-total 0
|
||||
.total-label(data-i18n="play_level.victory_gems_gained") Gems Gained
|
||||
|
||||
if view.shareURL
|
||||
#share-level-container
|
||||
span.share-level-label
|
||||
span(data-i18n='') Share this link to invite your friends & family to
|
||||
span= ' '
|
||||
a(href=view.shareURL, target='_blank')
|
||||
if view.level.isType('game-dev')
|
||||
span(data-i18n='') play your game level
|
||||
else
|
||||
span(data-i18n='') view your webpage
|
||||
.row
|
||||
.col-sm-9
|
||||
input.text-h4.semibold.form-control.input-md#share-level-input(value=view.shareURL)
|
||||
.col-sm-3
|
||||
button#share-level-btn.btn.btn-md.btn-success.btn-illustrated
|
||||
span(data-i18n='') Copy URL
|
||||
|
||||
if me.get('anonymous')
|
||||
.sign-up-poke.hide
|
||||
.sign-up-blurb(data-i18n="play_level.victory_sign_up_poke") Want to save your code? Create a free account!
|
||||
|
@ -127,8 +144,6 @@ block modal-footer-content
|
|||
button.btn.btn-illustrated.btn-success.leaderboard-button.btn-lg(data-dismiss="modal", data-i18n="leaderboard.view_other_solutions") View Other Solutions
|
||||
else if showReturnToCourse
|
||||
button.btn.btn-illustrated.btn-warning.return-to-course-button.btn-lg(data-dismiss="modal", data-i18n="play_level.victory_go_home") Go Home
|
||||
else if level.isType('game-dev', 'web-dev')
|
||||
button.btn.btn-illustrated.btn-primary.btn-lg ...
|
||||
|
||||
if showHourOfCodeDoneButton
|
||||
.hour-of-code-done
|
||||
|
|
|
@ -38,18 +38,31 @@
|
|||
span :
|
||||
h2.text-uppercase= i18n(view.nextLevel.attributes, 'name').replace('Course: ', '')
|
||||
|
||||
div!= view.nextLevelDescription
|
||||
div.next-level-description!= view.nextLevelDescription
|
||||
|
||||
.well.well-sm.well-parchment
|
||||
h3.text-uppercase
|
||||
| Share this level so your friends and family can play it:
|
||||
|
||||
.row
|
||||
.col-sm-8
|
||||
input.text-h4.semibold.form-control.input-lg#share-level-input(value='lkasjdflkjasdf')
|
||||
.col-sm-3
|
||||
button#share-level-btn.btn.btn-lg.btn-success.btn-illustrated
|
||||
span(data-i18n='') Copy URL
|
||||
if view.shareURL
|
||||
.well.well-sm.well-parchment
|
||||
h3.text-uppercase
|
||||
if view.level.isType('game-dev')
|
||||
span(data-i18n='') Share This Game
|
||||
else
|
||||
span(data-i18n='') Share This Webpage
|
||||
p
|
||||
span(data-i18n='') This link will let your friends & family
|
||||
span= ' '
|
||||
a(href=view.shareURL, target='_blank')
|
||||
if view.level.isType('game-dev')
|
||||
span(data-i18n='') play the game
|
||||
else
|
||||
span(data-i18n='') view the webpage
|
||||
span= ' '
|
||||
span(data-i18n='') you just created.
|
||||
.row
|
||||
.col-sm-9
|
||||
input.text-h4.semibold.form-control.input-lg#share-level-input(value=view.shareURL)
|
||||
.col-sm-3
|
||||
button#share-level-btn.btn.btn-lg.btn-success.btn-illustrated
|
||||
span(data-i18n='') Copy URL
|
||||
|
||||
.row
|
||||
.col-sm-5.col-sm-offset-2
|
||||
|
|
10
app/templates/play/level/play-web-dev-level-view.jade
Normal file
10
app/templates/play/level/play-web-dev-level-view.jade
Normal file
|
@ -0,0 +1,10 @@
|
|||
#web-surface-view
|
||||
|
||||
#info-bar.style-flat
|
||||
if !view.supermodel.finished()
|
||||
h1(data-i18n="common.loading")
|
||||
|
||||
else
|
||||
h1
|
||||
span Creator:
|
||||
| #{view.session.get('creatorName')}
|
|
@ -17,7 +17,7 @@ TEAM = 'humans'
|
|||
module.exports = class PlayGameDevLevelView extends RootView
|
||||
id: 'play-game-dev-level-view'
|
||||
template: require 'templates/play/level/play-game-dev-level-view'
|
||||
|
||||
|
||||
events:
|
||||
'click #play-btn': 'onClickPlayButton'
|
||||
|
||||
|
@ -26,7 +26,7 @@ module.exports = class PlayGameDevLevelView extends RootView
|
|||
loading: true
|
||||
progress: 0
|
||||
})
|
||||
|
||||
|
||||
@supermodel.on 'update-progress', (progress) =>
|
||||
@state.set({progress: (progress*100).toFixed(1)+'%'})
|
||||
@level = new Level()
|
||||
|
@ -41,7 +41,7 @@ module.exports = class PlayGameDevLevelView extends RootView
|
|||
|
||||
.then (levelLoader) =>
|
||||
{ @level, @session, @world } = levelLoader
|
||||
@god.setLevel(@level.serialize(@supermodel, @session))
|
||||
@god.setLevel(@level.serialize {@supermodel, @session})
|
||||
@god.setWorldClassMap(@world.classMap)
|
||||
@goalManager = new GoalManager(@world, @level.get('goals'), @team)
|
||||
@god.setGoalManager(@goalManager)
|
||||
|
@ -52,7 +52,7 @@ module.exports = class PlayGameDevLevelView extends RootView
|
|||
scripts: @world.scripts or [], view: @, @session, levelID: @level.get('slug')})
|
||||
@scriptManager.loadFromSession() # Should we? TODO: Figure out how scripts work for game dev levels
|
||||
@supermodel.finishLoading()
|
||||
|
||||
|
||||
.then (supermodel) =>
|
||||
@levelLoader.destroy()
|
||||
@levelLoader = null
|
||||
|
@ -74,7 +74,8 @@ module.exports = class PlayGameDevLevelView extends RootView
|
|||
@state.set('loading', false)
|
||||
|
||||
.catch ({message}) =>
|
||||
@state.set('errorMessage', message)
|
||||
console.error message
|
||||
@state.set('errorMessage', message)
|
||||
|
||||
onClickPlayButton: ->
|
||||
@god.createWorld(@spells, false, true)
|
||||
|
|
37
app/views/play/level/PlayWebDevLevelView.coffee
Normal file
37
app/views/play/level/PlayWebDevLevelView.coffee
Normal file
|
@ -0,0 +1,37 @@
|
|||
RootView = require 'views/core/RootView'
|
||||
|
||||
Level = require 'models/Level'
|
||||
LevelSession = require 'models/LevelSession'
|
||||
WebSurfaceView = require './WebSurfaceView'
|
||||
|
||||
module.exports = class PlayWebDevLevelView extends RootView
|
||||
id: 'play-web-dev-level-view'
|
||||
template: require 'templates/play/level/play-web-dev-level-view'
|
||||
|
||||
# events:
|
||||
# 'click #play-btn': 'onClickPlayButton'
|
||||
|
||||
initialize: (@options, @levelID, @sessionID) ->
|
||||
@courseID = @getQueryVariable 'course'
|
||||
@level = @supermodel.loadModel(new Level _id: @levelID).model
|
||||
@session = @supermodel.loadModel(new LevelSession _id: @sessionID).model
|
||||
|
||||
onLoaded: ->
|
||||
super()
|
||||
@insertSubView @webSurface = new WebSurfaceView {level: @level}
|
||||
Backbone.Mediator.publish 'tome:html-updated', html: @getHTML() ? '<h1>Player has no HTML</h1>', create: true
|
||||
@$el.find('#info-bar').delay(4000).fadeOut(2000)
|
||||
$('body').css('overflow', 'hidden')
|
||||
|
||||
showError: (jqxhr) ->
|
||||
$('h1').text jqxhr.statusText
|
||||
|
||||
getHTML: ->
|
||||
playerHTML = @session.get('code')?['hero-placeholder']?.plan
|
||||
return playerHTML unless hero = _.find @level.get('thangs'), id: 'Hero Placeholder'
|
||||
return playerHTML unless programmableConfig = _.find(hero.components, (component) -> component.config?.programmableMethods).config
|
||||
return programmableConfig.programmableMethods.plan.languages.html.replace /<playercode>[\s\S]*<\/playercode>/, playerHTML
|
||||
|
||||
destroy: ->
|
||||
@webSurface?.destroy()
|
||||
super()
|
|
@ -12,7 +12,7 @@ module.exports = class WebSurfaceView extends CocoView
|
|||
initialize: (options) ->
|
||||
@state = new State
|
||||
blah: 'blah'
|
||||
@goals = (goal for goal in options.goalManager.goals when goal.html)
|
||||
@goals = (goal for goal in options.goalManager?.goals ? [] when goal.html)
|
||||
# Consider https://www.npmjs.com/package/css-select to do this on virtualDOM instead of in iframe on concreteDOM
|
||||
super(options)
|
||||
|
||||
|
|
|
@ -44,11 +44,11 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
@levelSessions = @supermodel.loadCollection(@levelSessions, 'sessions', {
|
||||
data: { project: 'state.complete level.original playtime changed' }
|
||||
}).model
|
||||
|
||||
|
||||
if not @course
|
||||
@course = new Course()
|
||||
@supermodel.trackRequest @course.fetchForCourseInstance(@courseInstanceID)
|
||||
|
||||
|
||||
window.tracker?.trackEvent 'Play Level Victory Modal Loaded', category: 'Students', levelSlug: @level.get('slug'), ['Mixpanel']
|
||||
|
||||
onResourceLoadFailed: (e) ->
|
||||
|
@ -69,6 +69,7 @@ module.exports = class CourseVictoryModal extends ModalView
|
|||
course: @course
|
||||
classroom: @classroom
|
||||
levelSessions: @levelSessions
|
||||
session: @session
|
||||
})
|
||||
|
||||
progressView.once 'done', @onDone, @
|
||||
|
|
|
@ -32,6 +32,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
'click .sign-up-button': 'onClickSignupButton'
|
||||
'click .continue-from-offer-button': 'onClickContinueFromOffer'
|
||||
'click .skip-offer-button': 'onClickSkipOffer'
|
||||
'click #share-level-btn': 'onClickShareLevelButton'
|
||||
|
||||
# Feedback events
|
||||
'mouseover .rating i': (e) -> @showStars(@starNum($(e.target)))
|
||||
|
@ -73,7 +74,9 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
if @level.isType('course', 'course-ladder')
|
||||
@saveReviewEventually = _.debounce(@saveReviewEventually, 2000)
|
||||
@loadExistingFeedback()
|
||||
# TODO: support 'game-dev' and 'web-dev' (not the same as 'course' since can be played outside of courses)
|
||||
|
||||
if @level.isType('game-dev', 'web-dev')
|
||||
@shareURL = "#{window.location.origin}/play/#{@level.get('type')}-level/#{@level.get('slug')}/#{@session.id}"
|
||||
|
||||
destroy: ->
|
||||
clearInterval @sequentialAnimationInterval
|
||||
|
@ -499,6 +502,10 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
onClickSkipOffer: (e) ->
|
||||
Backbone.Mediator.publish 'router:navigate', @navigationEventUponCompletion
|
||||
|
||||
onClickShareLevelButton: ->
|
||||
@$('#share-level-input').val(@shareURL).select()
|
||||
@tryCopy()
|
||||
|
||||
# Ratings and reviews
|
||||
|
||||
starNum: (starEl) -> starEl.prevAll('i').length + 1
|
||||
|
|
|
@ -19,10 +19,14 @@ module.exports = class ProgressView extends CocoView
|
|||
@classroom = options.classroom
|
||||
@nextLevel = options.nextLevel
|
||||
@levelSessions = options.levelSessions
|
||||
@session = options.session
|
||||
# Translate and Markdownify level description, but take out any images (we don't have room for arena banners, etc.).
|
||||
# Images in Markdown are like ![description](url)
|
||||
@nextLevel.get('description', true) # Make sure the defaults are available
|
||||
@nextLevelDescription = marked(utils.i18n(@nextLevel.attributesWithDefaults, 'description').replace(/!\[.*?\]\(.*?\)\n*/g, ''))
|
||||
if @level.isType('game-dev', 'web-dev')
|
||||
@shareURL = "#{window.location.origin}/play/#{@level.get('type')}-level/#{@level.get('slug')}/#{@session.id}"
|
||||
@shareURL += "?course=#{@course.id}" if @course
|
||||
|
||||
onClickDoneButton: ->
|
||||
@trigger 'done'
|
||||
|
@ -34,5 +38,5 @@ module.exports = class ProgressView extends CocoView
|
|||
@trigger 'ladder'
|
||||
|
||||
onClickShareLevelButton: ->
|
||||
@$('#share-level-input').val('alskdjfla').select()
|
||||
@$('#share-level-input').val(@shareURL).select()
|
||||
@tryCopy()
|
||||
|
|
Loading…
Reference in a new issue