From: dsc Date: Wed, 7 Mar 2012 18:41:51 +0000 (-0800) Subject: Fixes issue pushing toggled checkboxes to model; revises event flow; fixes legend. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=228d31af95015d6b5739dce354d179358c47cda8;p=limn-bak.git Fixes issue pushing toggled checkboxes to model; revises event flow; fixes legend. --- diff --git a/lib/base.co b/lib/base.co index 33fb3bf..602ce71 100644 --- a/lib/base.co +++ b/lib/base.co @@ -16,9 +16,9 @@ BaseModel = exports.BaseModel = Backbone.Model.extend do # {{{ _.bindAll this, ...@__bind__ if @__bind__.length serialize: (v) -> - if v!? - v = '' - else if _.isBoolean v + # if v!? + # v = '' + if _.isBoolean v v = Number v else if _.isObject v v = JSON.stringify v @@ -26,11 +26,11 @@ BaseModel = exports.BaseModel = Backbone.Model.extend do # {{{ /** * Like `.toJSON()` in that it should return a plain object with no functions, - * but for the purpose of `.toKVPairs()`, allowing you to customize the values + * but for the purpose of `.toKV()`, allowing you to customize the values * included and keys used. * @returns {Object} */ - toKVObject: -> + toKVPairs: -> kvo = _.collapseObject @toJSON() for k, v in kvo kvo[k] = @serialize v @@ -41,8 +41,14 @@ BaseModel = exports.BaseModel = Backbone.Model.extend do # {{{ * a query string or a POST body. * @returns {String} */ - toKVPairs: (item_delim='&', kv_delim='=') -> - _.toKVPairs @toKVObject(), item_delim, kv_delim + toKV: (item_delim='&', kv_delim='=') -> + _.toKV @toKVPairs(), item_delim, kv_delim + + /** + * @returns {String} URL identifying this model. + */ + toURL: (item_delim='&', kv_delim='=') -> + "?#{@toKV()}" toString: -> "#{@ctorName}(id=#{@id})" @@ -57,8 +63,8 @@ BaseModel import do * @param {String|Object} o Serialized KV-pairs (or a plain object). * @returns {BaseModel} An instance of this model. */ - fromKVPairs: (o, item_delim='&', kv_delim='=') -> - o = _.fromKVPairs o, item_delim, kv_delim if typeof o is 'string' + fromKV: (o, item_delim='&', kv_delim='=') -> + o = _.fromKV o, item_delim, kv_delim if typeof o is 'string' Cls = if typeof this is 'function' then this else this.constructor new Cls _.uncollapseObject o @@ -71,11 +77,14 @@ BaseModel import do BaseList = exports.BaseList = Backbone.Collection.extend do # {{{ ctorName : 'BaseList' - toKVObject: -> + toKVPairs: -> _.collapseObject @toJSON() - toKVPairs: (item_delim='&', kv_delim='=') -> - _.toKVPairs @toKVObject(), item_delim, kv_delim + toKV: (item_delim='&', kv_delim='=') -> + _.toKV @toKVPairs(), item_delim, kv_delim + + toURL: (item_delim='&', kv_delim='=') -> + "?#{@toKV ...}" toString: -> "#{@ctorName}(length=#{@length})" # }}} diff --git a/lib/graph/graph-model.co b/lib/graph/graph-model.co index 372fb66..5df59fd 100644 --- a/lib/graph/graph-model.co +++ b/lib/graph/graph-model.co @@ -54,7 +54,7 @@ GraphOption = exports.GraphOption = Field.extend do # {{{ # Ignore functions/callbacks and, ahem, hidden tags. type = @get 'type', '' .toLowerCase() tags = @get 'tags', [] - if _.str.include(type, 'function') or _.intersection tags, IGNORED_TAGS .length + if _.str.include(type, 'function') or _.intersection(tags, IGNORED_TAGS).length @set 'ignore', true @@ -103,5 +103,12 @@ GraphOption = exports.GraphOption = Field.extend do # {{{ GraphOptionList = exports.GraphOptionList = FieldList.extend do # {{{ ctorName : 'GraphOptionList' model : GraphOption + + /** + * Override to omit defaults from URL. + */ + toKVPairs: -> + _.collapseObject @values {-keepDefaults, +serialize} + # }}} diff --git a/lib/graph/graph-view.co b/lib/graph/graph-view.co index 8e7cccc..0cb3982 100644 --- a/lib/graph/graph-view.co +++ b/lib/graph/graph-view.co @@ -99,8 +99,8 @@ GraphOptionsScaffold = exports.GraphOptionsScaffold = Scaffold.extend do # {{{ view.on 'change:collapse render', @render view - toKVPairs: -> - @collection.toKVPairs ... + toKV: -> + @collection.toKV ... # }}} diff --git a/lib/main.co b/lib/main.co index fc5a88c..70da9c1 100644 --- a/lib/main.co +++ b/lib/main.co @@ -12,26 +12,31 @@ Seq = require 'seq' } = require 'kraken/vis' root = this -CHART_OPTIONS_SPEC = [] -ROOT_VIS_DATA = {} -ROOT_VIS_OPTIONS = {} +CHART_OPTIONS_SPEC = [] +CHART_DEFAULT_OPTIONS = {} +ROOT_VIS_DATA = {} +ROOT_VIS_OPTIONS = {} # Create the Graph Scaffold main = -> + opts = root.CHART_DEFAULT_OPTIONS = {} + for opt of root.CHART_OPTIONS_SPEC + opts[opt.name] = opt.default + # TODO: create a preset manager # Remove chart options from data so we don't have to deepcopy ROOT_VIS_OPTIONS := delete root.ROOT_VIS_DATA.options # Bind to URL changes History.Adapter.bind window, 'statechange', -> - console.log 'StateChange!', String(root.location) + console.log 'StateChange!\n\n', String(root.location), '\n\n' # If we got querystring args, apply them to the graph data = {} if String(root.location).split '?' .1 - data = _.uncollapseObject _.fromKVPairs that.replace('#', '%23') + data = _.uncollapseObject _.fromKV that.replace('#', '%23') # # yarr, have to do options separately or everything goes to shit # options = delete data.options diff --git a/lib/scaffold/scaffold-model.co b/lib/scaffold/scaffold-model.co index 65814ff..9d242a6 100644 --- a/lib/scaffold/scaffold-model.co +++ b/lib/scaffold/scaffold-model.co @@ -96,7 +96,7 @@ Field = exports.Field = BaseModel.extend do # {{{ {id:@id} import do _.clone(@attributes) import { value:@getValue(), def:@get('default') } - toKVObject: -> + toKVPairs: -> { "#{@id}":@serializeValue() } toString: -> "(#{@id}: #{@serializeValue()})" @@ -112,19 +112,22 @@ FieldList = exports.FieldList = BaseList.extend do # {{{ * @returns {Object} */ values: (opts={}) -> - opts = {-keepDefaults, -serialize} import opts + opts = {+keepDefaults, -serialize} import opts _.synthesize do if opts.keepDefaults then @models else @models.filter -> not it.isDefault() -> [ it.get('name'), if opts.serialize then it.serializeValue() else it.getValue() ] toJSON: -> - @values() + @values {+keepDefaults, -serialize} - toKVObject: -> - _.collapseObject @values false, true + toKVPairs: -> + _.collapseObject @values {+keepDefaults, +serialize} - toKVPairs: (item_delim='&', kv_delim='=') -> - _.toKVPairs @toKVObject(), item_delim, kv_delim + toKV: (item_delim='&', kv_delim='=') -> + _.toKV @toKVPairs(), item_delim, kv_delim + + toURL: (item_delim='&', kv_delim='=') -> + "?#{@toKV ...}" toString: -> "#{@ctorName}(length=#{@length})" # }}} diff --git a/lib/scaffold/scaffold-view.co b/lib/scaffold/scaffold-view.co index 2f717d6..a766afb 100644 --- a/lib/scaffold/scaffold-view.co +++ b/lib/scaffold/scaffold-view.co @@ -10,17 +10,24 @@ FieldView = exports.FieldView = BaseView.extend do # {{{ tagName : 'div' className : 'field' + type : 'string' + events : 'blur .value' : 'update' 'submit .value' : 'update' - # initialize: -> - # # console.log "#this.initialize!" - # BaseView::initialize ... + initialize: -> + # console.log "#this.initialize!" + BaseView::initialize ... + @type = @model.get('type', 'string').toLowerCase() update: -> - val = @model.getParser() @$el.find('.value').val() + if @type is 'boolean' + val = !! @$el.find('.value').attr('checked') + else + val = @model.getParser() @$el.find('.value').val() + current = @model.getValue() return if _.isEqual val, current console.log "#this.update( #current -> #val )" @@ -111,7 +118,7 @@ Scaffold = exports.Scaffold = BaseView.extend do # {{{ # Proxy collection methods -<[ get at pluck invoke values toJSON toKVObject toKVPairs ]> +<[ get at pluck invoke values toJSON toKVPairs toKV toURL ]> .forEach (methodname) -> Scaffold::[methodname] = -> @collection[methodname].apply @collection, arguments diff --git a/lib/template/graph.jade b/lib/template/graph.jade index 264ca81..df5272d 100644 --- a/lib/template/graph.jade +++ b/lib/template/graph.jade @@ -27,10 +27,6 @@ section.graph(id=graph_id) input.span3.slug(type='text', id='slug', name='slug', placeholder='graph_slug', value=slug) p.help-block The slug uniquely identifies this graph and will be displayed in the URL. .half.control-group - label.dataset.control-label(for='dataset') Data Set - .controls - input.span3.dataset(type='text', id='dataset', name='dataset', placeholder='URL to dataset file', value=dataset) - p.help-block This dataset filename will soon be replaced by a friendly UI. .row-fluid .half.control-group label.width.control-label(for='width') Width @@ -42,6 +38,11 @@ section.graph(id=graph_id) .controls: input.span1.height(type='text', id='height', name='height', value=height) .graph-data-pane.tab-pane(id="graph-#{graph_id}-data") + .row-fluid + label.dataset.control-label(for='dataset') Data Set + .controls + input.span3.dataset(type='text', id='dataset', name='dataset', placeholder='URL to dataset file', value=dataset) + p.help-block This dataset filename will soon be replaced by a friendly UI. .graph-options-pane.tab-pane(id="graph-#{graph_id}-options") diff --git a/lib/underscore/object.co b/lib/underscore/object.co index b47d650..1416a49 100644 --- a/lib/underscore/object.co +++ b/lib/underscore/object.co @@ -37,7 +37,7 @@ _obj = do - toKVPairs: (o, item_delim='&', kv_delim='=') -> + toKV: (o, item_delim='&', kv_delim='=') -> _.reduce do o (acc, v, k) -> @@ -46,7 +46,7 @@ _obj = do [] .join item_delim - fromKVPairs: (qs, item_delim='&', kv_delim='=') -> + fromKV: (qs, item_delim='&', kv_delim='=') -> _.reduce do qs.split item_delim (acc, pair) -> diff --git a/lib/util/index.co b/lib/util/index.co index 9c24959..745238e 100644 --- a/lib/util/index.co +++ b/lib/util/index.co @@ -15,5 +15,17 @@ backbone = require 'kraken/util/backbone' # {crc32} = require 'kraken/util/crc' +## Debug +_.dump = (o, label='dump') -> + if not _.isArray(o) and _.isObject(o) + console.group label + for k, v in o + console.log "#k:", v + console.groupEnd() + else + console.log label, o + o + + exports import { root, _, op, backbone } # exports import { root, _, op, HashSet, BitString, crc32, } diff --git a/lib/util/op.co b/lib/util/op.co index ad42271..0c7c0b3 100644 --- a/lib/util/op.co +++ b/lib/util/op.co @@ -119,5 +119,4 @@ module.exports = op = encode : -> it and $ "
#it
" .html().replace /"/g, '"' decode : -> it and $ "
#it
" .text() - diff --git a/lib/vis/vis-model.co b/lib/vis/vis-model.co index 178a155..c534e1d 100644 --- a/lib/vis/vis-model.co +++ b/lib/vis/vis-model.co @@ -10,11 +10,13 @@ root = do -> this * other settings for both its content and presentation. */ VisModel = exports.VisModel = BaseModel.extend do # {{{ + IGNORE_OPTIONS : <[ width height timingName ]> ctorName : 'VisModel' urlRoot : '/graph' idAttribute : 'slug' + initialize : -> BaseModel::initialize ... name = @get 'name' @@ -23,7 +25,7 @@ VisModel = exports.VisModel = BaseModel.extend do # {{{ defaults: -> - { + ({ slug : '' name : '' desc : '' @@ -31,8 +33,7 @@ VisModel = exports.VisModel = BaseModel.extend do # {{{ # presets : [] width : 'auto' height : 320 - options : {} import root.ROOT_VIS_OPTIONS - } import root.ROOT_VIS_DATA + } import root.ROOT_VIS_DATA) import { options:_.clone root.ROOT_VIS_OPTIONS } parse: (data) -> @@ -59,19 +60,53 @@ VisModel = exports.VisModel = BaseModel.extend do # {{{ setOption: (key, value, opts={}) -> options = @get 'options', {} - options[key] = value - @set 'options', options, opts - @trigger "change:options:#key", this, value, key, opts unless opts.silent + unless _.contains @IGNORE_OPTIONS, key + options[key] = value + @set 'options', options, opts + @trigger "change:options:#key", this, value, key, opts unless opts.silent + this unsetOption: (key, opts={}) -> options = @get 'options', {} delete options[key] @set 'options', options, opts @trigger "change:options:#key", this, value, key, opts unless opts.silent - - - - toString: -> "#{@ctorName}(id=#{@id}, name=#{@get 'name'}, dataset=#{@get 'dataset'})" + this + + + ### URL Serialization + + toJSON: (options={}) -> + options = {+keepDefaults} import options + + json = _.clone(@attributes) import { options:_.clone(@attributes.options) } + return json if options.keepDefaults + + defs = root.CHART_DEFAULT_OPTIONS + opts = json.options + for k, v in opts + delete opts[k] if v is defs[k] + json + + + toKVPairs: -> + kvo = @toJSON() + # console.group 'toKVPairs' + # console.log '[IN]', JSON.stringify kvo + opts = kvo.options = _.clone kvo.options + for k, rootVal in root.ROOT_VIS_OPTIONS + v = opts[k] + # console.log " [#k] rootVal:", rootVal, "===", v, "?", _.isEqual(rootVal, v) unless _.isEqual(rootVal, v) + if _.isEqual rootVal, v + delete opts[k] + else + opts[k] = @serialize v + # console.log '[OUT]', JSON.stringify kvo + # console.groupEnd() + _.collapseObject kvo + + + toString: -> "#{@ctorName}(id=#{@id})" # }}} diff --git a/lib/vis/vis-view.co b/lib/vis/vis-view.co index 6ff0119..6b13eba 100644 --- a/lib/vis/vis-view.co +++ b/lib/vis/vis-view.co @@ -19,6 +19,7 @@ _ = require 'kraken/underscore' * - Graph metadata, such as name, description, slug */ VisView = exports.VisView = BaseView.extend do # {{{ + FILTER_CHART_OPTIONS : <[ file labels visibility colors dateWindow ticker timingName axisLabelFormatter valueFormatter xAxisLabelFormatter yAxisLabelFormatter xValueFormatter yValueFormatter xValueParser ]> __bind__ : <[ resizeViewport render renderAll onReady formatter axisFormatter ]> ctorName : 'VisView' tagName : 'section' @@ -41,11 +42,11 @@ VisView = exports.VisView = BaseView.extend do # {{{ BaseView::initialize ... # console.log "#this.initialize!" - for name of <[ resizeViewport render renderAll ]> + for name of <[ render renderAll ]> @[name] = _.debounce @[name], DEBOUNCE_RENDER # Resize graph on window resize - $ root .on 'resize', @resizeViewport + $ root .on 'resize', _.debounce(@resizeViewport, DEBOUNCE_RENDER) @id = _.domize 'graph', (@model.id or @model.cid) @@ -53,11 +54,11 @@ VisView = exports.VisView = BaseView.extend do # {{{ @model.on 'change', @render, this @model.on 'change:dataset', ~> changes = @model.changedAttributes() - console.log 'VisModel.changed(dataset) ->', JSON.stringify changes + console.log 'VisModel.changed( dataset ) ->', JSON.stringify changes @chart.updateOptions file:that if changes?.dataset @model.on 'change:options', ~> changes = @model.changedAttributes() - console.log 'VisModel.changed(options) ->', JSON.stringify changes + console.log 'VisModel.changed( options ) ->', JSON.stringify changes @chartOptions that, {+silent} if changes?.options @viewport = @$el.find '.viewport' @@ -67,8 +68,8 @@ VisView = exports.VisView = BaseView.extend do # {{{ @scaffold.collection.reset that if o.graph_spec @scaffold.on 'change', (scaffold, value, key, field) ~> - # console.log "scaffold.change!", value, key, field - @model.setOption key, value, {+silent} unless field.isDefault() + console.log "scaffold.change!", key, value, field + @model.setOption key, value, {+silent} #unless field.isDefault() options = @model.get 'options', {} @chartOptions options, {+silent} @@ -101,7 +102,12 @@ VisView = exports.VisView = BaseView.extend do # {{{ options.get(k)?.setValue v, opts this else - options.values() # TODO: pull this from model (must clone), sort out events + opts = @model.toJSON({ -keepDefaults })?.options or {} + for k of @FILTER_CHART_OPTIONS + # console.log "filter #k?", not opts[k] + if k in opts and not opts[k] + delete opts[k] + opts /** @@ -109,18 +115,23 @@ VisView = exports.VisView = BaseView.extend do # {{{ * @return { width, height } */ resizeViewport: -> - return this unless @ready + modelW = width = @model.get 'width' + modelH = height = @model.get 'height' + return { width, height } unless @ready # Remove old style, as it confuses dygraph after options update @viewport.attr 'style', '' label = @$el.find '.graph-label' - if (width = @model.get 'width') is 'auto' + if width is 'auto' vpWidth = @viewport.innerWidth() labelW = label.outerWidth() width = vpWidth - labelW - 10 - (vpWidth - label.position().left - labelW) - if (height = @model.get 'height') is 'auto' + width ?= modelW + if height is 'auto' height = @viewport.innerHeight() + height ?= modelH + size = { width, height } @viewport.css size # console.log 'resizeViewport!', JSON.stringify(size), @viewport @@ -145,29 +156,37 @@ VisView = exports.VisView = BaseView.extend do # {{{ render: -> return this unless @ready - console.log "#this.render!" size = @resizeViewport() - options = @chartOptions() import size + options = @chartOptions() #import size options import do labelsDiv : @$el.find '.graph-label' .0 # axisLabelFormatter : @axisFormatter # valueFormatter : @formatter - - # @chart?.destroy() - unless @chart - @chart = new Dygraph do - @viewport.0 - @model.get 'dataset' - options - else - @chart.updateOptions options - @chart.resize size + dataset = @model.get 'dataset' + + console.log "#this.render!", dataset + _.dump options, 'options' + + @chart?.destroy() + @chart = new Dygraph do + @viewport.0 + dataset + options + + # unless @chart + # @chart = new Dygraph do + # @viewport.0 + # dataset + # options + # else + # @chart.updateOptions options + # @chart.resize size # path = String(root.location?.path or '/') data = @toJSON() title = @model.get('name', root.document?.title or '') - url = "?"+@toKVPairs() + url = @toURL() # console.log 'History.pushState', JSON.stringify(data), title, url History.pushState data, title, url @@ -200,8 +219,11 @@ VisView = exports.VisView = BaseView.extend do # {{{ toJSON: -> @model.toJSON() - toKVPairs: -> - @model.toKVPairs.apply @model, arguments + toKV: -> + @model.toKV.apply @model, arguments + + toURL: -> + @model.toURL() toString: -> "#{@ctorName}(#{@model})" # }}}