mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-27 14:33:59 -04:00
Spell palette entries now using property docs from components.
This commit is contained in:
parent
b7be08ac19
commit
dc8c4394e1
8 changed files with 122 additions and 134 deletions
app
lib/world
templates/play/level/tome
views/play/level/tome
server
|
@ -689,109 +689,3 @@ D.spawnedRectangles = class SpawnedRectangles extends Doc
|
|||
}
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
D.pow = class Pow extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns `base` to the `exponent` power, that is, <code>base<sup>exponent</sup></code>.
|
||||
"""
|
||||
|
||||
example: ->
|
||||
"""
|
||||
Math.pow(7, 2); // returns 49
|
||||
"""
|
||||
|
||||
args: ->
|
||||
[
|
||||
new Arg "base", "number", "7", "The base number."
|
||||
new Arg "exponent", "number", "2", "The exponent used to raise the `base`."
|
||||
]
|
||||
|
||||
D.sqrt = class Sqrt extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns the square root of a non-negative number. Equivalent to `Math.pow(x, 0.5)`.
|
||||
"""
|
||||
|
||||
example: ->
|
||||
"""
|
||||
Math.sqrt(49); // returns 7
|
||||
"""
|
||||
|
||||
args: ->
|
||||
[new Arg "x", "number", "49", ""]
|
||||
|
||||
D.sin = class Sin extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns the sine of a number (between -1 and 1).
|
||||
"""
|
||||
|
||||
example: ->
|
||||
"""
|
||||
Math.sin(Math.PI / 4); // returns √2
|
||||
"""
|
||||
|
||||
args: ->
|
||||
[new Arg "x", "number", "Math.PI / 2", "A number in radians."]
|
||||
|
||||
D.cos = class Cos extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns the cosine of a number (between -1 and 1).
|
||||
"""
|
||||
|
||||
example: ->
|
||||
"""
|
||||
Math.cos(3 * Math.PI / 4); // returns -√2
|
||||
"""
|
||||
|
||||
args: ->
|
||||
[new Arg "x", "number", "Math.PI / 2", "A number in radians."]
|
||||
|
||||
D.tan = class Tan extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns the tangent of a number (between -1 and 1).
|
||||
"""
|
||||
|
||||
example: ->
|
||||
"""
|
||||
Math.tan(Math.PI / 4); // returns 0.9999999999999999
|
||||
"""
|
||||
|
||||
args: ->
|
||||
[new Arg "x", "number", "Math.PI / 2", "A number in radians."]
|
||||
|
||||
D.atan2 = class Atan2 extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns the arctangent of the quotient of its arguments--a numeric value between -π and π representing the counterclockwise angle theta of an (x, y) point and the positive X axis.
|
||||
"""
|
||||
|
||||
args: ->
|
||||
[
|
||||
new Arg "y", "number", "90", ""
|
||||
new Arg "x", "number", "15", ""
|
||||
]
|
||||
|
||||
D.PI = class PI extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
The ratio of the circumference of a circle to its diameter, approximately 3.14159.
|
||||
"""
|
||||
|
||||
D.random = class Random extends Doc
|
||||
owner: "Math"
|
||||
doc: ->
|
||||
"""
|
||||
Returns a random number x such that 0 <= x < 1.
|
||||
"""
|
||||
|
|
|
@ -1 +1 @@
|
|||
// Later we'll put the crazy HTML from docs.coffee in here as jade
|
||||
span= doc.title
|
|
@ -0,0 +1,37 @@
|
|||
h4
|
||||
span= doc.shortName
|
||||
| -
|
||||
code.prop-type= doc.type == 'function' && doc.owner == 'this' ? 'method' : doc.type
|
||||
if doc.type != 'function'
|
||||
| (read-only)
|
||||
|
||||
.description!= markedWithImages(doc.description || 'Still undocumented, sorry.')
|
||||
|
||||
if doc.type == 'function'
|
||||
p.example
|
||||
strong Example:
|
||||
div
|
||||
code= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
||||
else
|
||||
p.value
|
||||
strong Current Value:
|
||||
code.current-value(data-prop=doc.name)= value
|
||||
|
||||
if doc.args && doc.args.length
|
||||
p.args
|
||||
strong Parameters:
|
||||
for arg in doc.args
|
||||
div
|
||||
code= arg.name
|
||||
| :
|
||||
code= arg.type
|
||||
if arg.example
|
||||
| (ex:
|
||||
code= arg.example
|
||||
| )
|
||||
if arg.description
|
||||
div!= markedWithImages(arg.description)
|
||||
if arg.default
|
||||
div
|
||||
em Default value:
|
||||
code= arg.default
|
|
@ -1,8 +1,17 @@
|
|||
View = require 'views/kinds/CocoView'
|
||||
template = require 'templates/play/level/tome/spell_palette_entry'
|
||||
popoverTemplate = require 'templates/play/level/tome/spell_palette_entry_popover'
|
||||
{me} = require 'lib/auth'
|
||||
filters = require 'lib/image_filter'
|
||||
Docs = require 'lib/world/docs'
|
||||
{downTheChain} = require 'lib/world/world_utils'
|
||||
|
||||
# If we use marked somewhere else, we'll have to make sure to preserve options
|
||||
marked.setOptions {gfm: true, sanitize: false, smartLists: true, breaks: true}
|
||||
|
||||
markedWithImages = (s) ->
|
||||
s = s.replace /!\[(.*?)\]\((.+)? (\d+) (\d+) ?(.*?)?\)/g, '<img src="/images/docs/$2" alt="$1" title="$1" style="width: $3px; height: $4px;" class="$5"></img>' # setting width/height attrs doesn't prevent flickering, but inline css does
|
||||
marked(s)
|
||||
|
||||
module.exports = class SpellPaletteEntryView extends View
|
||||
tagName: 'div' # Could also try <code> instead of <div>, but would need to adjust colors
|
||||
|
@ -20,41 +29,79 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
super options
|
||||
@thang = options.thang
|
||||
@doc = options.doc
|
||||
@shortenize = options.shortenize
|
||||
if _.isString @doc
|
||||
@doc = name: @doc, type: typeof @thang[@doc]
|
||||
@doc.owner ?= 'this'
|
||||
if options.isSnippet
|
||||
@doc.type = 'snippet'
|
||||
@doc.shortName = @doc.name
|
||||
else
|
||||
suffix = if @doc.type is 'function' then '()' else ''
|
||||
@doc.shortName = "#{@doc.owner}.#{@doc.name}#{suffix};"
|
||||
if @doc.owner is 'this'
|
||||
@doc.shorterName = "#{@doc.name}#{suffix}"
|
||||
else
|
||||
@doc.shorterName = @doc.shortName.replace ';', ''
|
||||
@doc.title = if options.shortenize then @doc.shorterName else @doc.shortName
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.doc = @doc
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
text = if @shortenize then @doc.shorterName else @doc.shortName
|
||||
@$el.text(text).addClass(@doc.type)
|
||||
@$el.attr('title', @doc.title()).popover(
|
||||
@$el.addClass(@doc.type)
|
||||
@$el.popover(
|
||||
animation: true
|
||||
html: true
|
||||
placement: 'top'
|
||||
trigger: 'hover'
|
||||
content: @doc.html()
|
||||
content: @formatPopover()
|
||||
container: @$el.parent().parent().parent()
|
||||
)
|
||||
@$el.on 'show.bs.popover', =>
|
||||
# New, good event
|
||||
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.prop
|
||||
# Bad, old one for old scripts (TODO)
|
||||
Backbone.Mediator.publish 'editor:palette-hovered', thang: @thang, prop: @doc.prop
|
||||
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.name
|
||||
|
||||
formatPopover: ->
|
||||
content = popoverTemplate doc: @doc, value: @formatValue(), marked: marked, markedWithImages: markedWithImages, argumentExamples: (arg.example or arg.default or arg.name for arg in @doc.args ? [])
|
||||
owner = if @doc.owner is 'this' then @thang else window[@doc.owner]
|
||||
content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.'))
|
||||
|
||||
formatValue: (v) ->
|
||||
return '<Function>' if @doc.type is 'function'
|
||||
unless v?
|
||||
if @doc.owner is 'this'
|
||||
v = @thang[@doc.name]
|
||||
else
|
||||
v = window[@doc.owner][@doc.name]
|
||||
if @type is 'number' and not isNaN v
|
||||
if v == Math.round v
|
||||
return v
|
||||
return v.toFixed 2
|
||||
if _.isString v
|
||||
return "\"#{v}\""
|
||||
if v?.id
|
||||
return v.id
|
||||
if v?.name
|
||||
return v.name
|
||||
if _.isArray v
|
||||
return '[' + (@formatValue v2 for v2 in v).join(', ') + ']'
|
||||
v
|
||||
|
||||
onMouseOver: (e) ->
|
||||
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
||||
@doc.thang = @thang
|
||||
@$el.data('bs.popover').options.content = @doc.html()
|
||||
@$el.data('bs.popover').options.content = @formatPopover()
|
||||
@$el.popover('setContent')
|
||||
|
||||
onClick: (e) ->
|
||||
Backbone.Mediator.publish 'tome:palette-clicked', thang: @thang, prop: @doc.prop
|
||||
Backbone.Mediator.publish 'tome:palette-clicked', thang: @thang, prop: @doc.name
|
||||
|
||||
onFrameChanged: (e) ->
|
||||
return unless e.selectedThang?.id is @thang.id
|
||||
@options.thang = @thang = e.selectedThang # Update our thang to the current version
|
||||
@options.doc = @doc = Docs.getDocsFor(@thang, [@doc.prop])[0]
|
||||
@$el.find("code.current-value").text(@doc.formatValue()) # Don't call any functions. (?? What does this mean?)
|
||||
@$el.find("code.current-value").text(@formatValue())
|
||||
|
||||
destroy: ->
|
||||
@$el.off()
|
||||
super()
|
||||
super()
|
||||
|
|
|
@ -4,6 +4,7 @@ template = require 'templates/play/level/tome/spell_palette'
|
|||
filters = require 'lib/image_filter'
|
||||
Docs = require 'lib/world/docs'
|
||||
SpellPaletteEntryView = require './spell_palette_entry_view'
|
||||
LevelComponent = require 'models/LevelComponent'
|
||||
|
||||
module.exports = class SpellPaletteView extends View
|
||||
id: 'spell-palette-view'
|
||||
|
@ -24,13 +25,19 @@ module.exports = class SpellPaletteView extends View
|
|||
@createPalette()
|
||||
|
||||
createPalette: ->
|
||||
docs = Docs.getDocsFor @thang, @thang.programmableProperties
|
||||
docs = docs.concat Docs.getDocsFor(@thang, @thang.programmableSnippets, true)
|
||||
shortenize = docs.length > 6
|
||||
@entries = (@addEntry doc, shortenize for doc in docs)
|
||||
lcs = @supermodel.getModels LevelComponent
|
||||
allDocs = {}
|
||||
allDocs[doc.name] = doc for doc in (lc.get('propertyDocumentation') ? []) for lc in lcs
|
||||
|
||||
addEntry: (doc, shortenize) ->
|
||||
entry = new SpellPaletteEntryView doc: doc, thang: @thang, shortenize: shortenize
|
||||
props = @thang.programmableProperties ? []
|
||||
snippets = @thang.programmableSnippets ? []
|
||||
shortenize = props.length + snippets.length > 6
|
||||
@entries = []
|
||||
@entries.push @addEntry(allDocs[prop] ? prop, shortenize) for prop in props
|
||||
@entries.push @addEntry(allDocs[prop] ? prop, shortenize, true) for prop in snippets
|
||||
|
||||
addEntry: (doc, shortenize, isSnippet=false) ->
|
||||
entry = new SpellPaletteEntryView doc: doc, thang: @thang, shortenize: shortenize, isSnippet: isSnippet
|
||||
@$el.find('.properties').append entry.el
|
||||
entry.render() # Render after appending so that we can access parent container for popover
|
||||
entry
|
||||
|
|
|
@ -175,7 +175,7 @@ module.exports = class TomeView extends View
|
|||
@spellView?.setThang thang
|
||||
@spellTabView?.setThang thang
|
||||
if @spellPaletteView?.thang isnt thang
|
||||
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang
|
||||
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang, supermodel: @supermodel
|
||||
@spellPaletteView.toggleControls {}, spell.view.controlsEnabled # TODO: know when palette should have been disabled but didn't exist
|
||||
|
||||
reloadAllCode: ->
|
||||
|
|
|
@ -31,12 +31,12 @@ me.sound = (props) ->
|
|||
obj = _.cloneDeep(SoundSchema)
|
||||
obj.properties[prop] = props[prop] for prop of props
|
||||
obj
|
||||
|
||||
|
||||
ColorConfigSchema = me.object { format: 'color-sound' },
|
||||
hue: { format: 'range', type: 'number', minimum: 0, maximum: 1 }
|
||||
saturation: { format: 'range', type: 'number', minimum: 0, maximum: 1 }
|
||||
lightness: { format: 'range', type: 'number', minimum: 0, maximum: 1 }
|
||||
|
||||
|
||||
me.colorConfig = (props) ->
|
||||
obj = _.cloneDeep(ColorConfigSchema)
|
||||
obj.properties[prop] = props[prop] for prop of props
|
||||
|
@ -131,6 +131,8 @@ me.getLanguagesObject = -> return Language
|
|||
|
||||
me.classNamePattern = "^[A-Z][A-Za-z0-9]*$" # starts with capital letter; just letters and numbers
|
||||
me.identifierPattern = "^[a-z][A-Za-z0-9]*$" # starts with lowercase letter; just letters and numbers
|
||||
me.constantPattern = "^[A-Z0-9_]+$" # just uppercase letters, underscores, and numbers
|
||||
me.identifierOrConstantPattern = "^([a-z][A-Za-z0-9]*|[A-Z0-9_]+)$"
|
||||
|
||||
me.FunctionArgumentSchema = me.object {
|
||||
title: "Function Argument",
|
||||
|
@ -147,7 +149,7 @@ me.FunctionArgumentSchema = me.object {
|
|||
# not actual JS types, just whatever they describe...
|
||||
type: me.shortString(title: "Type", description: "Intended type of the argument.")
|
||||
example: me.shortString(title: "Example", description: "Example value for the argument.")
|
||||
description: {type: 'string', description: "Description of the argument.", maxLength: 1000}
|
||||
description: {title: "Description", type: 'string', description: "Description of the argument.", maxLength: 1000}
|
||||
"default":
|
||||
title: "Default"
|
||||
description: "Default value of the argument. (Your code should set this.)"
|
||||
|
|
|
@ -23,11 +23,12 @@ PropertyDocumentationSchema = c.object {
|
|||
description: "This Component provides a 'foo' property to satisfy all one's foobar needs. Use it wisely."
|
||||
required: ['name', 'type', 'description']
|
||||
},
|
||||
name: {type: 'string', pattern: c.identifierPattern, title: "Name", description: "Name of the property."}
|
||||
name: {type: 'string', pattern: c.identifierOrConstantPattern, title: "Name", description: "Name of the property."}
|
||||
# not actual JS types, just whatever they describe...
|
||||
type: c.shortString(title: "Type", description: "Intended type of the property.")
|
||||
description: {type: 'string', description: "Description of the property.", maxLength: 1000}
|
||||
description: {title: "Description", type: 'string', description: "Description of the property.", maxLength: 1000}
|
||||
args: c.array {title: "Arguments", description: "If this property has type 'function', then provide documentation for any function arguments."}, c.FunctionArgumentSchema
|
||||
owner: {title: "Owner", type: 'string', description: 'Owner of the property, like "this" or "Math".'}
|
||||
|
||||
DependencySchema = c.object {
|
||||
title: "Component Dependency"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue