From eb3e815efb9b4c0a36a7e00cf9f2423d18366adf Mon Sep 17 00:00:00 2001 From: dsc Date: Mon, 27 Feb 2012 11:31:37 -0800 Subject: [PATCH] Breaks baseview out of scaffold; adds KVPairs serialization to most models; updates model after checkbox click. --- lib/baseview.co | 68 +++++++++++++++++++++++++++++++++++++++++++++ lib/graph/model.co | 49 ++++++++++++++++++++++++++++---- lib/graph/view.co | 55 +++++++++++++----------------------- lib/main.co | 9 +++-- lib/scaffold/model.co | 30 +++++++++++++++++++- lib/scaffold/view.co | 74 ++---------------------------------------------- www/css/layout.styl | 6 ++- www/modules.yaml | 1 + 8 files changed, 174 insertions(+), 118 deletions(-) create mode 100644 lib/baseview.co diff --git a/lib/baseview.co b/lib/baseview.co new file mode 100644 index 0000000..40701ed --- /dev/null +++ b/lib/baseview.co @@ -0,0 +1,68 @@ +_ = require 'kraken/underscore' +op = require 'kraken/util/op' + + +BaseView = exports.BaseView = Backbone.View.extend do # {{{ + # List of methods to bind on initialize; set on subclass + __bind__ : [] + + + initialize: -> + _.bindAll this, ...@__bind__ if @__bind__.length + @__super__ = @constructor.__super__ + + @model.view = this + @$el.data { @model, view:this } + @model.on 'change', @render, this + @model.on 'destroy', @remove, this + + toTemplateLocals: -> + json = {value:v} = @model.toJSON() + if _.isArray(v) or _.isObject(v) + json.value = JSON.stringify v + { $, _, op, @model, view:this } import json + + $template: (locals={}) -> + $ @template @toTemplateLocals() import locals + + build: -> + return this unless @template + + outer = @$template() + @$el.html outer.html() + .attr do + id : outer.attr 'id' + class : outer.attr('class') + + + this + + render: -> + @build() + @trigger 'render', this + this + + hide : -> @$el.hide(); this + show : -> @$el.show(); this + remove : -> @$el.remove(); this + clear : -> @model.destroy(); @remove() + + + # remove : -> + # if (p = @$el.parent()).length + # @$parent or= p + # # @parent_index = p.children().indexOf @$el + # @$el.remove() + # this + # + # reparent : (parent=@$parent) -> + # parent = $ parent + # @$el.appendTo parent if parent?.length + # this + + toString : -> "#{@ctorName}(model=#{@model})" + + +# }}} + + diff --git a/lib/graph/model.co b/lib/graph/model.co index 125fc4d..405c47e 100644 --- a/lib/graph/model.co +++ b/lib/graph/model.co @@ -1,5 +1,6 @@ _ = require 'kraken/underscore' -{ Field, FieldList, BaseView, FieldView, Scaffold +{BaseView} = require 'kraken/baseview' +{ Field, FieldList, FieldView, Scaffold } = require 'kraken/scaffold' @@ -88,20 +89,56 @@ GraphOption = exports.GraphOption = Field.extend do # {{{ o[k] = '' if v!? o + toKVPairs: -> + key = @get 'name' + value = @get 'value' + if value? + "#{encodeURIComponent key}=#{encodeURIComponent value}" + else + '' + + # }}} GraphOptionList = exports.GraphOptionList = FieldList.extend do # {{{ ctorName : 'GraphOptionList' model : GraphOption - categories : {} + /** + * Transforms this list into form-encoded KV-pairs, excluding null values and + * @returns {String} + */ + toKVPairs: (keepDefaults=false) -> + @models + .filter -> it.get('name') and it.getValue()? and (keepDefaults or not it.isDefault()) + .map -> "#{encodeURIComponent it.get 'name'}=#{encodeURIComponent it.serializeValue()}" + .join '&' - initialize : -> - FieldList::initialize ... - @categories = {} - +# }}} + + +/** + * Represents a Graph, including its charting options, dataset, annotations, and all + * other settings for both its content and presentation. + */ +GraphModel = exports.GraphModel = Backbone.Model.extend do # {{{ + ctorName : 'GraphModel' + urlRoot : '/graphs' + initialize : -> + name = @get 'name' + if name and not (@id or @has 'id') + @id = @attributes.id = _.underscored name + + defaults : -> + { + name : 'Kraken Graph' + dataset : '/data/page_views_by_language.csv' + options : {} + } + + toString: -> "#{@ctorName}(id=#{@id}, name=#{@get 'name'}, dataset=#{@get 'dataset'})" # }}} diff --git a/lib/graph/view.co b/lib/graph/view.co index 31653f2..5dffbfe 100644 --- a/lib/graph/view.co +++ b/lib/graph/view.co @@ -1,9 +1,11 @@ _ = require 'kraken/underscore' -{ Field, FieldList, BaseView, FieldView, Scaffold +{BaseView} = require 'kraken/baseview' +{ Field, FieldList, FieldView, Scaffold } = require 'kraken/scaffold' -{ GraphOption, GraphOptionList, TagSet, +{ GraphModel, GraphOption, GraphOptionList, TagSet, } = require 'kraken/graph/model' +DEBOUNCE_RENDER = exports.DEBOUNCE_RENDER = 20ms /** @@ -19,11 +21,12 @@ GraphOptionView = exports.GraphOptionView = FieldView.extend do # {{{ isCollapsed : true events : - 'blur .value' : 'update' - 'submit .value' : 'update' - 'click .close' : 'toggleCollapsed' - 'click h3' : 'toggleCollapsed' - 'click .collapsed' : 'onClick' + 'blur .value' : 'update' + 'click input[type="checkbox"].value' : 'update' + 'submit .value' : 'update' + 'click .close' : 'toggleCollapsed' + 'click h3' : 'toggleCollapsed' + 'click .collapsed' : 'onClick' update: -> @@ -65,7 +68,7 @@ GraphOptionsScaffold = exports.GraphOptionsScaffold = Scaffold.extend do # {{{ initialize : -> Scaffold::initialize ... - @render = _.debounce @render.bind(this), 50 + @render = _.debounce @render.bind(this), DEBOUNCE_RENDER render: -> # console.log "#this.render() -> .isotope()" @@ -83,35 +86,14 @@ GraphOptionsScaffold = exports.GraphOptionsScaffold = Scaffold.extend do # {{{ view.on 'change:collapse render', @render view + toKVPairs: -> + @collection.toKVPairs() + # }}} -/** - * Represents a Graph, including its charting options, dataset, annotations, and all - * other settings for both its content and presentation. - */ -GraphModel = exports.GraphModel = Backbone.Model.extend do # {{{ - ctorName : 'GraphModel' - urlRoot : '/graphs' - - initialize : -> - name = @get 'name' - if name and not (@id or @has 'id') - @id = @attributes.id = _.underscored name - - defaults : -> - { - name : 'Kraken Graph' - dataset : '/data/page_views_by_language.csv' - options : {} - } - - toString: -> "#{@ctorName}(id=#{@id}, name=#{@get 'name'}, dataset=#{@get 'dataset'})" -# }}} - - GraphView = exports.GraphView = BaseView.extend do # {{{ ctorName : 'GraphView' tagName : 'section' @@ -124,6 +106,7 @@ GraphView = exports.GraphView = BaseView.extend do # {{{ initialize : (o={}) -> + @render = _.debounce @render.bind(this), DEBOUNCE_RENDER @model or= new GraphModel BaseView::initialize ... # console.log "#this.initialize!" @@ -138,9 +121,7 @@ GraphView = exports.GraphView = BaseView.extend do # {{{ @$el.find 'fieldset' .append @scaffold.el @scaffold.collection.reset that if o.graph_spec - setTimeout do - ~> @render() - 50 + _.delay @render, DEBOUNCE_RENDER chartOptions: (values) -> @@ -195,6 +176,10 @@ GraphView = exports.GraphView = BaseView.extend do # {{{ @render() false + + toKVPairs: (keepDefaults=false) -> + @scaffold.toKVPairs() + toString: -> "#{@ctorName}(#{@model})" # }}} diff --git a/lib/main.co b/lib/main.co index 7d6f33b..30dda30 100644 --- a/lib/main.co +++ b/lib/main.co @@ -1,10 +1,11 @@ -{_, op} = require 'kraken/util' -{ Field, FieldList, BaseView, FieldView, Scaffold -} = require 'kraken/scaffold' +{_, op} = require 'kraken/util' +{BaseView} = require 'kraken/baseview' +{ Field, FieldList, FieldView, Scaffold +} = require 'kraken/scaffold' { GraphView, GraphModel, TagSet, GraphOption, GraphOptionList, GraphOptionView, GraphOptionsScaffold, -} = require 'kraken/graph' +} = require 'kraken/graph' root = do -> this diff --git a/lib/scaffold/model.co b/lib/scaffold/model.co index 412acfd..825995e 100644 --- a/lib/scaffold/model.co +++ b/lib/scaffold/model.co @@ -1,6 +1,5 @@ _ = require 'kraken/underscore' op = require 'kraken/util/op' -Hash = require 'hashish' @@ -29,6 +28,7 @@ Field = exports.Field = Backbone.Model.extend do # {{{ } + /* * * Parsers * * */ getParser: (type) -> # XXX: handle 'or' by returning an array of parsers? @@ -66,6 +66,17 @@ Field = exports.Field = Backbone.Model.extend do # {{{ null + /* * * Serializers * * */ + serializeValue: -> + v = @getValue() + if v!? + v = '' + else if _.isArray(v) or _.isObject(v) + v = JSON.stringify v + String v + + + /* * * Value Accessors * * */ getValue: (def) -> @getParser() @get 'value', def @@ -88,6 +99,14 @@ Field = exports.Field = Backbone.Model.extend do # {{{ {id:@id} import do _.clone(@attributes) import { value:@getValue(), def:@get('default') } + toKVPairs: -> + key = @get 'name' + value = @get 'value' + if value? + "#{encodeURIComponent key}=#{encodeURIComponent value}" + else + '' + toString: -> "(#{@id}: #{@get 'value'})" # }}} @@ -105,6 +124,15 @@ FieldList = exports.FieldList = Backbone.Collection.extend do # {{{ @models.filter -> not it.isDefault() -> [ it.get('name'), it.getValue() ] + toJSON: -> + @values() + + toKVPairs: -> + @models + .filter -> it.get('name') and it.getValue()? + .map -> "#{encodeURIComponent it.id}=#{encodeURIComponent it.get 'value'}" + .join '&' + toString: -> "#{@ctorName}(length=#{@length})" # }}} diff --git a/lib/scaffold/view.co b/lib/scaffold/view.co index b48e1f5..0e7a605 100644 --- a/lib/scaffold/view.co +++ b/lib/scaffold/view.co @@ -1,74 +1,8 @@ -_ = require 'kraken/underscore' -op = require 'kraken/util/op' +_ = require 'kraken/underscore' +op = require 'kraken/util/op' +{BaseView} = require 'kraken/baseview' { Field, FieldList, -} = require 'kraken/scaffold/model' - - -### Views - -BaseView = exports.BaseView = Backbone.View.extend do # {{{ - # List of methods to bind on initialize; set on subclass - __bind__ : [] - - - initialize: -> - _.bindAll this, ...@__bind__ if @__bind__.length - @__super__ = @constructor.__super__ - - @model.view = this - @$el.data { @model, view:this } - @model.on 'change', @render, this - @model.on 'destroy', @remove, this - - toTemplateLocals: -> - json = {value:v} = @model.toJSON() - if _.isArray(v) or _.isObject(v) - json.value = JSON.stringify v - { $, _, op, @model, view:this } import json - - $template: (locals={}) -> - $ @template @toTemplateLocals() import locals - - build: -> - return this unless @template - - outer = @$template() - @$el.html outer.html() - .attr do - id : outer.attr 'id' - class : outer.attr('class') - - - this - - render: -> - @build() - @trigger 'render', this - this - - hide : -> @$el.hide(); this - show : -> @$el.show(); this - remove : -> @$el.remove(); this - clear : -> @model.destroy(); @remove() - - - # remove : -> - # if (p = @$el.parent()).length - # @$parent or= p - # # @parent_index = p.children().indexOf @$el - # @$el.remove() - # this - # - # reparent : (parent=@$parent) -> - # parent = $ parent - # @$el.appendTo parent if parent?.length - # this - - toString : -> "#{@ctorName}(model=#{@model})" - - -# }}} - +} = require 'kraken/scaffold/model' FieldView = exports.FieldView = BaseView.extend do # {{{ diff --git a/www/css/layout.styl b/www/css/layout.styl index 39cffae..69f28cd 100644 --- a/www/css/layout.styl +++ b/www/css/layout.styl @@ -9,14 +9,16 @@ header, footer, #content #content z-index 10 + padding 1em min-height 100% background-color $page_bgcolor box-shadow 0px 0px 6px 2px rgba(0,0,0,0.4) & > .inner position relative - width 80% - margin 0 auto + // width 80% + // min-width 960px + // margin 0 auto // .spacer offsets #content to pad for header .spacer diff --git a/www/modules.yaml b/www/modules.yaml index 1e0b1b7..4a075f7 100644 --- a/www/modules.yaml +++ b/www/modules.yaml @@ -35,6 +35,7 @@ all: - op - backbone - index + - baseview - template: - graph.jade - graph-option.jade -- 1.7.0.4