mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-12-02 03:47:09 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
9cbc6028b2
15 changed files with 82 additions and 67 deletions
|
@ -5,6 +5,7 @@ BEEN_HERE_BEFORE_KEY = 'beenHereBefore'
|
|||
|
||||
init = ->
|
||||
module.exports.me = window.me = new User(window.userObject) # inserted into main.html
|
||||
module.exports.me.onLoaded()
|
||||
trackFirstArrival()
|
||||
if me and not me.get('testGroupNumber')?
|
||||
# Assign testGroupNumber to returning visitors; new ones in server/routes/auth
|
||||
|
|
|
@ -162,10 +162,14 @@ groupDeltasByAffectingPaths = (deltas) ->
|
|||
prunedMap
|
||||
|
||||
module.exports.pruneConflictsFromDelta = (delta, conflicts) ->
|
||||
expandedDeltas = (conflict.pendingDelta for conflict in conflicts)
|
||||
module.exports.pruneExpandedDeltasFromDelta delta, expandedDeltas
|
||||
|
||||
module.exports.pruneExpandedDeltasFromDelta = (delta, expandedDeltas) ->
|
||||
# the jsondiffpatch delta mustn't include any dangling nodes,
|
||||
# or else things will get removed which shouldn't be, or errors will occur
|
||||
for conflict in conflicts
|
||||
prunePath delta, conflict.pendingDelta.deltaPath
|
||||
for expandedDelta in expandedDeltas
|
||||
prunePath delta, expandedDelta.deltaPath
|
||||
if _.isEmpty delta then undefined else delta
|
||||
|
||||
prunePath = (delta, path) ->
|
||||
|
|
|
@ -34,5 +34,5 @@ module.exports.applyErrorsToForm = (el, errors) ->
|
|||
|
||||
module.exports.clearFormAlerts = (el) ->
|
||||
$('.has-error', el).removeClass('has-error')
|
||||
$('.alert', el).remove()
|
||||
$('.alert.alert-danger', el).remove()
|
||||
el.find('.help-block.error-help-block').remove()
|
|
@ -78,7 +78,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t
|
|||
creating: "Fiók létrehozása"
|
||||
sign_up: "Regisztráció"
|
||||
log_in: "Belépés meglévő fiókkal"
|
||||
# social_signup: "Or, you can sign up through Facebook or G+:"
|
||||
social_signup: "De regisztrálhatsz a Facebook-on vagy a G+:-on keresztül is."
|
||||
# required: "You need to log in before you can go that way."
|
||||
|
||||
home:
|
||||
|
@ -166,10 +166,10 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t
|
|||
email_announcements_description: "Szeretnél levelet kapni a legújabb fejlesztéseinkről?"
|
||||
email_notifications: "Értesítések"
|
||||
# email_notifications_summary: "Controls for personalized, automatic email notifications related to your CodeCombat activity."
|
||||
# email_any_notes: "Any Notifications"
|
||||
# email_any_notes_description: "Disable to stop all activity notification emails."
|
||||
# email_recruit_notes: "Job Opportunities"
|
||||
# email_recruit_notes_description: "If you play really well, we may contact you about getting you a (better) job."
|
||||
email_any_notes: "Bármely értesítés"
|
||||
email_any_notes_description: "Minden tevékenységgel kapcsolatos e-mail értesítés letiltása."
|
||||
email_recruit_notes: "Álláslehetőségek"
|
||||
email_recruit_notes_description: "Ha igazán jól játszol lehet, hogy felveszzük veled a kapcsolatot és megbeszéljük, hogy szerezzünk-e neked egy (jobb) állást."
|
||||
contributor_emails: "Hozzájárulóknak szóló levelek"
|
||||
contribute_prefix: "Folyamatosan keresünk embereket, hogy csatlakozzanak hozzánk. Nézz rá a "
|
||||
contribute_page: "segítők oldalára"
|
||||
|
@ -181,8 +181,8 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t
|
|||
job_profile: "Munkaköri leírás"
|
||||
job_profile_approved: "Munkaköri leírásodat a Codecombat jóváhagyta. Munkaadók mindaddig láthatják, amíg meg nem jelölöd inaktíként, vagy négy hétig,ha addig nem kerül megváltoztatásra."
|
||||
job_profile_explanation: "Szió! Töltsd ki ezt és majd kapcsolatba lépünk veled és keresünk neked egy szoftware fejlesztői állást."
|
||||
# sample_profile: "See a sample profile"
|
||||
# view_profile: "View Your Profile"
|
||||
sample_profile: "Nézz meg egy mintaprofilt!"
|
||||
view_profile: "Nézd meg a profilodat!"
|
||||
|
||||
account_profile:
|
||||
edit_settings: "Beállítások szerkesztése"
|
||||
|
|
|
@ -15,10 +15,10 @@ class CocoModel extends Backbone.Model
|
|||
super()
|
||||
if not @constructor.className
|
||||
console.error("#{@} needs a className set.")
|
||||
@markToRevert()
|
||||
@addSchemaDefaults()
|
||||
@on 'sync', @onLoaded, @
|
||||
@on 'error', @onError, @
|
||||
@on 'add', @onLoaded, @
|
||||
@saveBackup = _.debounce(@saveBackup, 500)
|
||||
|
||||
type: ->
|
||||
|
@ -38,14 +38,15 @@ class CocoModel extends Backbone.Model
|
|||
@loaded = true
|
||||
@loading = false
|
||||
@jqxhr = null
|
||||
@markToRevert()
|
||||
@loadFromBackup()
|
||||
|
||||
getNormalizedURL: -> "#{@urlRoot}/#{@id}"
|
||||
|
||||
set: ->
|
||||
inFlux = @loading or not @loaded
|
||||
@markToRevert() unless inFlux or @_revertAttributes
|
||||
res = super(arguments...)
|
||||
@saveBackup() if @saveBackups and @loaded and @hasLocalChanges()
|
||||
@saveBackup() if @saveBackups and (not inFlux) and @hasLocalChanges()
|
||||
res
|
||||
|
||||
loadFromBackup: ->
|
||||
|
@ -61,22 +62,29 @@ class CocoModel extends Backbone.Model
|
|||
|
||||
@backedUp = {}
|
||||
schema: -> return @constructor.schema
|
||||
|
||||
getValidationErrors: ->
|
||||
errors = tv4.validateMultiple(@attributes, @constructor.schema or {}).errors
|
||||
return errors if errors?.length
|
||||
|
||||
validate: ->
|
||||
result = tv4.validateMultiple(@attributes, @constructor.schema? or {})
|
||||
if result.errors?.length
|
||||
console.log @, "got validate result with errors:", result
|
||||
return result.errors unless result.valid
|
||||
|
||||
errors = @getValidationErrors()
|
||||
if errors?.length
|
||||
console.debug "Validation failed for #{@constructor.className}: '#{@get('name') or @}'."
|
||||
for error in errors
|
||||
console.debug "\t", error.dataPath, ":", error.message
|
||||
return errors
|
||||
|
||||
save: (attrs, options) ->
|
||||
@set 'editPath', document.location.pathname
|
||||
options ?= {}
|
||||
options.headers ?= {}
|
||||
options.headers['X-Current-Path'] = document.location.pathname
|
||||
success = options.success
|
||||
error = options.error
|
||||
options.success = (model, res) =>
|
||||
@trigger "save:success", @
|
||||
success(@, res) if success
|
||||
@markToRevert()
|
||||
@markToRevert() if @_revertAttributes
|
||||
@clearBackup()
|
||||
options.error = (model, res) =>
|
||||
error(@, res) if error
|
||||
|
@ -93,7 +101,7 @@ class CocoModel extends Backbone.Model
|
|||
@jqxhr
|
||||
|
||||
markToRevert: ->
|
||||
return unless @saveBackups
|
||||
console.debug "Saving _revertAttributes for #{@constructor.className}: '#{@get('name')}'"
|
||||
if @type() is 'ThangType'
|
||||
@_revertAttributes = _.clone @attributes # No deep clones for these!
|
||||
else
|
||||
|
@ -142,7 +150,6 @@ class CocoModel extends Backbone.Model
|
|||
#console.log "setting", prop, "to", sch.default, "from sch.default" if sch.default?
|
||||
@set prop, sch.default if sch.default?
|
||||
if @loaded
|
||||
@markToRevert()
|
||||
@loadFromBackup()
|
||||
|
||||
@isObjectID: (s) ->
|
||||
|
|
|
@ -52,4 +52,8 @@
|
|||
.checkbox
|
||||
margin: 10px 10px 0
|
||||
input
|
||||
margin-right: 5px
|
||||
margin-right: 5px
|
||||
|
||||
#errors-wrapper
|
||||
margin-top: 20px
|
||||
margin-bottom: 0
|
|
@ -53,3 +53,7 @@ block modal-body-content
|
|||
label
|
||||
input(id=id + "-version-is-major", name="version-is-major", type="checkbox")
|
||||
span(data-i18n="versions.new_major_version") New Major Version
|
||||
|
||||
#errors-wrapper.alert.alert-danger.hide
|
||||
strong Validation Error! Save failed.
|
||||
p.errors
|
|
@ -44,26 +44,27 @@ module.exports = class DeltaView extends CocoView
|
|||
@expandedDeltas = @model.getExpandedDeltaWith(@comparisonModel)
|
||||
else
|
||||
@expandedDeltas = @model.getExpandedDelta()
|
||||
|
||||
@filterExpandedDeltas()
|
||||
[@expandedDeltas, @skippedDeltas] = @filterDeltas(@expandedDeltas)
|
||||
|
||||
if @headModel
|
||||
@headDeltas = @headModel.getExpandedDelta()
|
||||
@headDeltas = @filterDeltas(@headDeltas)[0]
|
||||
@conflicts = deltasLib.getConflicts(@headDeltas, @expandedDeltas)
|
||||
|
||||
filterExpandedDeltas: ->
|
||||
return unless @skipPaths
|
||||
filterDeltas: (deltas) ->
|
||||
return [deltas, []] unless @skipPaths
|
||||
for path, i in @skipPaths
|
||||
@skipPaths[i] = [path] if _.isString(path)
|
||||
newDeltas = []
|
||||
for delta in @expandedDeltas
|
||||
skippedDeltas = []
|
||||
for delta in deltas
|
||||
skip = false
|
||||
for skipPath in @skipPaths
|
||||
if _.isEqual _.first(delta.dataPath, skipPath.length), skipPath
|
||||
skip = true
|
||||
break
|
||||
newDeltas.push delta unless skip
|
||||
@expandedDeltas = newDeltas
|
||||
if skip then skippedDeltas.push delta else newDeltas.push delta
|
||||
[newDeltas, skippedDeltas]
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -87,7 +88,7 @@ module.exports = class DeltaView extends CocoView
|
|||
@expandDetails(deltaEl, deltaData)
|
||||
|
||||
expandDetails: (deltaEl, deltaData) ->
|
||||
treemaOptions = { schema: deltaData.schema, readOnly: true }
|
||||
treemaOptions = { schema: deltaData.schema or {}, readOnly: true }
|
||||
|
||||
if _.isObject(deltaData.left) and leftEl = deltaEl.find('.old-value')
|
||||
options = _.defaults {data: deltaData.left}, treemaOptions
|
||||
|
@ -109,5 +110,6 @@ module.exports = class DeltaView extends CocoView
|
|||
|
||||
getApplicableDelta: ->
|
||||
delta = @model.getDelta()
|
||||
delta = deltasLib.pruneConflictsFromDelta delta, @conflicts if @conflicts
|
||||
delta = deltasLib.pruneConflictsFromDelta delta, @conflicts if @conflicts
|
||||
delta = deltasLib.pruneExpandedDeltasFromDelta delta, @skippedDeltas if @skippedDeltas
|
||||
delta
|
|
@ -53,7 +53,7 @@ module.exports = class LevelSaveView extends SaveVersionModal
|
|||
|
||||
commitLevel: ->
|
||||
modelsToSave = []
|
||||
@showLoading()
|
||||
formsToSave = []
|
||||
for form in @$el.find('form')
|
||||
# Level form is first, then LevelComponents' forms, then LevelSystems' forms
|
||||
fields = {}
|
||||
|
@ -75,7 +75,19 @@ module.exports = class LevelSaveView extends SaveVersionModal
|
|||
@level.publish()
|
||||
else if @level.isPublished() and not newModel.isPublished()
|
||||
newModel.publish() # Publish any LevelComponents that weren't published yet
|
||||
formsToSave.push form
|
||||
|
||||
for model in modelsToSave
|
||||
if errors = model.getValidationErrors()
|
||||
messages = ("\t #{error.dataPath}: #{error.message}" for error in errors)
|
||||
messages = messages.join('<br />')
|
||||
@$el.find('#errors-wrapper .errors').html(messages)
|
||||
@$el.find('#errors-wrapper').removeClass('hide')
|
||||
return
|
||||
|
||||
@showLoading()
|
||||
tuples = _.zip(modelsToSave, formsToSave)
|
||||
for [newModel, form] in tuples
|
||||
res = newModel.save()
|
||||
do (newModel, form) =>
|
||||
res.error =>
|
||||
|
|
|
@ -152,32 +152,6 @@ class EventPrereqNode extends TreemaNode.nodeMap.object
|
|||
class ChannelNode extends TreemaNode.nodeMap.string
|
||||
buildValueForEditing: (valEl) ->
|
||||
super(valEl)
|
||||
valEl.find('input').autocomplete(source: channels, minLength: 0, delay: 0, autoFocus: true)
|
||||
autocompleteValues = ({label: val?.title or key, value: key} for key, val of Backbone.Mediator.channelSchemas)
|
||||
valEl.find('input').autocomplete(source: autocompleteValues, minLength: 0, delay: 0, autoFocus: true)
|
||||
valEl
|
||||
|
||||
channels = [
|
||||
"tome:palette-hovered",
|
||||
"tome:palette-clicked",
|
||||
"tome:spell-shown",
|
||||
"end-current-script",
|
||||
"goal-manager:new-goal-states",
|
||||
"god:new-world-created",
|
||||
"help-multiplayer",
|
||||
"help-next",
|
||||
"help-overview",
|
||||
"level-restart-ask",
|
||||
"level-set-playing",
|
||||
"level:docs-hidden",
|
||||
"level:team-set",
|
||||
"playback:manually-scrubbed",
|
||||
"sprite:speech-updated",
|
||||
"surface:coordinates-shown",
|
||||
"surface:frame-changed",
|
||||
"surface:sprite-selected",
|
||||
"world:thang-attacked-when-out-of-range",
|
||||
"world:thang-collected-item",
|
||||
"world:thang-died",
|
||||
"world:thang-left-map",
|
||||
"world:thang-touched-goal",
|
||||
"world:won"
|
||||
]
|
||||
|
|
|
@ -51,4 +51,5 @@ module.exports = class SettingsTabView extends View
|
|||
onSettingsChanged: (e) =>
|
||||
$('.level-title').text @settingsTreema.data.name
|
||||
for key in @editableSettings
|
||||
continue unless @settingsTreema.data[key] is undefined
|
||||
@level.set key, @settingsTreema.data[key]
|
||||
|
|
|
@ -194,7 +194,7 @@ module.exports = class ThangsTabView extends View
|
|||
return unless @selectedExtantThang and e.thang?.id is @selectedExtantThang?.id
|
||||
@surface.camera.dragDisabled = true
|
||||
{stageX, stageY} = e.originalEvent
|
||||
wop = @surface.camera.canvasToWorld x: stageX, y: stageY
|
||||
wop = @surface.camera.screenToWorld x: stageX, y: stageY
|
||||
wop.z = @selectedExtantThang.depth / 2
|
||||
@adjustThangPos @selectedExtantSprite, @selectedExtantThang, wop
|
||||
[w, h] = [@surface.camera.canvasWidth, @surface.camera.canvasHeight]
|
||||
|
@ -250,6 +250,7 @@ module.exports = class ThangsTabView extends View
|
|||
# @thangsTreema.deselectAll()
|
||||
|
||||
selectAddThang: (e) =>
|
||||
return if e? and $(e.target).closest('#thang-search').length # Ignore if you're trying to search thangs
|
||||
return unless e? and $(e.target).closest('#editor-level-thangs-tab-view').length or key.isPressed('esc')
|
||||
if e then target = $(e.target) else target = @$el.find('.add-thangs-palette') # pretend to click on background if no event
|
||||
return true if target.attr('id') is 'surface'
|
||||
|
@ -258,7 +259,7 @@ module.exports = class ThangsTabView extends View
|
|||
@$el.find('.add-thangs-palette .add-thang-palette-icon.selected').removeClass('selected')
|
||||
@selectAddThangType(if wasSelected then null else target.attr 'data-thang-type') unless key.alt or key.meta
|
||||
target.addClass('selected') if @addThangType
|
||||
false
|
||||
#false # was causing #1099, any reason to keep?
|
||||
|
||||
moveAddThangSelection: (direction) ->
|
||||
return unless @addThangType
|
||||
|
@ -319,7 +320,7 @@ module.exports = class ThangsTabView extends View
|
|||
|
||||
onSurfaceMouseMoved: (e) ->
|
||||
return unless @addThangSprite
|
||||
wop = @surface.camera.canvasToWorld x: e.x, y: e.y
|
||||
wop = @surface.camera.screenToWorld x: e.x, y: e.y
|
||||
wop.z = 0.5
|
||||
@adjustThangPos @addThangSprite, @addThangSprite.thang, wop
|
||||
null
|
||||
|
|
|
@ -8,6 +8,7 @@ module.exports = class PatchModal extends ModalView
|
|||
template: template
|
||||
plain: true
|
||||
modalWidthPercent: 60
|
||||
@DOC_SKIP_PATHS = ['_id','version', 'commitMessage', 'parent', 'created', 'slug', 'index', '__v', 'patches']
|
||||
|
||||
events:
|
||||
'click #withdraw-button': 'withdrawPatch'
|
||||
|
@ -36,14 +37,16 @@ module.exports = class PatchModal extends ModalView
|
|||
headModel = null
|
||||
if @targetModel.hasWriteAccess()
|
||||
headModel = @originalSource.clone(false)
|
||||
headModel.markToRevert true
|
||||
headModel.set(@targetModel.attributes)
|
||||
headModel.loaded = true
|
||||
|
||||
pendingModel = @originalSource.clone(false)
|
||||
pendingModel.markToRevert true
|
||||
pendingModel.applyDelta(@patch.get('delta'))
|
||||
pendingModel.loaded = true
|
||||
|
||||
@deltaView = new DeltaView({model:pendingModel, headModel:headModel})
|
||||
@deltaView = new DeltaView({model:pendingModel, headModel:headModel, skipPaths: PatchModal.DOC_SKIP_PATHS})
|
||||
changeEl = @$el.find('.changes-stub')
|
||||
@insertSubView(@deltaView, changeEl)
|
||||
super()
|
||||
|
|
|
@ -2,6 +2,7 @@ ModalView = require 'views/kinds/ModalView'
|
|||
template = require 'templates/modal/versions'
|
||||
tableTemplate = require 'templates/kinds/table'
|
||||
DeltaView = require 'views/editor/delta'
|
||||
PatchModal = require 'views/editor/patch_modal'
|
||||
|
||||
class VersionsViewCollection extends Backbone.Collection
|
||||
url: ""
|
||||
|
@ -49,7 +50,7 @@ module.exports = class VersionsModalView extends ModalView
|
|||
|
||||
laterVersion = new @model(_id:$(rows[0]).val())
|
||||
earlierVersion = new @model(_id:$(rows[1]).val())
|
||||
@deltaView = new DeltaView({model:earlierVersion, comparisonModel:laterVersion, skipPaths:['_id','version', 'commitMessage', 'parent', 'created', 'slug', 'index']})
|
||||
@deltaView = new DeltaView({model:earlierVersion, comparisonModel:laterVersion, skipPaths:PatchModal.DOC_SKIP_PATHS})
|
||||
@insertSubView(@deltaView, deltaEl)
|
||||
|
||||
getRenderData: (context={}) ->
|
||||
|
|
|
@ -325,7 +325,8 @@ module.exports = class Handler
|
|||
newDocument.save (err) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, @formatEntity(req, newDocument))
|
||||
@notifyWatchersOfChange(req.user, newDocument, req.body.editPath) if @modelClass.schema.is_patchable
|
||||
if @modelClass.schema.is_patchable
|
||||
@notifyWatchersOfChange(req.user, newDocument, req.headers['x-current-path'])
|
||||
|
||||
if major?
|
||||
parentDocument.makeNewMinorVersion(updatedObject, major, done)
|
||||
|
|
Loading…
Reference in a new issue