mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-05-01 08:23:57 -04:00
Merge branch 'master' into production
This commit is contained in:
commit
69118206ab
26 changed files with 149 additions and 37 deletions
app
core
lib
locale
schemas
styles
templates
views
server/levels
|
@ -58,7 +58,7 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
|
||||||
console.error 'Unable to save G+ token key', e
|
console.error 'Unable to save G+ token key', e
|
||||||
@accessToken = e
|
@accessToken = e
|
||||||
@trigger 'logged-in'
|
@trigger 'logged-in'
|
||||||
|
|
||||||
loginCodeCombat: ->
|
loginCodeCombat: ->
|
||||||
# email and profile data loaded separately
|
# email and profile data loaded separately
|
||||||
gapi.client.request(path: plusURL, callback: @onPersonEntityReceived)
|
gapi.client.request(path: plusURL, callback: @onPersonEntityReceived)
|
||||||
|
@ -71,7 +71,8 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass
|
||||||
for gpProp, userProp of userPropsToSave
|
for gpProp, userProp of userPropsToSave
|
||||||
keys = gpProp.split('.')
|
keys = gpProp.split('.')
|
||||||
value = r
|
value = r
|
||||||
value = value[key] for key in keys
|
for key in keys
|
||||||
|
value = value[key]
|
||||||
if value and not me.get(userProp)
|
if value and not me.get(userProp)
|
||||||
@shouldSave = true
|
@shouldSave = true
|
||||||
me.set(userProp, value)
|
me.set(userProp, value)
|
||||||
|
|
|
@ -459,6 +459,44 @@ class SlugPropsObject extends TreemaNode.nodeMap.object
|
||||||
return res if @workingSchema.properties?[res]?
|
return res if @workingSchema.properties?[res]?
|
||||||
_.string.slugify(res)
|
_.string.slugify(res)
|
||||||
|
|
||||||
|
class TaskTreema extends TreemaNode.nodeMap.string
|
||||||
|
buildValueForDisplay: (valEl) ->
|
||||||
|
@taskCheckbox = $('<input type="checkbox">').prop 'checked', @data.complete
|
||||||
|
task = $("<span>#{@data.name}</span>")
|
||||||
|
valEl.append(@taskCheckbox).append(task)
|
||||||
|
@taskCheckbox.on 'change', @onTaskChanged
|
||||||
|
|
||||||
|
buildValueForEditing: (valEl, data) ->
|
||||||
|
@nameInput = @buildValueForEditingSimply(valEl, data.name)
|
||||||
|
@nameInput.parent().prepend(@taskCheckbox)
|
||||||
|
|
||||||
|
onTaskChanged: (e) =>
|
||||||
|
@markAsChanged()
|
||||||
|
@saveChanges()
|
||||||
|
@flushChanges()
|
||||||
|
@broadcastChanges()
|
||||||
|
|
||||||
|
onEditInputBlur: (e) =>
|
||||||
|
@markAsChanged()
|
||||||
|
@saveChanges()
|
||||||
|
if @isValid() then @display() if @isEditing() else @nameInput.focus().select()
|
||||||
|
@flushChanges()
|
||||||
|
@broadcastChanges()
|
||||||
|
|
||||||
|
saveChanges: (oldData) ->
|
||||||
|
@data ?= {}
|
||||||
|
@data.name = @nameInput.val() if @nameInput
|
||||||
|
@data.complete = Boolean(@taskCheckbox.prop 'checked')
|
||||||
|
|
||||||
|
destroy: ->
|
||||||
|
@taskCheckbox.off()
|
||||||
|
super()
|
||||||
|
|
||||||
|
|
||||||
|
#class CheckboxTreema extends TreemaNode.nodeMap.boolean
|
||||||
|
# TODO: try this out
|
||||||
|
|
||||||
|
|
||||||
module.exports.setup = ->
|
module.exports.setup = ->
|
||||||
TreemaNode.setNodeSubclass('date-time', DateTimeTreema)
|
TreemaNode.setNodeSubclass('date-time', DateTimeTreema)
|
||||||
TreemaNode.setNodeSubclass('version', VersionTreema)
|
TreemaNode.setNodeSubclass('version', VersionTreema)
|
||||||
|
@ -475,3 +513,5 @@ module.exports.setup = ->
|
||||||
TreemaNode.setNodeSubclass('i18n', InternationalizationNode)
|
TreemaNode.setNodeSubclass('i18n', InternationalizationNode)
|
||||||
TreemaNode.setNodeSubclass('sound-file', SoundFileTreema)
|
TreemaNode.setNodeSubclass('sound-file', SoundFileTreema)
|
||||||
TreemaNode.setNodeSubclass 'slug-props', SlugPropsObject
|
TreemaNode.setNodeSubclass 'slug-props', SlugPropsObject
|
||||||
|
TreemaNode.setNodeSubclass 'task', TaskTreema
|
||||||
|
#TreemaNode.setNodeSubclass 'checkbox', CheckboxTreema
|
||||||
|
|
|
@ -62,9 +62,9 @@ module.exports = class SpriteParser
|
||||||
break
|
break
|
||||||
continue unless container.bounds and instructions.length
|
continue unless container.bounds and instructions.length
|
||||||
@addContainer {c: instructions, b: container.bounds}, container.name
|
@addContainer {c: instructions, b: container.bounds}, container.name
|
||||||
|
|
||||||
childrenMovieClips = []
|
childrenMovieClips = []
|
||||||
|
|
||||||
for movieClip, index in movieClips
|
for movieClip, index in movieClips
|
||||||
lastBounds = null
|
lastBounds = null
|
||||||
# fill in bounds which are null...
|
# fill in bounds which are null...
|
||||||
|
@ -73,7 +73,7 @@ module.exports = class SpriteParser
|
||||||
movieClip.frameBounds[boundsIndex] = _.clone(lastBounds)
|
movieClip.frameBounds[boundsIndex] = _.clone(lastBounds)
|
||||||
else
|
else
|
||||||
lastBounds = bounds
|
lastBounds = bounds
|
||||||
|
|
||||||
localGraphics = @getGraphicsFromBlock(movieClip, source)
|
localGraphics = @getGraphicsFromBlock(movieClip, source)
|
||||||
[shapeKeys, localShapes] = @getShapesFromBlock movieClip, source
|
[shapeKeys, localShapes] = @getShapesFromBlock movieClip, source
|
||||||
localContainers = @getContainersFromMovieClip movieClip, source, true
|
localContainers = @getContainersFromMovieClip movieClip, source, true
|
||||||
|
@ -90,7 +90,7 @@ module.exports = class SpriteParser
|
||||||
bounds: movieClip.bounds
|
bounds: movieClip.bounds
|
||||||
frameBounds: movieClip.frameBounds
|
frameBounds: movieClip.frameBounds
|
||||||
}, movieClip.name
|
}, movieClip.name
|
||||||
|
|
||||||
for movieClip in movieClips
|
for movieClip in movieClips
|
||||||
if movieClip.name not in childrenMovieClips
|
if movieClip.name not in childrenMovieClips
|
||||||
for bounds in movieClip.frameBounds
|
for bounds in movieClip.frameBounds
|
||||||
|
@ -390,7 +390,7 @@ module.exports = class SpriteParser
|
||||||
name = node.callee.property?.name
|
name = node.callee.property?.name
|
||||||
return unless name in ['get', 'to', 'wait']
|
return unless name in ['get', 'to', 'wait']
|
||||||
return if name is 'get' and callExpressions.length # avoid Ease calls in the tweens
|
return if name is 'get' and callExpressions.length # avoid Ease calls in the tweens
|
||||||
flattenedRanges = _.flatten [a.range for a in node.arguments]
|
flattenedRanges = _.flatten [(a.range for a in node.arguments)]
|
||||||
range = [_.min(flattenedRanges), _.max(flattenedRanges)]
|
range = [_.min(flattenedRanges), _.max(flattenedRanges)]
|
||||||
# Replace 'this.<local>' references with just the 'name'
|
# Replace 'this.<local>' references with just the 'name'
|
||||||
argsSource = @subSourceFromRange(range, source)
|
argsSource = @subSourceFromRange(range, source)
|
||||||
|
|
|
@ -326,7 +326,7 @@ module.exports = Lank = class Lank extends CocoClass
|
||||||
|
|
||||||
newScaleFactorX = @thang?.scaleFactorX ? @thang?.scaleFactor ? 1
|
newScaleFactorX = @thang?.scaleFactorX ? @thang?.scaleFactor ? 1
|
||||||
newScaleFactorY = @thang?.scaleFactorY ? @thang?.scaleFactor ? 1
|
newScaleFactorY = @thang?.scaleFactorY ? @thang?.scaleFactor ? 1
|
||||||
if @thang?.spriteName is 'Beam'
|
if @layer?.name is 'Land' or @thang?.spriteName is 'Beam'
|
||||||
@scaleFactorX = newScaleFactorX
|
@scaleFactorX = newScaleFactorX
|
||||||
@scaleFactorY = newScaleFactorY
|
@scaleFactorY = newScaleFactorY
|
||||||
else if @thang and (newScaleFactorX isnt @targetScaleFactorX or newScaleFactorY isnt @targetScaleFactorY)
|
else if @thang and (newScaleFactorX isnt @targetScaleFactorX or newScaleFactorY isnt @targetScaleFactorY)
|
||||||
|
|
|
@ -65,12 +65,12 @@ module.exports = class SingularSprite extends createjs.Sprite
|
||||||
@regY = -reg.y * scale
|
@regY = -reg.y * scale
|
||||||
@scaleX = @scaleY = 1 / @resolutionFactor
|
@scaleX = @scaleY = 1 / @resolutionFactor
|
||||||
|
|
||||||
if @camera and @thangType.get('name') in floors
|
|
||||||
@baseScaleY *= @camera.y2x
|
|
||||||
@scaleX *= -1 if action.flipX
|
@scaleX *= -1 if action.flipX
|
||||||
@scaleY *= -1 if action.flipY
|
@scaleY *= -1 if action.flipY
|
||||||
@baseScaleX = @scaleX
|
@baseScaleX = @scaleX
|
||||||
@baseScaleY = @scaleY
|
@baseScaleY = @scaleY
|
||||||
|
if @camera and @thangType.get('name') in floors
|
||||||
|
@baseScaleY *= @camera.y2x
|
||||||
@currentAnimation = actionName
|
@currentAnimation = actionName
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ module.exports = class System
|
||||||
hashString: (s) ->
|
hashString: (s) ->
|
||||||
return @hashes[s] if s of @hashes
|
return @hashes[s] if s of @hashes
|
||||||
hash = 0
|
hash = 0
|
||||||
hash = hash * 31 + s.charCodeAt(i) for i in [0 ... Math.min(s.length, 100)]
|
for i in [0 ... Math.min(s.length, 100)]
|
||||||
|
hash = hash * 31 + s.charCodeAt(i)
|
||||||
hash = @hashes[s] = hash % 3.141592653589793
|
hash = @hashes[s] = hash % 3.141592653589793
|
||||||
hash
|
hash
|
||||||
|
|
||||||
|
|
|
@ -480,6 +480,8 @@
|
||||||
forum_prefix: "For anything public, please try "
|
forum_prefix: "For anything public, please try "
|
||||||
forum_page: "our forum"
|
forum_page: "our forum"
|
||||||
forum_suffix: " instead."
|
forum_suffix: " instead."
|
||||||
|
faq_prefix: "There's also a"
|
||||||
|
faq: "FAQ"
|
||||||
subscribe_prefix: "If you need help figuring out a level, please"
|
subscribe_prefix: "If you need help figuring out a level, please"
|
||||||
subscribe: "buy a CodeCombat subscription"
|
subscribe: "buy a CodeCombat subscription"
|
||||||
subscribe_suffix: "and we'll be happy to help you with your code."
|
subscribe_suffix: "and we'll be happy to help you with your code."
|
||||||
|
|
|
@ -1,6 +1,48 @@
|
||||||
c = require './../schemas'
|
c = require './../schemas'
|
||||||
ThangComponentSchema = require './thang_component'
|
ThangComponentSchema = require './thang_component'
|
||||||
|
|
||||||
|
defaultTasks = [
|
||||||
|
'Name the level.'
|
||||||
|
'Create a Referee stub, if needed.'
|
||||||
|
'Build the level.'
|
||||||
|
'Set up goals.'
|
||||||
|
'Choose the Existence System lifespan and frame rate.'
|
||||||
|
'Choose the UI System paths and coordinate hover if needed.'
|
||||||
|
'Choose the AI System pathfinding and Vision System line of sight.'
|
||||||
|
'Write the sample code.'
|
||||||
|
|
||||||
|
'Do basic set decoration.'
|
||||||
|
'Adjust script camera bounds.'
|
||||||
|
'Choose music file in Introduction script.'
|
||||||
|
|
||||||
|
'Add to a campaign.'
|
||||||
|
'Publish for playtesting.'
|
||||||
|
'Choose level options like required/restricted gear.'
|
||||||
|
'Create achievements, including unlocking next level.'
|
||||||
|
|
||||||
|
'Playtest with a slow/tough hero.'
|
||||||
|
'Playtest with a fast/weak hero.'
|
||||||
|
'Playtest with a couple random seeds.'
|
||||||
|
'Make sure the level ends promptly on success and failure.'
|
||||||
|
'Remove/simplify unnecessary doodad collision.'
|
||||||
|
'Release to adventurers.'
|
||||||
|
|
||||||
|
'Write the description.'
|
||||||
|
'Translate the sample code comments.'
|
||||||
|
'Add Io/Clojure/Lua/CoffeeScript.'
|
||||||
|
'Write the guide.'
|
||||||
|
'Write a loading tip, if needed.'
|
||||||
|
'Populate i18n.'
|
||||||
|
|
||||||
|
'Mark whether it requires a subscription (after adventurer week).'
|
||||||
|
'Release to everyone.'
|
||||||
|
|
||||||
|
'Check completion/engagement/problem analytics.'
|
||||||
|
'Do any custom scripting, if needed.'
|
||||||
|
'Do thorough set decoration.'
|
||||||
|
'Add a walkthrough video.'
|
||||||
|
]
|
||||||
|
|
||||||
SpecificArticleSchema = c.object()
|
SpecificArticleSchema = c.object()
|
||||||
c.extendNamedProperties SpecificArticleSchema # name first
|
c.extendNamedProperties SpecificArticleSchema # name first
|
||||||
SpecificArticleSchema.properties.body = {type: 'string', title: 'Content', description: 'The body content of the article, in Markdown.', format: 'markdown'}
|
SpecificArticleSchema.properties.body = {type: 'string', title: 'Content', description: 'The body content of the article, in Markdown.', format: 'markdown'}
|
||||||
|
@ -252,6 +294,7 @@ _.extend LevelSchema.properties,
|
||||||
terrain: c.terrainString
|
terrain: c.terrainString
|
||||||
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
||||||
requiresSubscription: {title: 'Requires Subscription', description: 'Whether this level is available to subscribers only.', type: 'boolean'}
|
requiresSubscription: {title: 'Requires Subscription', description: 'Whether this level is available to subscribers only.', type: 'boolean'}
|
||||||
|
tasks: c.array {title: 'Tasks', description: 'Tasks to be completed for this level.', default: (name: t for t in defaultTasks)}, c.task
|
||||||
|
|
||||||
c.extendBasicProperties LevelSchema, 'level'
|
c.extendBasicProperties LevelSchema, 'level'
|
||||||
c.extendSearchableProperties LevelSchema
|
c.extendSearchableProperties LevelSchema
|
||||||
|
|
|
@ -228,3 +228,7 @@ me.RewardSchema = (descriptionFragment='earned by achievements') ->
|
||||||
levels: me.array {uniqueItems: true, description: "Levels #{descriptionFragment}."},
|
levels: me.array {uniqueItems: true, description: "Levels #{descriptionFragment}."},
|
||||||
me.stringID(links: [{rel: 'db', href: '/db/level/{($)}/version'}], title: 'Level', description: 'A reference to the earned Level.', format: 'latest-version-original-reference')
|
me.stringID(links: [{rel: 'db', href: '/db/level/{($)}/version'}], title: 'Level', description: 'A reference to the earned Level.', format: 'latest-version-original-reference')
|
||||||
gems: me.int {description: "Gems #{descriptionFragment}."}
|
gems: me.int {description: "Gems #{descriptionFragment}."}
|
||||||
|
|
||||||
|
me.task = me.object {title: 'Task', description: 'A task to be completed', format: 'task', default: {name: 'TODO', complete: false}},
|
||||||
|
name: {title: 'Name', description: 'What must be done?', type: 'string'}
|
||||||
|
complete: {title: 'Complete', description: 'Whether this task is done.', type: 'boolean', format: 'checkbox'}
|
||||||
|
|
|
@ -378,3 +378,8 @@ body > iframe[src^="https://apis.google.com"]
|
||||||
|
|
||||||
.progress-bar
|
.progress-bar
|
||||||
background-color: lightblue
|
background-color: lightblue
|
||||||
|
|
||||||
|
.treema-node input[type='checkbox']
|
||||||
|
@include scale(1.25)
|
||||||
|
width: auto
|
||||||
|
margin: 8px 15px 8px 15px
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
#components-treema
|
#components-treema
|
||||||
z-index: 11
|
z-index: 11
|
||||||
|
|
||||||
|
.not-present
|
||||||
|
opacity: 0.75
|
||||||
|
|
||||||
.edit-component-container
|
.edit-component-container
|
||||||
margin-left: 290px
|
margin-left: 290px
|
||||||
position: absolute
|
position: absolute
|
||||||
|
|
|
@ -9,10 +9,11 @@ block content
|
||||||
li.active(data-i18n="#{currentEditor}")
|
li.active(data-i18n="#{currentEditor}")
|
||||||
| #{currentEditor}
|
| #{currentEditor}
|
||||||
|
|
||||||
if me.get('anonymous')
|
if me.isAdmin() || !newModelsAdminOnly
|
||||||
a.btn.btn-primary.open-modal-button(data-toggle="coco-modal", data-target="core/AuthModal", role="button", data-i18n="#{currentNewSignup}") Log in to Create a New Content
|
if me.get('anonymous')
|
||||||
else
|
a.btn.btn-primary.open-modal-button(data-toggle="coco-modal", data-target="core/AuthModal", role="button", data-i18n="#{currentNewSignup}") Log in to Create a New Something
|
||||||
a.btn.btn-primary.open-modal-button#new-model-button(data-i18n="#{currentNew}") Create a New Something
|
else
|
||||||
|
a.btn.btn-primary.open-modal-button#new-model-button(data-i18n="#{currentNew}") Create a New Something
|
||||||
input#search(data-i18n="[placeholder]#{currentSearch}")
|
input#search(data-i18n="[placeholder]#{currentSearch}")
|
||||||
hr
|
hr
|
||||||
div.results
|
div.results
|
||||||
|
|
|
@ -9,6 +9,9 @@ block modal-body-content
|
||||||
span.spl(data-i18n="contact.forum_prefix") For anything public, please try
|
span.spl(data-i18n="contact.forum_prefix") For anything public, please try
|
||||||
a(href="http://discourse.codecombat.com/", data-i18n="contact.forum_page") our forum
|
a(href="http://discourse.codecombat.com/", data-i18n="contact.forum_page") our forum
|
||||||
span(data-i18n="contact.forum_suffix") instead.
|
span(data-i18n="contact.forum_suffix") instead.
|
||||||
|
span.spl.spr(data-i18n="contact.faq_prefix") There's also a
|
||||||
|
a(data-i18n="contact.faq", href="http://discourse.codecombat.com/t/faq-check-before-posting/1027") FAQ
|
||||||
|
| .
|
||||||
if me.isPremium()
|
if me.isPremium()
|
||||||
p(data-i18n="contact.subscriber_support") Since you're a CodeCombat subscriber, your email will get our priority support.
|
p(data-i18n="contact.subscriber_support") Since you're a CodeCombat subscriber, your email will get our priority support.
|
||||||
else
|
else
|
||||||
|
|
|
@ -92,9 +92,9 @@ block header
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=anonymous ? "disabled": "")
|
||||||
a(data-i18n="common.fork")#fork-start-button Fork
|
a(data-i18n="common.fork")#fork-start-button Fork
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=anonymous ? "disabled": "")
|
||||||
a(data-toggle="coco-modal", data-target="modal/RevertModal", data-i18n="editor.revert")#revert-button Revert
|
a(data-toggle="coco-modal", data-target="modal/RevertModal", data-i18n="editor.revert", disabled=anonymous)#revert-button Revert
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=anonymous ? "disabled": "")
|
||||||
a(data-toggle="coco-modal", data-target="editor/level/modals/GenerateTerrainModal", data-i18n="editor.generate_terrain").generate-terrain-button Generate Terrain
|
a(data-toggle="coco-modal", data-target="editor/level/modals/GenerateTerrainModal", data-i18n="editor.generate_terrain", disabled=anonymous).generate-terrain-button Generate Terrain
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=anonymous ? "disabled": "")
|
||||||
a(data-i18n="editor.pop_i18n")#pop-level-i18n-button Populate i18n
|
a(data-i18n="editor.pop_i18n")#pop-level-i18n-button Populate i18n
|
||||||
li.divider
|
li.divider
|
||||||
|
|
|
@ -52,11 +52,11 @@ block header
|
||||||
span.glyphicon-chevron-down.glyphicon
|
span.glyphicon-chevron-down.glyphicon
|
||||||
ul.dropdown-menu
|
ul.dropdown-menu
|
||||||
li.dropdown-header(data-i18n="common.actions") Actions
|
li.dropdown-header(data-i18n="common.actions") Actions
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=!me.isAdmin() ? "disabled": "")
|
||||||
a(data-i18n="common.fork")#fork-start-button Fork
|
a(data-i18n="common.fork")#fork-start-button Fork
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=!authorized ? "disabled": "")
|
||||||
a(data-toggle="coco-modal", data-target="modal/RevertModal", data-i18n="editor.revert")#revert-button Revert
|
a(data-toggle="coco-modal", data-target="modal/RevertModal", data-i18n="editor.revert", disabled=!authorized)#revert-button Revert
|
||||||
li(class=anonymous ? "disabled": "")
|
li(class=!authorized ? "disabled": "")
|
||||||
a(data-i18n="editor.pop_i18n")#pop-level-i18n-button Populate i18n
|
a(data-i18n="editor.pop_i18n")#pop-level-i18n-button Populate i18n
|
||||||
li.divider
|
li.divider
|
||||||
li.dropdown-header(data-i18n="common.info") Info
|
li.dropdown-header(data-i18n="common.info") Info
|
||||||
|
|
|
@ -199,6 +199,7 @@ module.exports = class CocoView extends Backbone.View
|
||||||
# special handler for opening modals that are dynamically loaded, rather than static in the page. It works (or should work) like Bootstrap's modals, except use coco-modal for the data-toggle value.
|
# special handler for opening modals that are dynamically loaded, rather than static in the page. It works (or should work) like Bootstrap's modals, except use coco-modal for the data-toggle value.
|
||||||
elem = $(e.target)
|
elem = $(e.target)
|
||||||
return unless elem.data('toggle') is 'coco-modal'
|
return unless elem.data('toggle') is 'coco-modal'
|
||||||
|
return if elem.attr('disabled')
|
||||||
target = elem.data('target')
|
target = elem.data('target')
|
||||||
Modal = require 'views/'+target
|
Modal = require 'views/'+target
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
|
@ -6,7 +6,6 @@ module.exports = class ForkModal extends ModalView
|
||||||
id: 'fork-modal'
|
id: 'fork-modal'
|
||||||
template: template
|
template: template
|
||||||
instant: false
|
instant: false
|
||||||
modalWidthPercent: 60
|
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click #fork-model-confirm-button': 'forkModel'
|
'click #fork-model-confirm-button': 'forkModel'
|
||||||
|
|
|
@ -14,6 +14,7 @@ module.exports = class AchievementSearchView extends SearchView
|
||||||
context.currentNew = 'editor.new_achievement_title'
|
context.currentNew = 'editor.new_achievement_title'
|
||||||
context.currentNewSignup = 'editor.new_achievement_title_login'
|
context.currentNewSignup = 'editor.new_achievement_title_login'
|
||||||
context.currentSearch = 'editor.achievement_search_title'
|
context.currentSearch = 'editor.achievement_search_title'
|
||||||
|
context.newModelsAdminOnly = true
|
||||||
context.unauthorized = true unless me.isAdmin()
|
context.unauthorized = true unless me.isAdmin()
|
||||||
@$el.i18n()
|
@$el.i18n()
|
||||||
context
|
context
|
||||||
|
|
|
@ -14,5 +14,6 @@ module.exports = class ArticleSearchView extends SearchView
|
||||||
context.currentNew = 'editor.new_article_title'
|
context.currentNew = 'editor.new_article_title'
|
||||||
context.currentNewSignup = 'editor.new_article_title_login'
|
context.currentNewSignup = 'editor.new_article_title_login'
|
||||||
context.currentSearch = 'editor.article_search_title'
|
context.currentSearch = 'editor.article_search_title'
|
||||||
|
context.newModelsAdminOnly = true
|
||||||
@$el.i18n()
|
@$el.i18n()
|
||||||
context
|
context
|
||||||
|
|
|
@ -40,7 +40,7 @@ module.exports = class LevelEditView extends RootView
|
||||||
'click .play-with-team-button': 'onPlayLevel'
|
'click .play-with-team-button': 'onPlayLevel'
|
||||||
'click .play-with-team-parent': 'onPlayLevelTeamSelect'
|
'click .play-with-team-parent': 'onPlayLevelTeamSelect'
|
||||||
'click #commit-level-start-button': 'startCommittingLevel'
|
'click #commit-level-start-button': 'startCommittingLevel'
|
||||||
'click #fork-start-button': 'startForking'
|
'click li:not(.disabled) > #fork-start-button': 'startForking'
|
||||||
'click #level-history-button': 'showVersionHistory'
|
'click #level-history-button': 'showVersionHistory'
|
||||||
'click #undo-button': 'onUndo'
|
'click #undo-button': 'onUndo'
|
||||||
'mouseenter #undo-button': 'showUndoDescription'
|
'mouseenter #undo-button': 'showUndoDescription'
|
||||||
|
@ -50,7 +50,7 @@ module.exports = class LevelEditView extends RootView
|
||||||
'click #components-tab': -> @subviews.editor_level_components_tab_view.refreshLevelThangsTreema @level.get('thangs')
|
'click #components-tab': -> @subviews.editor_level_components_tab_view.refreshLevelThangsTreema @level.get('thangs')
|
||||||
'click #level-patch-button': 'startPatchingLevel'
|
'click #level-patch-button': 'startPatchingLevel'
|
||||||
'click #level-watch-button': 'toggleWatchLevel'
|
'click #level-watch-button': 'toggleWatchLevel'
|
||||||
'click #pop-level-i18n-button': 'onPopulateI18N'
|
'click li:not(.disabled) > #pop-level-i18n-button': 'onPopulateI18N'
|
||||||
'click a[href="#editor-level-documentation"]': 'onClickDocumentationTab'
|
'click a[href="#editor-level-documentation"]': 'onClickDocumentationTab'
|
||||||
'mouseup .nav-tabs > li a': 'toggleTab'
|
'mouseup .nav-tabs > li a': 'toggleTab'
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ module.exports = class LevelEditView extends RootView
|
||||||
showLoading: ($el) ->
|
showLoading: ($el) ->
|
||||||
$el ?= @$el.find('.outer-content')
|
$el ?= @$el.find('.outer-content')
|
||||||
super($el)
|
super($el)
|
||||||
|
|
||||||
getTitle: -> "LevelEditor - " + (@level.get('name') or '...')
|
getTitle: -> "LevelEditor - " + (@level.get('name') or '...')
|
||||||
|
|
||||||
onLoaded: ->
|
onLoaded: ->
|
||||||
|
@ -170,7 +170,7 @@ module.exports = class LevelEditView extends RootView
|
||||||
button = @$el.find('#level-watch-button')
|
button = @$el.find('#level-watch-button')
|
||||||
@level.watch(button.find('.watch').is(':visible'))
|
@level.watch(button.find('.watch').is(':visible'))
|
||||||
button.find('> span').toggleClass('secret')
|
button.find('> span').toggleClass('secret')
|
||||||
|
|
||||||
onPopulateI18N: ->
|
onPopulateI18N: ->
|
||||||
@level.populateI18N()
|
@level.populateI18N()
|
||||||
f = -> document.location.reload()
|
f = -> document.location.reload()
|
||||||
|
|
|
@ -31,7 +31,7 @@ module.exports = class ComponentsTabView extends CocoView
|
||||||
thangType = @supermodel.getModelByOriginal ThangType, thang.thangType
|
thangType = @supermodel.getModelByOriginal ThangType, thang.thangType
|
||||||
for component in thangType.get('components') ? []
|
for component in thangType.get('components') ? []
|
||||||
componentMap[component.original] = component
|
componentMap[component.original] = component
|
||||||
|
|
||||||
for component in thang.components
|
for component in thang.components
|
||||||
componentMap[component.original] = component
|
componentMap[component.original] = component
|
||||||
|
|
||||||
|
@ -45,9 +45,10 @@ module.exports = class ComponentsTabView extends CocoView
|
||||||
componentModelMap = {}
|
componentModelMap = {}
|
||||||
componentModelMap[comp.get('original')] = comp for comp in componentModels
|
componentModelMap[comp.get('original')] = comp for comp in componentModels
|
||||||
components = ({original: key.split('.')[0], majorVersion: parseInt(key.split('.')[1], 10), thangs: value, count: value.length} for key, value of @presentComponents)
|
components = ({original: key.split('.')[0], majorVersion: parseInt(key.split('.')[1], 10), thangs: value, count: value.length} for key, value of @presentComponents)
|
||||||
treemaData = _.sortBy components, (comp) ->
|
components = components.concat ({original: c.get('original'), majorVersion: c.get('version').major, thangs: [], count: 0} for c in componentModels when not @presentComponents[c.get('original') + '.' + c.get('version').major])
|
||||||
comp = componentModelMap[comp.original]
|
treemaData = _.sortBy components, (comp) =>
|
||||||
res = [comp.get('system'), comp.get('name')]
|
component = componentModelMap[comp.original]
|
||||||
|
res = [(if comp.count then 0 else 1), component.get('system'), component.get('name')]
|
||||||
return res
|
return res
|
||||||
|
|
||||||
treemaOptions =
|
treemaOptions =
|
||||||
|
@ -82,7 +83,7 @@ module.exports = class ComponentsTabView extends CocoView
|
||||||
onLevelComponentEditingEnded: (e) ->
|
onLevelComponentEditingEnded: (e) ->
|
||||||
@removeSubView @levelComponentEditView
|
@removeSubView @levelComponentEditView
|
||||||
@levelComponentEditView = null
|
@levelComponentEditView = null
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@componentsTreema?.destroy()
|
@componentsTreema?.destroy()
|
||||||
super()
|
super()
|
||||||
|
@ -98,4 +99,6 @@ class LevelComponentNode extends TreemaObjectNode
|
||||||
comp = _.find @settings.supermodel.getModels(LevelComponent), (m) =>
|
comp = _.find @settings.supermodel.getModels(LevelComponent), (m) =>
|
||||||
m.get('original') is data.original and m.get('version').major is data.majorVersion
|
m.get('original') is data.original and m.get('version').major is data.majorVersion
|
||||||
name = "#{comp.get('system')}.#{comp.get('name')} v#{comp.get('version').major}"
|
name = "#{comp.get('system')}.#{comp.get('name')} v#{comp.get('version').major}"
|
||||||
@buildValueForDisplaySimply valEl, "#{name} (#{count})"
|
result = @buildValueForDisplaySimply valEl, "#{name} (#{count})"
|
||||||
|
result.addClass 'not-present' unless data.count
|
||||||
|
result
|
||||||
|
|
|
@ -14,7 +14,8 @@ module.exports = class SettingsTabView extends CocoView
|
||||||
# not thangs or scripts or the backend stuff
|
# not thangs or scripts or the backend stuff
|
||||||
editableSettings: [
|
editableSettings: [
|
||||||
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
|
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
|
||||||
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription'
|
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription',
|
||||||
|
'tasks'
|
||||||
]
|
]
|
||||||
|
|
||||||
subscriptions:
|
subscriptions:
|
||||||
|
|
|
@ -45,13 +45,13 @@ module.exports = class ThangTypeEditView extends RootView
|
||||||
'click #stop-button': 'stopAnimation'
|
'click #stop-button': 'stopAnimation'
|
||||||
'click #play-button': 'playAnimation'
|
'click #play-button': 'playAnimation'
|
||||||
'click #history-button': 'showVersionHistory'
|
'click #history-button': 'showVersionHistory'
|
||||||
'click #fork-start-button': 'startForking'
|
'click li:not(.disabled) > #fork-start-button': 'startForking'
|
||||||
'click #save-button': 'openSaveModal'
|
'click #save-button': 'openSaveModal'
|
||||||
'click #patches-tab': -> @patchesView.load()
|
'click #patches-tab': -> @patchesView.load()
|
||||||
'click .play-with-level-button': 'onPlayLevel'
|
'click .play-with-level-button': 'onPlayLevel'
|
||||||
'click .play-with-level-parent': 'onPlayLevelSelect'
|
'click .play-with-level-parent': 'onPlayLevelSelect'
|
||||||
'keyup .play-with-level-input': 'onPlayLevelKeyUp'
|
'keyup .play-with-level-input': 'onPlayLevelKeyUp'
|
||||||
'click #pop-level-i18n-button': 'onPopulateLevelI18N'
|
'click li:not(.disabled) > #pop-level-i18n-button': 'onPopulateLevelI18N'
|
||||||
|
|
||||||
|
|
||||||
onClickSetVectorIcon: ->
|
onClickSetVectorIcon: ->
|
||||||
|
|
|
@ -15,6 +15,7 @@ module.exports = class ThangTypeSearchView extends SearchView
|
||||||
context.currentNew = 'editor.new_thang_title'
|
context.currentNew = 'editor.new_thang_title'
|
||||||
context.currentNewSignup = 'editor.new_thang_title_login'
|
context.currentNewSignup = 'editor.new_thang_title_login'
|
||||||
context.currentSearch = 'editor.thang_search_title'
|
context.currentSearch = 'editor.thang_search_title'
|
||||||
|
context.newModelsAdminOnly = true
|
||||||
@$el.i18n()
|
@$el.i18n()
|
||||||
context
|
context
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,8 @@ module.exports = class SpellView extends CocoView
|
||||||
# Lock contiguous section of default code
|
# Lock contiguous section of default code
|
||||||
# Only works for languages without closing delimeters on blocks currently
|
# Only works for languages without closing delimeters on blocks currently
|
||||||
lines = @aceDoc.getAllLines()
|
lines = @aceDoc.getAllLines()
|
||||||
lastRow = row for line, row in lines when not /^\s*$/.test(line)
|
for line, row in lines when not /^\s*$/.test(line)
|
||||||
|
lastRow = row
|
||||||
if lastRow?
|
if lastRow?
|
||||||
@readOnlyRanges.push new Range 0, 0, lastRow, lines[lastRow].length - 1
|
@readOnlyRanges.push new Range 0, 0, lastRow, lines[lastRow].length - 1
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ LevelHandler = class LevelHandler extends Handler
|
||||||
'i18nCoverage'
|
'i18nCoverage'
|
||||||
'loadingTip'
|
'loadingTip'
|
||||||
'requiresSubscription'
|
'requiresSubscription'
|
||||||
|
'tasks'
|
||||||
]
|
]
|
||||||
|
|
||||||
postEditableProperties: ['name']
|
postEditableProperties: ['name']
|
||||||
|
@ -72,7 +73,7 @@ LevelHandler = class LevelHandler extends Handler
|
||||||
Session.findOne(sessionQuery).exec (err, doc) =>
|
Session.findOne(sessionQuery).exec (err, doc) =>
|
||||||
return @sendDatabaseError(res, err) if err
|
return @sendDatabaseError(res, err) if err
|
||||||
return @sendSuccess(res, doc) if doc?
|
return @sendSuccess(res, doc) if doc?
|
||||||
return @sendPaymentRequiredError(res, err) if (not req.user.isPremium()) and level.get('requiresSubscription')
|
return @sendPaymentRequiredError(res, err) if (not req.user.isPremium()) and level.get('requiresSubscription')
|
||||||
@createAndSaveNewSession sessionQuery, req, res
|
@createAndSaveNewSession sessionQuery, req, res
|
||||||
|
|
||||||
createAndSaveNewSession: (sessionQuery, req, res) =>
|
createAndSaveNewSession: (sessionQuery, req, res) =>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue