Moves timeseries classes.
authordsc <dsc@wikimedia.org>
Tue, 24 Apr 2012 19:56:28 +0000 (12:56 -0700)
committerdsc <dsc@wikimedia.org>
Tue, 24 Apr 2012 19:56:28 +0000 (12:56 -0700)
27 files changed:
lib/base/base-view.co
lib/base/index.co
lib/chart/chart-option-model.co
lib/chart/chart-option-view.co
lib/dashboard/dashboard-view.co
lib/dataset/data-view.co
lib/dataset/dataset-view.co
lib/dataset/datasource-model.co
lib/dataset/datasource-ui-view.co
lib/dataset/metric-edit-view.co
lib/dataset/metric-model.co
lib/graph/graph-display-view.co
lib/graph/graph-edit-view.co
lib/main-edit.co
lib/scaffold/scaffold-view.co
lib/template/chart-scaffold.jade
lib/template/data.jade
lib/template/dataset.jade
lib/template/datasource-ui.jade
lib/template/datasource.jade
lib/template/graph-edit.jade
lib/template/metric-edit.jade
lib/timeseries/csv.co [moved from lib/util/timeseries/csv.co with 95% similarity]
lib/timeseries/index.co [moved from lib/util/timeseries/index.co with 100% similarity]
lib/timeseries/timeseries.co [moved from lib/util/timeseries/timeseries.co with 99% similarity]
lib/util/index.co
lib/util/op.co

index 7d22832..dce79ce 100644 (file)
@@ -4,6 +4,8 @@ Backbone = require 'backbone'
 } = require 'kraken/util'
 { BaseBackboneMixin, mixinBase,
 } = require 'kraken/base/base-mixin'
+{ DataBinding,
+} = require 'kraken/base/data-binding'
 
 
 
@@ -13,15 +15,20 @@ Backbone = require 'backbone'
  */
 BaseView = exports.BaseView = Backbone.View.extend mixinBase do # {{{
     tagName : 'section'
+    model : BaseModel
     
     /**
-     * The identifier for this view class.
-     * By default, the class name is converted to underscore-case, and a
-     * trailing '_view' suffix is dropped.
-     * Example: "CamelCaseView" becomes "camel_case"
+     * Method-name called by `onReturnKeypress` when used as an event-handler.
      * @type String
      */
-    __view_type_id__: null
+    callOnReturnKeypress: null
+    
+    
+    /**
+     * Parent view of this view.
+     * @type BaseView
+     */
+    parent : null
     
     /**
      * Array of [view, selector]-pairs.
@@ -33,7 +40,7 @@ BaseView = exports.BaseView = Backbone.View.extend mixinBase do # {{{
      * Whether this view has been added to the DOM.
      * @type Boolean
      */
-    _parented: false
+    isAttached: false
     
     
     
@@ -42,7 +49,8 @@ BaseView = exports.BaseView = Backbone.View.extend mixinBase do # {{{
         @__superclass__ = @..__super__.constructor
         @__view_type_id__ or= _.str.underscored @getClassName() .replace /_view$/, ''
         @waitingOn      = 0
-        @subviews       = []
+        @subviews       = new ViewList
+        @onReturnKeypress = _.debounce @onReturnKeypress.bind(this), 50
         Backbone.View ...
         @trigger 'create', this
     
@@ -65,63 +73,130 @@ BaseView = exports.BaseView = Backbone.View.extend mixinBase do # {{{
             @$el.data { @model, view:this }
             @model.on 'change',  @render, this
             @model.on 'destroy', @remove, this
-        @model
+            @trigger 'change:model', this, model
+        model
     
     
     
     ### Subviews
     
-    addSubview: (selector, view) ->
-        [view, selector] = [selector, null] unless view
-        @subviews.push [view, selector]
+    setParent: (parent) ->
+        [old_parent, @parent] = [@parent, parent]
+        @trigger 'parent', this, parent, old_parent
+        this
+    
+    unsetParent: ->
+        [old_parent, @parent] = [@parent, null]
+        @trigger 'unparent', this, old_parent
+        this
+    
+    
+    addSubview: (view) ->
+        @removeSubview view
+        @subviews.push view
+        view.setParent this
         view
     
     removeSubview: (view) ->
-        for [v, sel], idx of @subviews
-            if v is view
-                @subviews.splice(idx, 1)
-                return [v, sel]
-        null
+        if @hasSubview view
+            view.remove()
+            @subviews.remove view
+            view.unsetParent()
+        view
     
     hasSubview: (view) ->
-        _.any @subviews, ([v]) -> v is view
+        @subviews.contains view
     
     invokeSubviews: ->
-        _ _.pluck(@subviews, 0) .invoke ...arguments
+        @subviews.invoke ...arguments
     
-    attachSubviews: ->
-        for [view, selector] of @subviews
-            return unless view
-            view.undelegateEvents()
-            return unless el = view.render()?.el
-            if selector
-                @$el.find selector .append el
-            else
-                @$el.append el
-            view.delegateEvents()
+    removeAllSubviews: ->
+        @subviews.forEach @removeSubview, this
+        @subviews = new ViewList
         this
     
-    removeAllSubviews: ->
-        @invokeSubviews 'remove'
-        _.pluck @subviews, 0 .forEach @removeSubview, this
+    
+    
+    ### UI Utilities
+    
+    attach: (el) ->
+        # @undelegateEvents()
+        @$el.appendTo el
+        # only trigger the event the first time
+        return this if @isAttached
+        @isAttached = true
+        _.delay do
+            ~> # have to let DOM settle to ensure elements can be found
+                @delegateEvents()
+                @trigger 'attach', this
+            50
         this
     
-    bubbleEvent: (evt) ->
-        @invokeSubviews 'trigger', ...arguments
+    remove : ->
+        # @undelegateEvents()
+        @$el.remove()
+        return this unless @isAttached
+        @isAttached = false
+        @trigger 'unattach', this
+        this
+    
+    clear  : ->
+        @remove()
+        @model.destroy()
+        @trigger 'clear', this
+        this
+    
+    hide : -> @$el.hide(); @trigger('hide', this); this
+    show : -> @$el.show(); @trigger('show', this); this
+    
+    /**
+     * Attach each subview to its bind-point.
+     * @returns {this}
+     */
+    attachSubviews: ->
+        bps = @getOwnSubviewBindPoints()
+        if @subviews.length and not bps.length
+            console.warn "#this.attachSubviews(): no subview bind-points found!"
+            return this
+        for view of @subviews
+            if bp = @findSubviewBindPoint view, bps
+                view.attach bp
+            else
+                console.warn "#this.attachSubviews(): Unable to find bind-point for #view!"
         this
     
+    /**
+     * Finds all subview bind-points under this view's element, but not under
+     * the view element of any subview.
+     * @returns {jQuery|undefined}
+     */
+    getOwnSubviewBindPoints: ->
+        @$ '[data-subview]' .not @$ '[data-subview] [data-subview]'
+    
+    /**
+     * Find the matching subview bind-point for the given view.
+     */
+    findSubviewBindPoint: (view, bind_points) ->
+        bind_points or= @getOwnSubviewBindPoints()
+        
+        # check if any bindpoint specifies this subview by id
+        if view.id
+            bp = bind_points.filter "[data-subview$=':#{view.id}']"
+            return bp.eq 0 if bp.length
+        
+        # Find all elements that specify this type as the subview type
+        bp = bind_points.filter "[data-subview='#{view.getClassName()}']"
+        return bp.eq 0 if bp.length
+    
+    
     
     ### Rendering Chain
     
     toTemplateLocals: ->
-        json = {value:v} = @model.toJSON()
-        if _.isArray(v) or _.isObject(v)
-            json.value = JSON.stringify v
-        json
+        @model.toJSON()
     
-    $template: (locals={}) ->
-        $ @template do
-            { $, _, op, @model, view:this } import @toTemplateLocals() import locals
+    $template: ->
+        $ @template { _, op, @model, view:this, ...@toTemplateLocals() }
     
     build: ->
         return this unless @template
@@ -129,59 +204,52 @@ BaseView = exports.BaseView = Backbone.View.extend mixinBase do # {{{
         @$el.html outer.html()
             .attr do
                 id    : outer.attr 'id'
-                class : outer.attr('class')
+                class : outer.attr 'class'
         @attachSubviews()
+        @isBuilt = true
         this
     
     render: ->
-        @build()
+        if @isBuilt
+            @update()
+        else
+            @build()
+        @renderSubviews()
         @trigger 'render', this
         this
     
     renderSubviews: ->
-        _.invoke _.pluck(@subviews, 0), 'render'
+        @attachSubviews()
+        @subviews.invoke 'render'
         this
     
-    
-    attach: (el) ->
-        @$el.appendTo el
-        # only trigger the event the first time
-        return this if @_parented
-        @_parented = true
-        _.delay do
-            ~> # have to let DOM settle to ensure elements can be found
-                @delegateEvents()
-                @trigger 'parent', this
-            50
+    update: ->
+        new DataBinding this .update @toTemplateLocals()
+        @trigger 'update', this
         this
     
-    remove : ->
-        @undelegateEvents()
-        @$el.remove()
-        return this unless @_parented
-        @_parented = false
-        @trigger 'unparent', this
-        this
     
+    /* * * *  Events  * * * */
     
-    ### UI Utilities
+    bubbleEvent: (evt) ->
+        @invokeSubviews 'trigger', ...arguments
+        this
     
-    hide   : -> @$el.hide();      @trigger('hide', this);       this
-    show   : -> @$el.show();      @trigger('show', this);       this
-    clear  : -> @model.destroy(); @trigger('clear', this);      @remove()
+    redispatch: (evt) ->
+        @trigger ...arguments
+        this
     
+    onlyOnReturn: (fn, ...args) ->
+        fn = _.debounce fn.bind(this), 50
+        (evt) ~> fn.apply this, args if evt.keyCode is 13
     
-    # 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
+    /**
+     * Call a delegate on keypress == the return key.
+     * @returns {Function} Keypress event handler.
+     */
+    onReturnKeypress: (evt) ->
+        fn = this[@callOnReturnKeypress] if @callOnReturnKeypress
+        fn.call this if fn and evt.keyCode is 13
     
     toString : ->
         "#{@getClassName()}(model=#{@model})"
@@ -194,3 +262,27 @@ BaseView = exports.BaseView = Backbone.View.extend mixinBase do # {{{
 
 # }}}
 
+
+
+class exports.ViewList extends Array
+    
+    (views=[]) ->
+        super ...
+    
+    extend: (views) ->
+        _.each views, ~> @push it
+        this
+    
+    findByModel: (model) ->
+        @find -> it.model is model
+    
+    toString: ->
+        contents = if @length then "\"#{@join '","'}\"" else ''
+        "ViewList[#{@length}](#contents)"
+
+
+<[ each contains invoke pluck find remove compact flatten without union intersection difference unique uniq ]>
+    .forEach (methodname) ->
+        ViewList::[methodname] = -> _[methodname].call _, this, ...arguments
+
+
index b3b17f8..9a31587 100644 (file)
@@ -1,6 +1,7 @@
-mixins    = require 'kraken/base/base-mixin'
-models    = require 'kraken/base/base-model'
-views     = require 'kraken/base/base-view'
-cache     = require 'kraken/base/model-cache'
-cascading = require 'kraken/base/cascading-model'
-exports import mixins import models import views import cache import cascading
+mixins       = require 'kraken/base/base-mixin'
+models       = require 'kraken/base/base-model'
+views        = require 'kraken/base/base-view'
+cache        = require 'kraken/base/model-cache'
+cascading    = require 'kraken/base/cascading-model'
+data_binding = require 'kraken/base/data-binding'
+exports import mixins import models import views import cache import cascading import data_binding
index a531efe..cdba717 100644 (file)
@@ -59,8 +59,8 @@ ChartOption = exports.ChartOption = Field.extend do # {{{
         KNOWN_TAGS.update @getCategory()
         
         # Ignore functions/callbacks and, ahem, hidden tags.
-        type = @get 'type', '' .toLowerCase()
-        tags = @get 'tags', []
+        type = @get 'type' .toLowerCase() or ''
+        tags = @get('tags') or []
         if _.str.include(type, 'function') or _.intersection(tags, @IGNORED_TAGS).length
             @set 'ignore', true
     
@@ -69,7 +69,7 @@ ChartOption = exports.ChartOption = Field.extend do # {{{
     # will not trigger the 'changed:tags' event.
     addTag: (tag) ->
         return this unless tag
-        tags = @get('tags', [])
+        tags = @get('tags') or []
         tags.push tag
         @set 'tags', tags
         this
@@ -78,7 +78,7 @@ ChartOption = exports.ChartOption = Field.extend do # {{{
     # will not trigger the 'changed:tags' event.
     removeTag: (tag) ->
         return this unless tag
-        tags = @get('tags', [])
+        tags = @get('tags') or []
         _.remove tags, tag
         @set 'tags', tags
         this
@@ -93,7 +93,7 @@ ChartOption = exports.ChartOption = Field.extend do # {{{
     
     # A field's category is its first tag.
     getCategory: ->
-        @get('tags', [])[0]
+        tags = (@get('tags') or [])[0]
     
     getCategoryIndex: ->
         @getTagIndex @getCategory()
@@ -112,7 +112,7 @@ ChartOption = exports.ChartOption = Field.extend do # {{{
  * @class List of ChartOption fields.
  */
 ChartOptionList = exports.ChartOptionList = FieldList.extend do # {{{
-    model      : ChartOption
+    model : ChartOption
     
     
     constructor: function ChartOptionList
index bf7329a..86d86e0 100644 (file)
@@ -19,9 +19,9 @@ ChartOptionView = exports.ChartOptionView = FieldView.extend do # {{{
     isCollapsed : true
     
     events :
-        'blur .value'                        : 'update'
-        'click input[type="checkbox"].value' : 'update'
-        'submit .value'                      : 'update'
+        'blur .value'                        : 'change'
+        'click input[type="checkbox"].value' : 'change'
+        'submit .value'                      : 'change'
         'click .close'                       : 'toggleCollapsed'
         'click h3'                           : 'toggleCollapsed'
         'click .collapsed'                   : 'onClick'
@@ -32,6 +32,7 @@ ChartOptionView = exports.ChartOptionView = FieldView.extend do # {{{
     
     render: ->
         FieldView::render ...
+        @$el.addClass 'ignore'    if @get 'ignore'
         @$el.addClass 'collapsed' if @isCollapsed
         this
     
@@ -106,9 +107,10 @@ ChartOptionScaffold = exports.ChartOptionScaffold = Scaffold.extend do # {{{
     
     render: ->
         console.log "#this.render(ready=#{@ready}) -> .isotope()"
-        # Scaffold::render ...
+        Scaffold::render ...
         return this unless @ready
-        container = if @fields then @$el.find @fields else @$el
+        
+        container = if @fields then @$ @fields else @$el
         container
             .addClass 'isotope'
             .find '.chart-option.field' .addClass 'isotope-item'
@@ -125,21 +127,21 @@ ChartOptionScaffold = exports.ChartOptionScaffold = Scaffold.extend do # {{{
         this
     
     getOptionsFilter: ->
-        data = @$el.find '.options-filter-button.active' .toArray().map -> $ it .data()
+        data = @$ '.options-filter-button.active' .toArray().map -> $ it .data()
         sel = data.reduce do
             (sel, d) ->
                 sel += that if d.filter
                 sel
-            ''
+            ':not(.ignore)'
         sel
     
     collapseAll: ->
-        _.invoke @_subviews, 'collapse', true
+        _.invoke @subviews, 'collapse', true
         # @renderSubviews()
         false
     
     expandAll: ->
-        _.invoke @_subviews, 'collapse', false
+        _.invoke @subviews, 'collapse', false
         # @renderSubviews()
         false
     
@@ -148,9 +150,10 @@ ChartOptionScaffold = exports.ChartOptionScaffold = Scaffold.extend do # {{{
      * Add a ChartOption to this scaffold, rerendering the isotope
      * layout after collapse events.
      */
-    addOne: (field) ->
-        view = Scaffold::addOne ...
-        view.on 'change:collapse render', @render, this
+    addField: (field) ->
+        view = Scaffold::addField ...
+        # view.on 'change:collapse render', @render, this
+        view.on 'change:collapse', @render, this
         view
     
     toKV: ->
index 470647b..fe66048 100644 (file)
@@ -68,7 +68,7 @@ DashboardView = exports.DashboardView = BaseView.extend do # {{{
                 @trigger 'ready', this
     
     attachGraphs: ->
-        graphs_el = @$el.find '#graphs'
+        graphs_el = @$ '#graphs'
         for id of @graph_ids
             break unless graph = @graphs.get id
             continue if graph.view.isAttached
index d031f97..f07549e 100644 (file)
@@ -1,7 +1,7 @@
 Seq = require 'seq'
 { _, op,
 } = require 'kraken/util'
-{ BaseView,
+{ BaseView, ViewList,
 } = require 'kraken/base'
 { DataSetView,
 } = require 'kraken/dataset/dataset-view'
@@ -18,7 +18,6 @@ DataView = exports.DataView = BaseView.extend do # {{{
     className      : 'data-ui'
     template       : require 'kraken/template/data'
     
-    data        : {}
     datasources : null
     
     
@@ -29,36 +28,41 @@ DataView = exports.DataView = BaseView.extend do # {{{
     initialize: ->
         @graph_id = @options.graph_id
         BaseView::initialize ...
+        @metric_views = new ViewList
         @datasources = @model.sources
+        @model.metrics
+       &n