mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
Improved per-language spell palette and tab documentation.
This commit is contained in:
parent
8c6ee66684
commit
aee95ac5c0
11 changed files with 263 additions and 220 deletions
|
@ -26,7 +26,16 @@ PropertyDocumentationSchema = c.object {
|
|||
name: {type: 'string', 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: {title: "Description", type: 'string', description: "Description of the property.", format: 'markdown', maxLength: 1000}
|
||||
description:
|
||||
oneOf: [
|
||||
{title: "Description", type: 'string', description: "Description of the property.", maxLength: 1000, format: 'markdown'}
|
||||
{
|
||||
type: 'object',
|
||||
title: "Language Descriptions",
|
||||
description: "Property descriptions by code language.",
|
||||
additionalProperties: {type: 'string', description: "Description of the property.", maxLength: 1000, format: 'markdown'}
|
||||
}
|
||||
]
|
||||
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".'}
|
||||
example:
|
||||
|
@ -46,8 +55,26 @@ PropertyDocumentationSchema = c.object {
|
|||
default: {type: 'null'}
|
||||
},
|
||||
type: c.shortString(title: "Type", description: "Type of the return value")
|
||||
example: c.shortString(title: "Example", description: "Example return value")
|
||||
description: {title: "Description", type: 'string', description: "Description of the return value.", maxLength: 1000}
|
||||
example:
|
||||
oneOf: [
|
||||
c.shortString(title: "Example", description: "Example return value")
|
||||
{
|
||||
type: 'object',
|
||||
title: "Language Examples",
|
||||
description: "Example return values by code language.",
|
||||
additionalProperties: c.shortString(description: 'Example return value.', format: 'javascript') # TODO: not JS
|
||||
}
|
||||
]
|
||||
description:
|
||||
oneOf: [
|
||||
{title: "Description", type: 'string', description: "Description of the return value.", maxLength: 1000}
|
||||
{
|
||||
type: 'object',
|
||||
title: "Language Descriptions",
|
||||
description: "Example return values by code language.",
|
||||
additionalProperties: {type: 'string', description: "Description of the return value.", maxLength: 1000}
|
||||
}
|
||||
]
|
||||
|
||||
DependencySchema = c.object {
|
||||
title: "Component Dependency"
|
||||
|
|
|
@ -164,8 +164,26 @@ me.FunctionArgumentSchema = me.object {
|
|||
name: {type: 'string', pattern: me.identifierPattern, title: "Name", description: "Name of the function argument."}
|
||||
# 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: {title: "Description", type: 'string', description: "Description of the argument.", maxLength: 1000}
|
||||
example:
|
||||
oneOf: [
|
||||
me.shortString(title: "Example", description: "Example value for the argument.")
|
||||
{
|
||||
type: 'object',
|
||||
title: "Language Examples",
|
||||
description: "Examples by code language.",
|
||||
additionalProperties: me.shortString(description: 'Example value for the argument.')
|
||||
}
|
||||
]
|
||||
description:
|
||||
oneOf: [
|
||||
{title: "Description", type: 'string', description: "Description of the argument.", maxLength: 1000}
|
||||
{
|
||||
type: 'object',
|
||||
title: "Language Descriptions",
|
||||
description: "Example argument descriptions by code language.",
|
||||
additionalProperties: {type: 'string', description: "Description of the argument.", maxLength: 1000}
|
||||
}
|
||||
]
|
||||
"default":
|
||||
title: "Default"
|
||||
description: "Default value of the argument. (Your code should set this.)"
|
||||
|
|
|
@ -90,4 +90,6 @@ module.exports =
|
|||
properties:
|
||||
spell:
|
||||
type: "object"
|
||||
language:
|
||||
type: "string"
|
||||
required: ["spell"]
|
||||
|
|
|
@ -4,54 +4,59 @@ block content
|
|||
|
||||
h1#site-slogan(data-i18n="home.slogan") Learn to Code by Playing a Game
|
||||
|
||||
.code-languages
|
||||
.primary-code-languages.row
|
||||
.col-md-6
|
||||
.code-language#javascript(data-code-language='javascript')
|
||||
.code-wizard
|
||||
h2 JavaScript
|
||||
p The language of the web. Great for writing websites, web apps, HTML5 games, and servers.
|
||||
|
||||
.col-md-6
|
||||
.code-language.beta#python(data-code-language='python')
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h2 Python
|
||||
p Simple yet powerful, Python is a great general purpose programming language.
|
||||
|
||||
.secondary-code-languages.row
|
||||
.col-md-3
|
||||
.code-language.beta#coffeescript(data-code-language='coffeescript')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 CoffeeScript
|
||||
p Nicer JavaScript syntax
|
||||
|
||||
.col-md-3
|
||||
.code-language.beta#clojure(data-code-language='clojure')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 Clojure
|
||||
p A modern Lisp
|
||||
|
||||
.col-md-3
|
||||
.code-language.beta#lua(data-code-language='lua')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 Lua
|
||||
p Game scripting language
|
||||
|
||||
.col-md-3
|
||||
.code-language.beta#io(data-code-language='io')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 Io
|
||||
p Simple but obscure
|
||||
|
||||
if me.isAdmin()
|
||||
// Admin gate until fully tested
|
||||
.code-languages
|
||||
.primary-code-languages.row
|
||||
.col-md-6
|
||||
.code-language#javascript(data-code-language='javascript')
|
||||
.code-wizard
|
||||
h2 JavaScript
|
||||
p The language of the web. Great for writing websites, web apps, HTML5 games, and servers.
|
||||
|
||||
.col-md-6
|
||||
.code-language.beta#python(data-code-language='python')
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h2 Python
|
||||
p Simple yet powerful, Python is a great general purpose programming language.
|
||||
|
||||
.secondary-code-languages.row
|
||||
.col-md-3
|
||||
.code-language.beta#coffeescript(data-code-language='coffeescript')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 CoffeeScript
|
||||
p Nicer JavaScript syntax
|
||||
|
||||
.col-md-3
|
||||
.code-language.beta#clojure(data-code-language='clojure')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 Clojure
|
||||
p A modern Lisp
|
||||
|
||||
.col-md-3
|
||||
.code-language.beta#lua(data-code-language='lua')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 Lua
|
||||
p Game scripting language
|
||||
|
||||
.col-md-3
|
||||
.code-language.beta#io(data-code-language='io')
|
||||
.code-language-logo
|
||||
.code-wizard
|
||||
.code-language-beta
|
||||
h3 Io
|
||||
p Simple but obscure
|
||||
else
|
||||
// Old
|
||||
#front-screenshot
|
||||
img(src="/images/pages/home/front_screenshot_01.png", alt="")
|
||||
|
||||
.alert.alert-danger.lt-ie10
|
||||
strong(data-i18n="home.no_ie") CodeCombat does not run in Internet Explorer 9 or older. Sorry!
|
||||
|
|
|
@ -11,11 +11,22 @@ if doc.example
|
|||
p.example
|
||||
strong Example:
|
||||
div!= marked("```\n" + doc.example + "```")
|
||||
else if doc.type == 'function'
|
||||
else if doc.type == 'function' && argumentExamples.length
|
||||
p.example
|
||||
strong Example:
|
||||
div
|
||||
code= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
||||
if language == 'javascript'
|
||||
code= doc.owner + '.' + doc.name + '(' + argumentExamples.join(', ') + ');'
|
||||
else if language == 'coffeescript'
|
||||
code= doc.ownerName + (doc.ownerName == '@' ? '' : '.') + doc.name + ' ' + argumentExamples.join(', ')
|
||||
else if language == 'python'
|
||||
code= doc.ownerName + '.' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'clojure'
|
||||
code= '(.' + doc.name + ' ' + doc.ownerName + ' ' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'lua'
|
||||
code= doc.ownerName + ':' + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
else if language == 'io'
|
||||
code= (doc.ownerName == 'this' ? '' : doc.ownerName + ' ') + doc.name + '(' + argumentExamples.join(', ') + ')'
|
||||
|
||||
if (doc.type != 'function' && doc.type != 'snippet') || doc.name == 'now'
|
||||
p.value
|
||||
|
|
124
app/views/play/level/tome/doc_formatter.coffee
Normal file
124
app/views/play/level/tome/doc_formatter.coffee
Normal file
|
@ -0,0 +1,124 @@
|
|||
popoverTemplate = require 'templates/play/level/tome/spell_palette_entry_popover'
|
||||
{downTheChain} = require 'lib/world/world_utils'
|
||||
window.Vector = require 'lib/world/vector' # So we can document it
|
||||
|
||||
safeJSONStringify = (input, maxDepth) ->
|
||||
recursion = (input, path, depth) ->
|
||||
output = {}
|
||||
pPath = undefined
|
||||
refIdx = undefined
|
||||
path = path or ""
|
||||
depth = depth or 0
|
||||
depth++
|
||||
return "{depth over " + maxDepth + "}" if maxDepth and depth > maxDepth
|
||||
for p of input
|
||||
pPath = ((if path then (path + ".") else "")) + p
|
||||
if typeof input[p] is "function"
|
||||
output[p] = "{function}"
|
||||
else if typeof input[p] is "object"
|
||||
refIdx = refs.indexOf(input[p])
|
||||
if -1 isnt refIdx
|
||||
output[p] = "{reference to " + refsPaths[refIdx] + "}"
|
||||
else
|
||||
refs.push input[p]
|
||||
refsPaths.push pPath
|
||||
output[p] = recursion(input[p], pPath, depth)
|
||||
else
|
||||
output[p] = input[p]
|
||||
output
|
||||
refs = []
|
||||
refsPaths = []
|
||||
maxDepth = maxDepth or 5
|
||||
if typeof input is "object"
|
||||
output = recursion(input)
|
||||
else
|
||||
output = input
|
||||
JSON.stringify output, null, 1
|
||||
|
||||
module.exports = class DocFormatter
|
||||
constructor: (@options) ->
|
||||
@doc = _.cloneDeep options.doc
|
||||
@fillOutDoc()
|
||||
|
||||
fillOutDoc: ->
|
||||
if _.isString @doc
|
||||
@doc = name: @doc, type: typeof @options.thang[@doc]
|
||||
if @options.isSnippet
|
||||
@doc.type = 'snippet'
|
||||
@doc.owner = 'snippets'
|
||||
@doc.shortName = @doc.shorterName = @doc.title = @doc.name
|
||||
else
|
||||
@doc.owner ?= 'this'
|
||||
ownerName = @doc.ownerName = if @doc.owner isnt 'this' then @doc.owner else switch @options.language
|
||||
when 'python', 'lua' then 'self'
|
||||
when 'coffeescript' then '@'
|
||||
else 'this'
|
||||
if @doc.type is 'function'
|
||||
sep = {clojure: ' '}[@options.language] ? ', '
|
||||
argNames = (arg.name for arg in @doc.args ? []).join sep
|
||||
argString = if argNames then '__ARGS__' else ''
|
||||
@doc.shortName = switch @options.language
|
||||
when 'coffeescript' then "#{ownerName}#{if ownerName is '@' then '' else '.'}#{@doc.name}#{if argString then ' ' + argString else '()'}"
|
||||
when 'python' then "#{ownerName}.#{@doc.name}(#{argString})"
|
||||
when 'lua' then "#{ownerName}:#{@doc.name}(#{argString})"
|
||||
when 'clojure' then "(.#{@doc.name} #{ownerName}#{if argNames then ' ' + argString else ''})"
|
||||
when 'io' then "#{if ownerName is 'this' then '' else ownerName + ' '}#{@doc.name}#{if argNames then '(' + argNames + ')' else ''}"
|
||||
else "#{ownerName}.#{@doc.name}(#{argString});"
|
||||
else
|
||||
@doc.shortName = switch @options.language
|
||||
when 'coffeescript' then "#{ownerName}#{if ownerName is '@' then '' else '.'}#{@doc.name}"
|
||||
when 'python' then "#{ownerName}.#{@doc.name}"
|
||||
when 'lua' then "#{ownerName}.#{@doc.name}"
|
||||
when 'clojure' then "(.#{@doc.name} #{ownerName})"
|
||||
when 'io' then "#{if ownerName is 'this' then '' else ownerName + ' '}#{@doc.name}"
|
||||
else "#{ownerName}.#{@doc.name};"
|
||||
@doc.shorterName = @doc.shortName
|
||||
if @doc.type is 'function' and argString
|
||||
@doc.shortName = @doc.shorterName.replace argString, argNames
|
||||
@doc.shorterName = @doc.shorterName.replace argString, (if argNames.length > 6 then '...' else argNames)
|
||||
if @options.language is 'javascript'
|
||||
@doc.shorterName = @doc.shortName.replace ';', ''
|
||||
if @doc.owner is 'this' or @options.tabbify
|
||||
@doc.shorterName = @doc.shorterName.replace /^this\./, ''
|
||||
@doc.title = if @options.shortenize then @doc.shorterName else @doc.shortName
|
||||
|
||||
# Grab the language-specific documentation for some sub-properties, if we have it.
|
||||
toTranslate = [{obj: @doc, prop: 'example'}, {obj: @doc, prop: 'returns'}]
|
||||
for arg in (@doc.args ? [])
|
||||
toTranslate.push {obj: arg, prop: 'example'}, {obj: arg, prop: 'description'}
|
||||
for {obj, prop} in toTranslate
|
||||
if val = obj[prop]?[@options.language]
|
||||
obj[prop] = val
|
||||
else unless _.isString obj[prop]
|
||||
obj[prop] = null
|
||||
|
||||
formatPopover: ->
|
||||
content = popoverTemplate doc: @doc, language: @options.language, value: @formatValue(), marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in @doc.args ? [])
|
||||
owner = if @doc.owner is 'this' then @options.thang else window[@doc.owner]
|
||||
content = content.replace /#{spriteName}/g, @options.thang.type ? @options.thang.spriteName # Prefer type, and excluded the quotes we'd get with @formatValue
|
||||
content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.'))
|
||||
|
||||
formatValue: (v) ->
|
||||
return null if @doc.type is 'snippet'
|
||||
return @options.thang.now() if @doc.name is 'now'
|
||||
return '[Function]' if not v and @doc.type is 'function'
|
||||
unless v?
|
||||
if @doc.owner is 'this'
|
||||
v = @options.thang[@doc.name]
|
||||
else
|
||||
v = window[@doc.owner][@doc.name] # grab Math or Vector
|
||||
if @doc.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(', ') + ']'
|
||||
if _.isPlainObject v
|
||||
return safeJSONStringify v, 2
|
||||
v
|
|
@ -34,7 +34,7 @@ module.exports = class Spell
|
|||
@thangs = {}
|
||||
@view = new SpellView {spell: @, session: @session, worker: @worker}
|
||||
@view.render() # Get it ready and code loaded in advance
|
||||
@tabView = new SpellListTabEntryView spell: @, supermodel: @supermodel
|
||||
@tabView = new SpellListTabEntryView spell: @, supermodel: @supermodel, language: @language
|
||||
@tabView.render()
|
||||
@team = @permissions.readwrite[0] ? "common"
|
||||
Backbone.Mediator.publish 'tome:spell-created', spell: @
|
||||
|
@ -146,7 +146,7 @@ module.exports = class Spell
|
|||
for thangId, spellThang of @thangs
|
||||
spellThang.aether?.setLanguage @language
|
||||
spellThang.castAether = null
|
||||
Backbone.Mediator.publish 'tome:spell-changed-language', spell: @
|
||||
Backbone.Mediator.publish 'tome:spell-changed-language', spell: @, language: @language
|
||||
workerMessage =
|
||||
function: "updateLanguageAether"
|
||||
newLanguage: @language
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
SpellListEntryView = require './spell_list_entry_view'
|
||||
ThangAvatarView = require 'views/play/level/thang_avatar_view'
|
||||
template = require 'templates/play/level/tome/spell_list_tab_entry'
|
||||
popoverTemplate = require 'templates/play/level/tome/spell_palette_entry_popover'
|
||||
LevelComponent = require 'models/LevelComponent'
|
||||
{downTheChain} = require 'lib/world/world_utils'
|
||||
DocFormatter = require './doc_formatter'
|
||||
|
||||
module.exports = class SpellListTabEntryView extends SpellListEntryView
|
||||
template: template
|
||||
|
@ -13,6 +12,7 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
|
|||
'tome:spell-loaded': "onSpellLoaded"
|
||||
'tome:spell-changed': "onSpellChanged"
|
||||
'god:new-world-created': 'onNewWorld'
|
||||
'tome:spell-changed-language': 'onSpellChangedLanguage'
|
||||
|
||||
events:
|
||||
'click .spell-list-button': 'onDropdownClick'
|
||||
|
@ -60,43 +60,16 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
|
|||
found = true
|
||||
break
|
||||
return unless found
|
||||
doc = _.clone doc
|
||||
doc.owner = 'this'
|
||||
doc.shortName = doc.shorterName = doc.title = "this.#{doc.name}();"
|
||||
docFormatter = new DocFormatter doc: doc, thang: @thang, language: @options.language
|
||||
@$el.find('code').popover(
|
||||
animation: true
|
||||
html: true
|
||||
placement: 'bottom'
|
||||
trigger: 'hover'
|
||||
content: @formatPopover doc
|
||||
content: docFormatter.formatPopover()
|
||||
container: @$el.parent()
|
||||
)
|
||||
|
||||
formatPopover: (doc) ->
|
||||
content = popoverTemplate doc: doc, marked: marked, argumentExamples: (arg.example or arg.default or arg.name for arg in doc.args ? [])
|
||||
owner = @thang
|
||||
content = content.replace /#{spriteName}/g, @thang.type ? @thang.spriteName # Prefer type, and excluded the quotes we'd get with @formatValue
|
||||
content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.'))
|
||||
|
||||
formatValue: (v) ->
|
||||
# TODO: refactor and move spell_palette_entry_view version of this somewhere else
|
||||
# maybe think about making it common with what Aether does and the SpellDebugView, too
|
||||
if _.isNumber 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(', ') + ']'
|
||||
if _.isPlainObject v
|
||||
return safeJSONStringify v, 2
|
||||
v
|
||||
|
||||
onMouseEnterAvatar: (e) -> # Don't call super
|
||||
onMouseLeaveAvatar: (e) -> # Don't call super
|
||||
onClick: (e) -> # Don't call super
|
||||
|
@ -125,6 +98,14 @@ module.exports = class SpellListTabEntryView extends SpellListEntryView
|
|||
return unless e.spell is @spell
|
||||
@updateReloadButton()
|
||||
|
||||
onSpellChangedLanguage: (e) ->
|
||||
return unless e.spell is @spell
|
||||
@options.language = e.language
|
||||
@$el.find('code').popover 'destroy'
|
||||
@render()
|
||||
@docsBuilt = false
|
||||
@buildDocs() if @thang
|
||||
|
||||
toggleControls: (e, enabled) ->
|
||||
# Don't call super; do it differently
|
||||
return if e.controls and not ('editor' in e.controls)
|
||||
|
|
|
@ -1,57 +1,8 @@
|
|||
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'
|
||||
{downTheChain} = require 'lib/world/world_utils'
|
||||
window.Vector = require 'lib/world/vector' # So we can document it
|
||||
|
||||
safeJSONStringify = (input, maxDepth) ->
|
||||
recursion = (input, path, depth) ->
|
||||
output = {}
|
||||
pPath = undefined
|
||||
refIdx = undefined
|
||||
path = path or ""
|
||||
depth = depth or 0
|
||||
depth++
|
||||
return "{depth over " + maxDepth + "}" if maxDepth and depth > maxDepth
|
||||
for p of input
|
||||
pPath = ((if path then (path + ".") else "")) + p
|
||||
if typeof input[p] is "function"
|
||||
output[p] = "{function}"
|
||||
else if typeof input[p] is "object"
|
||||
refIdx = refs.indexOf(input[p])
|
||||
if -1 isnt refIdx
|
||||
output[p] = "{reference to " + refsPaths[refIdx] + "}"
|
||||
else
|
||||
refs.push input[p]
|
||||
refsPaths.push pPath
|
||||
output[p] = recursion(input[p], pPath, depth)
|
||||
else
|
||||
output[p] = input[p]
|
||||
output
|
||||
refs = []
|
||||
refsPaths = []
|
||||
maxDepth = maxDepth or 5
|
||||
if typeof input is "object"
|
||||
output = recursion(input)
|
||||
else
|
||||
output = input
|
||||
JSON.stringify output, null, 1
|
||||
|
||||
# http://stackoverflow.com/a/987376/540620
|
||||
$.fn.selectText = ->
|
||||
el = @[0]
|
||||
if document.body.createTextRange
|
||||
range = document.body.createTextRange()
|
||||
range.moveToElementText(el)
|
||||
range.select()
|
||||
else if window.getSelection
|
||||
selection = window.getSelection()
|
||||
range = document.createRange()
|
||||
range.selectNodeContents(el)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
DocFormatter = require './doc_formatter'
|
||||
|
||||
module.exports = class SpellPaletteEntryView extends View
|
||||
tagName: 'div' # Could also try <code> instead of <div>, but would need to adjust colors
|
||||
|
@ -73,52 +24,8 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
constructor: (options) ->
|
||||
super options
|
||||
@thang = options.thang
|
||||
@doc = options.doc
|
||||
if _.isString @doc
|
||||
@doc = name: @doc, type: typeof @thang[@doc]
|
||||
if options.isSnippet
|
||||
@doc.type = 'snippet'
|
||||
@doc.owner = 'snippets'
|
||||
@doc.shortName = @doc.shorterName = @doc.title = @doc.name
|
||||
else
|
||||
@doc.owner ?= 'this'
|
||||
ownerName = @doc.ownerName = if @doc.owner isnt 'this' then @doc.owner else switch options.language
|
||||
when 'python', 'lua' then 'self'
|
||||
when 'coffeescript' then '@'
|
||||
else 'this'
|
||||
if @doc.type is 'function'
|
||||
sep = {clojure: ' '}[options.language] ? ', '
|
||||
argNames = (arg.name for arg in @doc.args ? []).join sep
|
||||
argString = if argNames then '__ARGS__' else ''
|
||||
@doc.shortName = switch options.language
|
||||
when 'coffeescript' then "#{ownerName}#{if ownerName is '@' then '' else '.'}#{@doc.name}#{if argString then ' ' + argString else '()'}"
|
||||
when 'python' then "#{ownerName}.#{@doc.name}(#{argString})"
|
||||
when 'lua' then "#{ownerName}:#{@doc.name}(#{argString})"
|
||||
when 'clojure' then "(#{@doc.name} #{ownerName}#{if argNames then ' ' + argString else ''})"
|
||||
when 'io' then "#{if ownerName is 'this' then '' else ownerName + ' '}#{@doc.name}#{if argNames then '(' + argNames + ')' else ''}"
|
||||
else "#{ownerName}.#{@doc.name}(#{argString});"
|
||||
else
|
||||
@doc.shortName = switch options.language
|
||||
when 'coffeescript' then "#{ownerName}#{if ownerName is '@' then '' else '.'}#{@doc.name}"
|
||||
when 'python' then "#{ownerName}.#{@doc.name}"
|
||||
when 'lua' then "#{ownerName}.#{@doc.name}"
|
||||
when 'clojure' then "(#{@doc.name} #{ownerName})"
|
||||
when 'io' then "#{if ownerName is 'this' then '' else ownerName + ' '}#{@doc.name}"
|
||||
else "#{ownerName}.#{@doc.name};"
|
||||
@doc.shorterName = @doc.shortName
|
||||
if @doc.type is 'function' and argString
|
||||
@doc.shortName = @doc.shorterName.replace argString, argNames
|
||||
@doc.shorterName = @doc.shorterName.replace argString, (if argNames.length > 6 then '...' else argNames)
|
||||
if @options.language is 'javascript'
|
||||
@doc.shorterName = @doc.shortName.replace ';', ''
|
||||
if @doc.owner is 'this' or options.tabbify
|
||||
@doc.shorterName = @doc.shorterName.replace /^this\./, ''
|
||||
@doc.title = if options.shortenize then @doc.shorterName else @doc.shortName
|
||||
|
||||
if example = @doc.example?[options.language]
|
||||
@doc.example = example
|
||||
else unless _.isString @doc.example
|
||||
@doc.example = null
|
||||
@docFormatter = new DocFormatter options
|
||||
@doc = @docFormatter.doc
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -133,46 +40,15 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
html: true
|
||||
placement: 'top'
|
||||
trigger: 'manual' # Hover, until they click, which will then pin it until unclick.
|
||||
content: @formatPopover()
|
||||
content: @docFormatter.formatPopover()
|
||||
container: '#tome-view'
|
||||
)
|
||||
@$el.on 'show.bs.popover', =>
|
||||
Backbone.Mediator.publish 'tome:palette-hovered', thang: @thang, prop: @doc.name, entry: @
|
||||
|
||||
formatPopover: ->
|
||||
content = popoverTemplate doc: @doc, value: @formatValue(), marked: marked, 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 = content.replace /#{spriteName}/g, @thang.type ? @thang.spriteName # Prefer type, and excluded the quotes we'd get with @formatValue
|
||||
content.replace /\#\{(.*?)\}/g, (s, properties) => @formatValue downTheChain(owner, properties.split('.'))
|
||||
|
||||
formatValue: (v) ->
|
||||
return null if @doc.type is 'snippet'
|
||||
return @thang.now() if @doc.name is 'now'
|
||||
return '[Function]' if not v and @doc.type is 'function'
|
||||
unless v?
|
||||
if @doc.owner is 'this'
|
||||
v = @thang[@doc.name]
|
||||
else
|
||||
v = window[@doc.owner][@doc.name] # grab Math or Vector
|
||||
if @doc.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(', ') + ']'
|
||||
if _.isPlainObject v
|
||||
return safeJSONStringify v, 2
|
||||
v
|
||||
|
||||
onMouseEnter: (e) ->
|
||||
# Make sure the doc has the updated Thang so it can regenerate its prop value
|
||||
@$el.data('bs.popover').options.content = @formatPopover()
|
||||
@$el.data('bs.popover').options.content = @docFormatter.formatPopover()
|
||||
@$el.popover('setContent')
|
||||
@$el.popover 'show' unless @popoverPinned or @otherPopoverPinned
|
||||
|
||||
|
@ -200,7 +76,7 @@ module.exports = class SpellPaletteEntryView extends View
|
|||
|
||||
onFrameChanged: (e) ->
|
||||
return unless e.selectedThang?.id is @thang.id
|
||||
@options.thang = @thang = e.selectedThang # Update our thang to the current version
|
||||
@options.thang = @thang = @docFormatter.options.thang = e.selectedThang # Update our thang to the current version
|
||||
|
||||
onPaletteHovered: (e) ->
|
||||
return if e.entry is @
|
||||
|
|
|
@ -57,7 +57,6 @@ module.exports = class SpellPaletteView extends View
|
|||
allDocs = {}
|
||||
for lc in lcs
|
||||
for doc in (lc.get('propertyDocumentation') ? [])
|
||||
doc = _.clone doc
|
||||
allDocs['__' + doc.name] ?= []
|
||||
allDocs['__' + doc.name].push doc
|
||||
if doc.type is 'snippet' then doc.owner = 'snippets'
|
||||
|
|
|
@ -201,7 +201,7 @@ module.exports = class TomeView extends View
|
|||
|
||||
updateSpellPalette: (thang, spell) ->
|
||||
return unless thang and @spellPaletteView?.thang isnt thang and thang.programmableProperties or thang.apiProperties
|
||||
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang, supermodel: @supermodel, programmable: spell?.canRead(), language: spell.language, session: @options.session
|
||||
@spellPaletteView = @insertSubView new SpellPaletteView thang: thang, supermodel: @supermodel, programmable: spell?.canRead(), language: spell?.language ? @options.session.get('codeLanguage'), session: @options.session
|
||||
@spellPaletteView.toggleControls {}, spell.view.controlsEnabled if spell # TODO: know when palette should have been disabled but didn't exist
|
||||
|
||||
spellFor: (thang, spellName) ->
|
||||
|
|
Loading…
Reference in a new issue