Spell palette entries now using property docs from components.

This commit is contained in:
Nick Winter 2014-02-12 16:42:09 -08:00
parent b7be08ac19
commit dc8c4394e1
8 changed files with 122 additions and 134 deletions

View file

@ -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.
"""

View file

@ -1 +1 @@
// Later we'll put the crazy HTML from docs.coffee in here as jade
span= doc.title

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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: ->

View file

@ -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.)"

View file

@ -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"