* The view for a single configurable option.
*/
GraphOptionView = exports.GraphOptionView = FieldView.extend do # {{{
+ # __bind__ : <[ onClick ]>
ctorName : 'GraphOptionView'
tagName : 'div'
className : 'field option'
events :
'blur .value' : 'update'
'submit .value' : 'update'
+ 'click .close' : 'toggleCollapsed'
+ 'click' : 'onClick'
- initialize: ->
- # console.log "#this.initialize!"
- FieldView::initialize ...
- @$el.on 'click', (evt) ~>
- target = $ evt.target
- @toggleCollapsed() if @el is evt.target or not target.is '.value, label, input'
-
+ # initialize: ->
+ # console.log "#this.initialize!"
+ # FieldView::initialize ...
+ #
update: ->
val = @$el.find('.value').val()
current = @model.get 'value'
return if val is current
-
console.log "#this.update( #current -> #val )"
@model.setValue val, {+silent}
render: ->
- FieldView::render.call this
+ @__super__.render ...
@$el.addClass 'collapsed' if @isCollapsed
- # outer = $ @template @model.toJSON()
- # @$el.html outer.html()
- # .attr do
- # id : outer.attr 'id'
- # class : outer.attr('class') + if @isCollapsed then ' collapsed' else ''
this
+ onClick: (evt) ->
+ target = $ evt.target
+ console.log "#this.onClick()", target
+ @toggleCollapsed() if @$el.hasClass('collapsed') and not target.hasClass('close')
+
toggleCollapsed: ->
+ starting = @$el.hasClass 'collapsed' #@isCollapsed
@$el.toggleClass 'collapsed'
@isCollapsed = @$el.hasClass 'collapsed'
+ console.log "#this.toggleCollapsed!", starting, '->', @isCollapsed
+ @trigger 'change:collapse', this
this
# }}}
collectionType : GraphOptionList
subviewType : GraphOptionView
- # initialize : ->
- # Scaffold::initialize ...
+
+ initialize : ->
+ Scaffold::initialize ...
+ @render = _.debounce @render.bind(this), 50
render: ->
+ # console.log "#this.render() -> .isotope()"
@__super__.render ...
@$el.isotope do
itemSelector : '.field.option'
layoutMode : 'masonry'
- masonry : columnWidth : 100
+ masonry : columnWidth : 10
+ # itemPositionDataEnabled : true
# animationEngine : 'jquery'
- itemPositionDataEnabled : true
-
+
+ addOne: ->
+ # console.log "#this.addOne!"
+ view = @__super__.addOne ...
+ view.on 'change:collapse render', @render
+ view
# }}}
initialize : (o={}) ->
@model or= new GraphModel
BaseView::initialize ...
+ # console.log "#this.initialize!"
@model.on 'change', @render, this
@model.on 'destroy', @remove, this
options.values()
render: ->
- # BaseView::render ...
-
options = @chartOptions()
w = options.width or= @scaffold.get 'width' .getValue() or 480
h = options.height or= @scaffold.get 'height' .getValue() or 320
--- /dev/null
+models = require 'kraken/scaffold/model'
+views = require 'kraken/scaffold/view'
+exports import models import views
--- /dev/null
+_ = require 'kraken/underscore'
+op = require 'kraken/util/op'
+
+
+
+### Scaffold Models
+
+Field = exports.Field = Backbone.Model.extend do # {{{
+ ctorName : 'Field'
+ idAttribute : 'name'
+
+ initialize: ->
+ @set 'value', @get('default'), {+silent} if not @has 'value'
+ # console.log "#this.initialize!"
+
+ defaults: ->
+ {
+ name : ''
+ type : 'String'
+ default : null
+ desc : ''
+ category : 'General'
+ include : 'diff'
+ tags : []
+ examples : []
+ }
+
+ getParser: (type) ->
+ type or= @get 'type'
+ t = _ type.toLowerCase()
+
+ parser = op.toStr
+ if t.startsWith 'integer'
+ parser = op.toInt
+ if t.startsWith 'float'
+ parser = op.toFloat
+ if t.startsWith 'boolean'
+ parser = op.toBool
+ if t.startsWith 'object' or t.startsWith 'array'
+ parser = op.toObject
+ if t.startsWith 'function'
+ parser = (fn) -> eval "(#fn)"
+
+ # TODO: handle 'or' by returning an array of parsers
+ parser
+
+
+ getValue: (def) ->
+ @getParser() @get 'value', def
+
+ setValue: (v, options) ->
+ def = @get 'default'
+ if not v and def == null
+ val = null
+ else
+ val = @getParser()(v)
+ @set 'value', val, options
+
+ clearValue: ->
+ @set 'value', @get('default')
+
+ isDefault: ->
+ @get('value') is @get('default')
+
+ toJSON: ->
+ {id:@id} import do
+ _.clone(@attributes) import { value:@getValue(), def:@get('default') }
+
+ toString: -> "(#{@id}: #{@get 'value'})"
+# }}}
+
+
+FieldList = exports.FieldList = Backbone.Collection.extend do # {{{
+ ctorName : 'FieldList'
+ model : Field
+
+ /**
+ * Collects a map of fields to their values, excluding those set to `null` or their default.
+ * @returns {Object}
+ */
+ values: ->
+ _.synthesize do
+ @models.filter -> not it.isDefault()
+ -> [ it.get('name'), it.getValue() ]
+
+ toString: -> "#{@ctorName}(length=#{@length})"
+# }}}
+
_ = require 'kraken/underscore'
op = require 'kraken/util/op'
-
-
-
-### Scaffold Models
-
-Field = exports.Field = Backbone.Model.extend do # {{{
- ctorName : 'Field'
- idAttribute : 'name'
-
- initialize: ->
- @set 'value', @get('default'), {+silent} if not @has 'value'
- # console.log "#this.initialize!"
-
- defaults: ->
- {
- name : ''
- type : 'String'
- default : null
- desc : ''
- category : 'General'
- include : 'diff'
- tags : []
- examples : []
- }
-
- getParser: (type) ->
- type or= @get 'type'
- t = _ type.toLowerCase()
-
- parser = op.toStr
- if t.startsWith 'integer'
- parser = op.toInt
- if t.startsWith 'float'
- parser = op.toFloat
- if t.startsWith 'boolean'
- parser = op.toBool
- if t.startsWith 'object' or t.startsWith 'array'
- parser = op.toObject
- if t.startsWith 'function'
- parser = (fn) -> eval "(#fn)"
-
- # TODO: handle 'or' by returning an array of parsers
- parser
-
-
- getValue: (def) ->
- @getParser() @get 'value', def
-
- setValue: (v, options) ->
- def = @get 'default'
- if not v and def == null
- val = null
- else
- val = @getParser()(v)
- @set 'value', val, options
-
- clearValue: ->
- @set 'value', @get('default')
-
- isDefault: ->
- @get('value') is @get('default')
-
- toJSON: ->
- {id:@id} import do
- _.clone(@attributes) import { value:@getValue(), def:@get('default') }
-
- toString: -> "(#{@id}: #{@get 'value'})"
-# }}}
-
-
-FieldList = exports.FieldList = Backbone.Collection.extend do # {{{
- ctorName : 'FieldList'
- model : Field
-
- /**
- * Collects a map of fields to their values, excluding those set to `null` or their default.
- * @returns {Object}
- */
- values: ->
- _.synthesize do
- @models.filter -> not it.isDefault()
- -> [ it.get('name'), it.getValue() ]
-
- toString: -> "#{@ctorName}(length=#{@length})"
-# }}}
-
-
+{ Field, FieldList,
+} = require 'kraken/scaffold/model'
### Views
initialize: ->
- _.bindAll this, ...@__bind__
+ _.bindAll this, ...@__bind__ if @__bind__.length
@__super__ = @constructor.__super__
- Backbone.View::initialize ...
@model.view = this
@$el.data { @model, view:this }
render: ->
@build()
+ @trigger 'render', this
+ this
hide : -> @$el.hide(); this
show : -> @$el.show(); this
val = @$el.find('.value').val()
current = @model.get 'value'
return if val is current
- console.log "#this.onUIChange( #current -> #val )"
+ # console.log "#this.onUIChange( #current -> #val )"
@model.setValue val, {+silent}
render: ->
- return @remove() if @model.get 'hidden'
+ return @remove() if @model.get 'hidden', false
return BaseView::render ... if @template
name = @model.get 'name'
addOne: (field) ->
+ # console.log "[S] #this.addOne!", @__super__
_.remove @subviews, field.view if field.view
SubviewType = @subviewType
view = new SubviewType model:field
@subviews.push view
- @$el.append view.render().el
+ @$el.append view.render().el unless field.get 'hidden'
+
+ @render()
view
addAll: ->
--- /dev/null
+- window.Markdown || (window.Markdown = new (require('showdown').Showdown).converter());
+- (jade.filters || (jade.filters = {})).markdown = function (s, name){ return s && Markdown.makeHtml(s.replace(/\n/g, '\n\n')); };
+
-- var _ = require('kraken/underscore');
+include browser-helpers
+- var option_id = _.domize('option', id);
- var value_id = _.domize('value', id);
- var category_cls = _.domize('category', category);
- var tags_cls = tags.map(_.domize('tag')).join(' ');
- var type_cls = _.domize('type', type);
-.field.option(id=_.domize('option', id), class="#{category_cls} #{tags_cls}")
+.field.option(id=option_id, class="#{category_cls} #{tags_cls}")
+ a.close ×
+
h3.shortname #{_.shortname(name)}
label.name(for=value_id) #{name}
- input.value(type="text", id=value_id, name=name, value=value)
+ input.value(type="text", id=value_id, name=name, class=type_cls, value=value)
.type(class=type_cls) #{type}
- .default(class=type_cls) #{def}
+ .default(class=type_cls, title="Default: #{def} (#{type})") #{def}
.desc
- #{desc}
- //- != jade.filters.markdown(desc)
+ != (jade.filters || {}).markdown(desc)
- .tags: ul
+ .tags(data-toggle="collapse", data-target="ul"): ul.collapse
for tag in tags
li.tag(class=_.domize('tag', tag)) #{tag}
- .examples: ul
+ .examples(data-toggle="collapse", data-target="ul"): ul.collapse
for example in examples
li.example
a(href="http://dygraphs.com/tests/#{example}.html", target="_blank") #{example}
form.details
label.name(for='#{id}_name') Name
- fieldset
+ fieldset.options
legend Graph Options
--- /dev/null
+_ = require 'underscore'
+
+
+slice = [].slice
+hasOwn = {}.hasOwnProperty
+objToString = {}.toString
+
+toArray = _.toArray
+
+
+
+decorate = (fn) ->
+ if not fn.__decorated__
+ for name of _pet.FUNCTION_METHODS
+ m = _[name]
+ fn[name] = m.__methodized__ or methodize m
+ fn.__decorated__ = true
+ return fn
+
+methodize = (fn) ->
+ m = fn.__methodized__
+ return m if m
+
+ g = fn.__genericized__
+ return g.__wraps__ if g and g.__wraps__
+
+ m = fn.__methodized__ = (args...) ->
+ args.unshift this
+ return fn.apply this, args
+
+ m.__wraps__ = fn
+ return decorate m
+
+
+
+_pet = module.exports = \
+ function pet (o, start=0, end=undefined) ->
+ if _.isArguments o
+ o = _.toArray o, start, end
+
+ return decorate o if typeof o is 'function'
+ return _ o
+
+# function methods to be attached on call to _(fn)
+_pet.FUNCTION_METHODS = [
+ 'bind', 'bindAll', 'memoize',
+ 'delay', 'defer', 'throttle', 'debounce', 'once', 'after',
+ 'wrap', 'compose',
+ 'unwrap', 'partial', 'curry', 'flip', 'methodize', 'aritize', 'limit'
+]
+
+
+class2name = "Boolean Number String Function Array Date RegExp Object"
+ .split(" ")
+ .reduce ((class2name, name) ->
+ class2name[ "[object "+name+"]" ] = name
+ return class2name), {}
+
+
+## Objects
+_.mixin
+
+ has: (o, v) ->
+ vals = if _.isArray(o) then o else _.values(o)
+ return vals.indexOf(v) is not -1
+
+ remove: (o, vs...) ->
+ if _.isArray(o)
+ _.each vs, (v) ->
+ idx = o.indexOf v
+ if idx is not -1
+ o.splice idx, 1
+ else
+ _.each o, (v, k) ->
+ if vs.indexOf(v) != -1
+ delete o[k]
+ return o
+
+ set: (o, key, value, def) ->
+ if o and key? and (value? or def?)
+ o[key] = value ? def
+ return o
+
+ attr: (o, key, value, def) ->
+ return o if not o or key is undefined
+
+ if _.isPlainObject key
+ return _.extend o, key
+
+ if (value ? def) is not undefined
+ return _.set o, key, value, def
+
+ return o[key]
+
+
+
+## Types
+_.mixin
+
+ basicTypeName: (o) ->
+ return if o is null then "null" else (class2name[objToString.call(o)] || "Object")
+
+ isWindow: (o) ->
+ return o and typeof o is "object" and "setInterval" of o
+
+ isPlainObject: (o) ->
+ # Must be an Object.
+ # Because of IE, we also have to check the presence of the constructor property.
+ # Make sure that DOM nodes and window objects don't pass through, as well
+ if not o or basicTypeName(o) is not "Object" or o.nodeType or _.isWindow(o)
+ return false
+
+ # Not own constructor property? must be Object
+ C = o.constructor
+ if C and not hasOwn.call(o, "constructor") and not hasOwn.call(C.prototype, "isPrototypeOf")
+ return false
+
+ # Own properties are enumerated firstly, so to speed up,
+ # if last one is own, then all properties are own.
+ for key in o
+ ; # semicolon **on new line** is required by coffeescript to denote empty statement.
+
+ return key is undefined or hasOwn.call(o, key)
+
+
+## Arrays
+_.mixin
+
+ toArray: (iterable, start=0, end=undefined) ->
+ _.slice toArray(iterable), start, end
+
+ flatten: (A) ->
+ _.reduce do
+ slice.call(arguments)
+ (flat, v) ->
+ flat.concat( if _.isArray v then _.reduce(v, arguments.callee, []) else v )
+ []
+
+
+
+## Functions
+_ofArity = _.memoize(
+ (n, limit) ->
+ args = ( '$'+i for i from 0 til n ).join(',')
+ name = ( if limit then 'limited' else 'artized' )
+ apply_with = ( if limit then "[].slice.call(arguments, 0, #{n})" else 'arguments' )
+ return eval "
+ (function #{name}(fn){
+ var _fn = function(#{args}){ return fn.apply(this, #{apply_with}); };
+ _fn.__wraps__ = fn;
+ return _(_fn);
+ })"
+ )
+
+_.mixin
+ methodize: methodize
+
+ unwrap: (fn) ->
+ (fn and _.isFunction(fn) and _.unwrap(fn.__wraps__)) or fn
+
+
+ partial: (fn, args...) ->
+ partially = ->
+ fn.apply this, args.concat(slice.call(arguments))
+ partially.__wraps__ = fn
+ return _ partially
+
+
+ genericize: (fn) ->
+ g = fn.__genericized__
+ return g if g
+
+ m = fn.__methodized__
+ return m.__wraps__ if m and m.__wraps__
+
+ g = fn.__genericized__ = (args...) ->
+ fn.apply args.shift(), args
+
+ g.__wraps__ = fn
+ return _ g
+
+
+ curry: (fn, args...) ->
+ if not _.isFunction fn
+ return fn
+
+ if fn.__curried__
+ return fn.apply this, args
+
+ L = fn.length or _.unwrap(fn).length
+ if args.length >= L
+ return fn.apply this, args
+
+ curried = ->
+ _args = args.concat slice.call(arguments)
+ if _args.length >= L
+ return fn.apply this, _args
+ _args.unshift fn
+ return _.curry.apply this, _args
+
+ curried.__wraps__ = fn
+ curried.__curried__ = args
+ return _ curried
+
+
+ flip: (fn) ->
+ f = fn.__flipped__
+ return f if f
+
+ f = fn.__flipped__ = \
+ flipped = ->
+ args = arguments
+ hd = args[0]
+ args[0] = args[1]
+ args[1] = hd
+ return fn.apply this, args
+
+ f.__wraps__ = fn
+ return _ f
+
+
+ aritize: (fn, n) ->
+ return fn if fn.length is n
+
+ cache = fn.__aritized__
+ if not cache
+ cache = fn.__aritized__ = {}
+ else if cache[n]
+ return cache[n]
+
+ return ( cache[n] = _ofArity(n, false)(fn) )
+
+
+ limit: (fn, n) ->
+ cache = fn.__limited__
+ if not cache
+ cache = fn.__limited__ = {}
+ else if cache[n]
+ return cache[n]
+
+ return ( cache[n] = _ofArity(n, true)(fn) )
+
+
+
+
+
+
+_.extend _pet, _
default: null
desc: A function which parses x-values (i.e. the dependent series). Must return a number, even when
the values are dates. In this case, millis since epoch are used. This is used primarily for parsing
- CSV data. *=Dygraphs is slightly more accepting in the dates which it will parse. See code for
+ CSV data.
+
+ * Dygraphs is slightly more accepting in the dates which it will parse. See code for
details.
category: CSV parsing
tags:
type: Integer
default: null
desc: 'Prefer axes { x: { pixelsPerLabel } }'
+ hidden: true
category: Deprecated
tags:
- deprecated
type: Integer
default: null
desc: 'Prefer axes: { y: { pixelsPerLabel } }'
+ hidden: true
category: Deprecated
tags:
- deprecated
type: function
default: null
desc: 'Prefer axes { x: { axisLabelFormatter } }'
+ hidden: true
category: Deprecated
tags:
- deprecated
type: function
default: null
desc: 'Prefer axes: { x: { valueFormatter } }'
+ hidden: true
category: Deprecated
tags:
- deprecated
type: function
default: null
desc: 'Prefer axes: { y: { axisLabelFormatter } }'
+ hidden: true
category: Deprecated
tags:
- deprecated
type: function
default: null
desc: 'Prefer axes: { y: { valueFormatter } }'
+ hidden: true
category: Deprecated
tags:
- deprecated
--- /dev/null
+//\r
+// showdown.js -- A javascript port of Markdown.\r
+//\r
+// Copyright (c) 2007 John Fraser.\r
+//\r
+// Original Markdown Copyright (c) 2004-2005 John Gruber\r
+// <http://daringfireball.net/projects/markdown/>\r
+//\r
+// Redistributable under a BSD-style open source license.\r
+// See license.txt for more information.\r
+//\r
+// The full source distribution is at:\r
+//\r
+// A A L\r
+// T C A\r
+// T K B\r
+//\r
+// <http://www.attacklab.net/>\r
+//\r
+\r
+//\r
+// Wherever possible, Showdown is a straight, line-by-line port\r
+// of the Perl version of Markdown.\r
+//\r
+// This is not a normal parser design; it's basically just a\r
+// series of string substitutions. It's hard to read and\r
+// maintain this way, but keeping Showdown close to the original\r
+// design makes it easier to port new features.\r
+//\r
+// More importantly, Showdown behaves like markdown.pl in most\r
+// edge cases. So web applications can do client-side preview\r
+// in Javascript, and then build identical HTML on the server.\r
+//\r
+// This port needs the new RegExp functionality of ECMA 262,\r
+// 3rd Edition (i.e. Javascript 1.5). Most modern web browsers\r
+// should do fine. Even with the new regular expression features,\r
+// We do a lot of work to emulate Perl's regex functionality.\r
+// The tricky changes in this file mostly have the "attacklab:"\r
+// label. Major or self-explanatory changes don't.\r
+//\r
+// Smart diff tools like Araxis Merge will be able to match up\r
+// this file with markdown.pl in a useful way. A little tweaking\r
+// helps: in a copy of markdown.pl, replace "#" with "//" and\r
+// replace "$text" with "text". Be sure to ignore whitespace\r
+// and line endings.\r
+//\r
+\r
+\r
+//\r
+// Showdown usage:\r
+//\r
+// var text = "Markdown *rocks*.";\r
+//\r
+// var converter = new Showdown.converter();\r
+// var html = converter.makeHtml(text);\r
+//\r
+// alert(html);\r
+//\r