Place error message over Surface next to line

This commit is contained in:
Matt Lott 2014-11-06 21:43:39 -08:00
parent f3e4906810
commit b4dde5705b
8 changed files with 69 additions and 29 deletions

View file

@ -126,3 +126,7 @@ module.exports =
'tome:winnability-updated': c.object {title: 'Winnability Updated', description: 'When we think we can now win (or can no longer win), we may want to emphasize the submit button versus the run button (or vice versa), so this fires when we get new goal states (even preloaded goal states) suggesting success or failure change.', required: ['winnable']},
winnable: {type: 'boolean'}
'tome:show-problem-alert': c.object {title: 'Show Problem Alert', description: 'A problem alert needs to be shown.', required: ['problem']},
problem: {type: 'object'}
lineOffsetPx: {type: ['number', 'undefined']}

View file

@ -1,16 +1,17 @@
@import "app/styles/mixins"
@import "app/styles/bootstrap/variables"
.problem-alert
#problem-alert-view.problem-alert
z-index: 10
position: absolute
// Position these at the end of the spell editor, right above the spell toolbar.
bottom: -20px
left: 10px
right: 10px
top: 45px
right: 500px
background: transparent
border: 1px solid transparent
padding: 0
font-size: 18px
text-shadow: none
color: white
word-wrap: break-word

View file

@ -20,6 +20,8 @@
#gold-view
#problem-alert-view
#level-chat-view
#multiplayer-status-view

View file

@ -1,4 +1,4 @@
button.close(type="button", data-dismiss="alert") ×
button.close(type="button") ×
if hint
span.problem-title!= hint
br

View file

@ -23,6 +23,7 @@ RealTimeCollection = require 'collections/RealTimeCollection'
# subviews
LevelLoadingView = require './LevelLoadingView'
ProblemAlertView = require './tome/ProblemAlertView'
TomeView = require './tome/TomeView'
ChatView = require './LevelChatView'
HUDView = require './LevelHUDView'
@ -249,6 +250,7 @@ module.exports = class PlayLevelView extends RootView
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
if @level.get('type') in ['ladder', 'hero-ladder']
@insertSubView new MultiplayerStatusView levelID: @levelID, session: @session, level: @level
@insertSubView new ProblemAlertView {}
worldName = utils.i18n @level.attributes, 'name'
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel}
#_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'

View file

@ -1,20 +1,14 @@
ProblemAlertView = require './ProblemAlertView'
Range = ace.require('ace/range').Range
module.exports = class Problem
annotation: null
alertView: null
markerRange: null
constructor: (@aether, @aetherProblem, @ace, withAlert=false, isCast=false, @levelID) ->
constructor: (@aether, @aetherProblem, @ace, isCast=false, @levelID) ->
@buildAnnotation()
@buildAlertView() if withAlert
@buildMarkerRange() if isCast
Backbone.Mediator.publish("problem:problem-created", line:@annotation.row, text: @annotation.text) if application.isIPadApp
destroy: ->
unless @alertView?.destroyed
@alertView?.$el?.remove()
@alertView?.destroy()
@removeMarkerRange()
@userCodeProblem.off() if @userCodeProblem
@ -29,11 +23,6 @@ module.exports = class Problem
text: text,
type: @aetherProblem.level ? 'error'
buildAlertView: ->
@alertView = new ProblemAlertView problem: @
@alertView.render()
$(@ace.container).append @alertView.el
buildMarkerRange: ->
return unless @aetherProblem.range
[start, end] = @aetherProblem.range

View file

@ -3,32 +3,68 @@ template = require 'templates/play/level/tome/problem_alert'
{me} = require 'lib/auth'
module.exports = class ProblemAlertView extends CocoView
id: 'problem-alert-view'
className: 'problem-alert'
template: template
subscriptions: {}
subscriptions:
'tome:show-problem-alert': 'onShowProblemAlert'
'tome:manual-cast': 'onHideProblemAlert'
'real-time-multiplayer:manual-cast': 'onHideProblemAlert'
events:
'click .close': 'onRemoveClicked'
constructor: (options) ->
super options
@problem = options.problem
if options.problem?
@problem = options.problem
@onWindowResize()
else
@$el.hide()
$(window).on 'resize', @onWindowResize
destroy: ->
$(window).off 'resize', @onWindowResize
super()
getRenderData: (context={}) ->
context = super context
format = (s) -> s?.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br>')
context.message = format @problem.aetherProblem.message
context.hint = format @problem.aetherProblem.hint
if @problem?
format = (s) -> s?.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br>')
context.message = format @problem.aetherProblem.message
context.hint = format @problem.aetherProblem.hint
context
afterRender: ->
super()
@$el.addClass('alert').addClass("alert-#{@problem.aetherProblem.level}").hide().fadeIn('slow')
@$el.addClass('no-hint') unless @problem.aetherProblem.hint
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'error_appear', volume: 1.0
if @problem?
@$el.addClass('alert').addClass("alert-#{@problem.aetherProblem.level}").hide().fadeIn('slow')
@$el.addClass('no-hint') unless @problem.aetherProblem.hint
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'error_appear', volume: 1.0
onShowProblemAlert: (data) ->
return if @problem? and data.problem.aetherProblem.message is @problem.aetherProblem.message and data.problem.aetherProblem.hint is @problem.aetherProblem.hint
return unless $('#code-area').is(":visible")
@problem = data.problem
@lineOffsetPx = data.lineOffsetPx or 0
@$el.show()
@onWindowResize()
@render()
onHideProblemAlert: ->
@onRemoveClicked()
onRemoveClicked: ->
@$el.remove()
@destroy()
#@problem.destroy() # let's try leaving the annotations / marker ranges alone
@$el.hide()
@problem = null
onWindowResize: (e) =>
# TODO: This all seems a little hacky
if @problem?
@$el.css('left', $('#goals-view').outerWidth(true) + 'px')
@$el.css('right', $('#code-area').outerWidth(true) + 'px')
# 45px from top roughly aligns top of alert with top of first code line
# TODO: calculate this in a more dynamic, less sketchy way
@$el.css('top', (45 + @lineOffsetPx) + 'px')

View file

@ -515,7 +515,13 @@ module.exports = class SpellView extends CocoView
for aetherProblem, problemIndex in aether.getAllProblems()
continue if key = aetherProblem.userInfo?.key and key of seenProblemKeys
seenProblemKeys[key] = true if key
@problems.push problem = new Problem aether, aetherProblem, @ace, isCast and problemIndex is 0, isCast, @spell.levelID
@problems.push problem = new Problem aether, aetherProblem, @ace, isCast, @spell.levelID
if isCast and problemIndex is 0
if problem.aetherProblem.range?
# Line height is 20px
# TODO: Can we get line height dynamically from ace?
lineOffsetPx = problem.aetherProblem.range[0].row * 20 - @ace.session.getScrollTop()
Backbone.Mediator.publish 'tome:show-problem-alert', problem: problem, lineOffsetPx: lineOffsetPx
@saveUserCodeProblem(aether, aetherProblem) if isCast
annotations.push problem.annotation if problem.annotation
@aceSession.setAnnotations annotations