Commit 90d42a5d authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Automatic splitting of categories list to columns.

Simplified the structure of overviewData.json file. Categories
and class names are now inside one data-structure, and no columns
are specified.

Current implementation of splitting classes list into columns
is too simple-minded.  Have to improve it.  Otherwise it's working.
parent 1bf369d7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -95,11 +95,11 @@ module JsDuck
        @timer.time(:parsing) { @guides.parse_dir(@guides_dir) }
      end

      @categories = Categories.new(get_doc_formatter(relations))
      @categories = Categories.new(get_doc_formatter(relations), relations)
      if @categories_path
        @timer.time(:parsing) do
          @categories.parse(@categories_path)
          @categories.validate(relations)
          @categories.validate
        end
      end

+63 −32
Original line number Diff line number Diff line
@@ -5,58 +5,48 @@ module JsDuck

  # Reads in categories and outputs JSON file
  class Categories
    def initialize(doc_formatter)
    def initialize(doc_formatter, relations={})
      @doc_formatter = doc_formatter
      @overview = {"organisation" => [], "categories" => {}}
      @relations = relations
      @categories = []
    end

    # Parses categories in JSON file
    def parse(path)
      @overview = JSON.parse(IO.read(path))
      @categories = JSON.parse(IO.read(path))["categories"]
    end

    # Prints warnings for missing classes in categories file
    def validate(relations)
      overview_classes = {}
    def validate
      listed_classes = {}

      # Check that each class listed in overview file exists
      @overview["categories"].each_pair do |cat_name, cat|
        cat["classes"].each do |cls_name|
          unless relations[cls_name]
            Logger.instance.warn("Class '#{cls_name}' in category '#{cat_name}' not found")
      @categories.each do |cat|
        cat["groups"].each do |group|
          group["classes"].each do |cls_name|
            unless @relations[cls_name]
              Logger.instance.warn("Class '#{cls_name}' in category '#{cat['name']}/#{group['name']}' not found")
            end
            listed_classes[cls_name] = true
          end
          overview_classes[cls_name] = true
        end
      end

      # Check that each existing non-private class is listed in overview file
      relations.each do |cls|
        unless overview_classes[cls[:name]] || cls[:private]
          Logger.instance.warn("Class '#{cls[:name]}' not found in overview file")
      @relations.each do |cls|
        unless listed_classes[cls[:name]] || cls[:private]
          Logger.instance.warn("Class '#{cls[:name]}' not found in categories file")
        end
      end
    end

    # Returns HTML listing of classes divided into categories
    def to_html
      html = @overview["organisation"].map do |group|
      html = @categories.map do |category|
        [
          "<div class='section classes'>",
          "<h1>#{group['name']}</h1>",
          group['categories'].map do |cat|
            [
              "<div class='#{cat['align']}'>",
              cat['items'].map do |item|
                [
                  "<h3>#{item}</h3>",
                  "<div class='links'>",
                  class_links(item),
                  "</div>",
                ]
              end,
              "</div>",
            ]
          end,
          "<h1>#{category['name']}</h1>",
          render_columns(category['groups']),
          "<div style='clear:both'></div>",
          "</div>",
        ]
@@ -69,10 +59,51 @@ module JsDuck
      EOHTML
    end

    def class_links(category)
      return @overview["categories"][category]["classes"].map do |cls|
        @doc_formatter.link(cls, nil, cls)
    def render_columns(groups)
      align = ["lft", "mid", "rgt"]
      i = -1
      return split_to_columns(groups, 3).map do |col|
        i += 1
        [
          "<div class='#{align[i]}'>",
          render_groups(col),
          "</div>",
        ]
      end
    end

    def render_groups(groups)
      return groups.map do |g|
        [
          "<h3>#{g['name']}</h3>",
          "<div class='links'>",
          g["classes"].map {|cls| @relations[cls] ? @doc_formatter.link(cls, nil, cls) : cls },
          "</div>",
        ]
      end
    end

    def split_to_columns(groups, n)
      header_size = 3
      # The size of one item is it's number of classes + the space for header
      total_size = groups.reduce(0) {|sum, g| sum + g["classes"].length + header_size }

      # split into n columns
      avg_col_size = (total_size / n).ceil
      columns = Array.new(n) {|i| [] }

      col_size = 0
      col_index = 0
      groups.each do |g|
        col_size += g["classes"].length + header_size
        columns[col_index] << g
        if col_size >= avg_col_size
          col_index += 1
          col_size = 0
        end
      end

      columns
    end

  end
+68 −0
Original line number Diff line number Diff line
require "jsduck/categories"

describe JsDuck::Categories do

  describe "splitting to one column" do
    before do
      categories = JsDuck::Categories.new({})
      @cols = categories.split_to_columns([
          {"classes" => ["1", "2", "3"]},
          {"classes" => ["4", "5"]},
          {"classes" => ["6"]},
        ], 1)
    end

    it "creates just one column" do
      @cols.length.should == 1
    end

    it "places all groups to first column" do
      @cols[0].length.should == 3
    end
  end

  describe "splitting to two equal-height columns" do
    before do
      categories = JsDuck::Categories.new({})
      @cols = categories.split_to_columns([
          {"classes" => ["1", "2", "3", "4", "5", "6"]}, # 6+3 = 9
          {"classes" => ["7", "8"]}, # 2+3 = 5
          {"classes" => ["9"]}, # 1+3 = 4
        ], 2)
    end

    it "creates two columns" do
      @cols.length.should == 2
    end

    it "places first group to first column" do
      @cols[0].length.should == 1
    end

    it "places other two groups to second column" do
      @cols[1].length.should == 2
    end
  end

  describe "splitting one group to two columns" do
    before do
      categories = JsDuck::Categories.new({})
      @cols = categories.split_to_columns([
          {"classes" => ["1", "2"]}
        ], 2)
    end

    it "creates two columns" do
      @cols.length.should == 2
    end

    it "places first group to first column" do
      @cols[0].length.should == 1
    end

    it "leaves the second column empty" do
      @cols[1].length.should == 0
    end
  end

end
+461 −470
Original line number Diff line number Diff line
{
    "organisation": [
        {
            "name": "Base",
            "categories": [
                {"align": "lft", "items": ["Class System", "Support"]},
                {"align": "mid", "items": ["Application Architecture"]},
                {"align": "rgt", "items": ["DOM & Browser"]}
            ]
        },
        {
            "name": "View",
            "categories": [
                {"align": "lft", "items": ["Containers & Panels"]},
                {"align": "mid", "items": ["Layouts"]},
                {"align": "rgt", "items": ["Draw"]}
            ]
        },
        {
            "name": "Components",
    "categories": [
                {"align": "lft", "items": ["Components","Tree","Toolbar","Menu"]},
                {"align": "mid", "items": ["Form","Form Actions","Grid"]},
                {"align": "rgt", "items": ["Charts","Drag & Drop","Component Utilities"]}
            ]
        },
        {
            "name": "Data",
            "categories": [
                {"align": "lft", "items": ["Data Models","Data Readers & Writers"]},
                {"align": "mid", "items": ["Data Proxies"]},
                {"align": "rgt", "items": ["Data Stores","Direct"]}
            ]
        },
            "name": "Base",
            "groups": [
                {
            "name": "Utilities",
            "categories": [
                {"align": "lft", "items": ["Native Extensions"]},
                {"align": "mid", "items": ["Utility"]},
                {"align": "rgt", "items": ["Events"]}
            ]
        }
    ],

    "categories": {
        "Class System": {
            "guide": "class_system",
                    "name": "Class System",
                    "classes": [
                        "Ext",
                        "Ext.Base",
@@ -55,8 +15,33 @@
                        "Ext.PluginManager"
                    ]
                },
        "DOM & Browser": {
            "guide": "DOM",
                {
                    "name": "Support",
                    "classes": [
                        "Ext.is",
                        "Ext.env.Browser",
                        "Ext.env.FeatureDetector",
                        "Ext.env.OS",
                        "Ext.supports",
                        "Ext.Version"
                    ]
                },
                {
                    "name": "Application Architecture",
                    "classes": [
                        "Ext.app.Application",
                        "Ext.app.Controller",
                        "Ext.ModelManager",
                        "Ext.state.CookieProvider",
                        "Ext.state.Manager",
                        "Ext.state.Provider",
                        "Ext.state.LocalStorageProvider",
                        "Ext.state.Stateful",
                        "Ext.util.History"
                    ]
                },
                {
                    "name": "DOM & Browser",
                    "classes": [
                        "Ext.DomQuery",
                        "Ext.CompositeElement",
@@ -82,9 +67,14 @@
                        "Ext.data.JsonP",
                        "Ext.ElementLoader"
                    ]
                }
            ]
        },
        "Containers & Panels": {
            "guide": "layouts_and_containers",
        {
            "name": "View",
            "groups": [
                {
                    "name": "Containers & Panels",
                    "classes": [
                        "Ext.container.AbstractContainer",
                        "Ext.container.Container",
@@ -102,8 +92,8 @@
                        "Ext.form.Panel"
                    ]
                },
        "Layouts": {
            "guide": "layouts_and_containers",
                {
                    "name": "Layouts",
                    "classes": [
                        "Ext.layout.Layout",
                        "Ext.layout.container.Accordion",
@@ -125,8 +115,25 @@
                        "Ext.layout.container.VBox"
                    ]
                },
        "Components": {
            "guide": "components",
                {
                    "name": "Draw",
                    "classes": [
                        "Ext.draw.Color",
                        "Ext.draw.Component",
                        "Ext.draw.CompositeSprite",
                        "Ext.draw.Sprite",
                        "Ext.draw.Surface",
                        "Ext.draw.engine.Svg",
                        "Ext.draw.engine.Vml"
                    ]
                }
            ]
        },
        {
            "name": "Components",
            "groups": [
                {
                    "name": "Components",
                    "classes": [
                        "Ext.ComponentQuery",
                        "Ext.AbstractComponent",
@@ -154,8 +161,8 @@
                        "Ext.window.Window"
                    ]
                },
        "Tree": {
            "guide": "tree",
                {
                    "name": "Tree",
                    "classes": [
                        "Ext.tree.Panel",
                        "Ext.data.Tree",
@@ -164,7 +171,8 @@
                        "Ext.tree.View"
                    ]
                },
        "Toolbar": {
                {
                    "name": "Toolbar",
                    "classes": [
                        "Ext.toolbar.Fill",
                        "Ext.toolbar.Item",
@@ -175,45 +183,8 @@
                        "Ext.toolbar.Toolbar"
                    ]
                },
        "Grid": {
            "guide": "grid",
            "classes": [
                "Ext.grid.Panel",
                "Ext.grid.column.Column",
                "Ext.grid.column.Action",
                "Ext.grid.column.Boolean",
                "Ext.grid.column.Date",
                "Ext.grid.column.Number",
                "Ext.grid.column.Template",
                "Ext.grid.feature.AbstractSummary",
                "Ext.grid.feature.Chunking",
                "Ext.grid.feature.RowBody",
                "Ext.grid.feature.Summary",
                "Ext.grid.feature.Feature",
                "Ext.grid.feature.Grouping",
                "Ext.grid.feature.GroupingSummary",
                "Ext.grid.header.Container",
                "Ext.grid.PagingScroller",
                "Ext.grid.property.Grid",
                "Ext.grid.property.HeaderContainer",
                "Ext.grid.property.Property",
                "Ext.grid.property.Store",
                "Ext.grid.plugin.CellEditing",
                "Ext.grid.plugin.DragDrop",
                "Ext.grid.plugin.Editing",
                "Ext.grid.plugin.HeaderResizer",
                "Ext.grid.plugin.RowEditing",
                "Ext.grid.RowNumberer",
                "Ext.grid.Scroller",
                "Ext.view.AbstractView",
                "Ext.view.BoundList",
                "Ext.view.BoundListKeyNav",
                "Ext.view.TableChunker",
                "Ext.view.Table",
                "Ext.view.View"
            ]
        },
        "Menu": {
                {
                    "name": "Menu",
                    "classes": [
                        "Ext.menu.CheckItem",
                        "Ext.menu.ColorPicker",
@@ -224,8 +195,8 @@
                        "Ext.menu.Separator"
                    ]
                },
        "Form": {
            "guide": "forms",
                {
                    "name": "Form",
                    "classes": [
                        "Ext.form.Basic",
                        "Ext.form.CheckboxGroup",
@@ -255,7 +226,8 @@
                        "Ext.form.field.VTypes"
                    ]
                },
        "Form Actions": {
                {
                    "name": "Form Actions",
                    "classes": [
                        "Ext.form.action.Action",
                        "Ext.form.action.DirectLoad",
@@ -265,7 +237,98 @@
                        "Ext.form.action.Submit"
                    ]
                },
        "Component Utilities": {
                {
                    "name": "Grid",
                    "classes": [
                        "Ext.grid.Panel",
                        "Ext.grid.column.Column",
                        "Ext.grid.column.Action",
                        "Ext.grid.column.Boolean",
                        "Ext.grid.column.Date",
                        "Ext.grid.column.Number",
                        "Ext.grid.column.Template",
                        "Ext.grid.feature.AbstractSummary",
                        "Ext.grid.feature.Chunking",
                        "Ext.grid.feature.RowBody",
                        "Ext.grid.feature.Summary",
                        "Ext.grid.feature.Feature",
                        "Ext.grid.feature.Grouping",
                        "Ext.grid.feature.GroupingSummary",
                        "Ext.grid.header.Container",
                        "Ext.grid.PagingScroller",
                        "Ext.grid.property.Grid",
                        "Ext.grid.property.HeaderContainer",
                        "Ext.grid.property.Property",
                        "Ext.grid.property.Store",
                        "Ext.grid.plugin.CellEditing",
                        "Ext.grid.plugin.DragDrop",
                        "Ext.grid.plugin.Editing",
                        "Ext.grid.plugin.HeaderResizer",
                        "Ext.grid.plugin.RowEditing",
                        "Ext.grid.RowNumberer",
                        "Ext.grid.Scroller",
                        "Ext.view.AbstractView",
                        "Ext.view.BoundList",
                        "Ext.view.BoundListKeyNav",
                        "Ext.view.TableChunker",
                        "Ext.view.Table",
                        "Ext.view.View"
                    ]
                },
                {
                    "name": "Charts",
                    "classes": [
                        "Ext.chart.Callout",
                        "Ext.chart.Chart",
                        "Ext.chart.Highlight",
                        "Ext.chart.Legend",
                        "Ext.chart.Label",
                        "Ext.chart.LegendItem",
                        "Ext.chart.Mask",
                        "Ext.chart.Navigation",
                        "Ext.chart.Tip",
                        "Ext.chart.axis.Abstract",
                        "Ext.chart.axis.Axis",
                        "Ext.chart.axis.Category",
                        "Ext.chart.axis.Gauge",
                        "Ext.chart.axis.Numeric",
                        "Ext.chart.axis.Time",
                        "Ext.chart.series.Area",
                        "Ext.chart.series.Bar",
                        "Ext.chart.series.Cartesian",
                        "Ext.chart.series.Column",
                        "Ext.chart.series.Gauge",
                        "Ext.chart.series.Line",
                        "Ext.chart.series.Pie",
                        "Ext.chart.series.Radar",
                        "Ext.chart.series.Scatter",
                        "Ext.chart.series.Series",
                        "Ext.chart.theme.Theme"
                    ]
                },
                {
                    "name": "Drag & Drop",
                    "classes": [
                        "Ext.dd.DD",
                        "Ext.dd.DDProxy",
                        "Ext.dd.DDTarget",
                        "Ext.dd.DragDrop",
                        "Ext.dd.DragDropManager",
                        "Ext.dd.DragSource",
                        "Ext.dd.DragTracker",
                        "Ext.dd.DragZone",
                        "Ext.dd.DropTarget",
                        "Ext.dd.DropZone",
                        "Ext.dd.Registry",
                        "Ext.dd.ScrollManager",
                        "Ext.dd.StatusProxy",
                        "Ext.panel.Proxy",
                        "Ext.tree.plugin.TreeViewDragDrop",
                        "Ext.util.ComponentDragger"
                    ]
                },
                {
                    "name": "Component Utilities",
                    "classes": [
                        "Ext.Action",
                        "Ext.ComponentLoader",
@@ -288,30 +351,14 @@
                        "Ext.XTemplate",
                        "Ext.ZIndexManager"
                    ]
        },
        "Drag & Drop": {
            "guide": "drag_and_drop",
            "classes": [
                "Ext.dd.DD",
                "Ext.dd.DDProxy",
                "Ext.dd.DDTarget",
                "Ext.dd.DragDrop",
                "Ext.dd.DragDropManager",
                "Ext.dd.DragSource",
                "Ext.dd.DragTracker",
                "Ext.dd.DragZone",
                "Ext.dd.DropTarget",
                "Ext.dd.DropZone",
                "Ext.dd.Registry",
                "Ext.dd.ScrollManager",
                "Ext.dd.StatusProxy",
                "Ext.panel.Proxy",
                "Ext.tree.plugin.TreeViewDragDrop",
                "Ext.util.ComponentDragger"
                }
            ]
        },
        "Data Models": {
            "guide": "data",
        {
            "name": "Data",
            "groups": [
                {
                    "name": "Data Models",
                    "classes": [
                        "Ext.data.Model",
                        "Ext.data.Field",
@@ -324,8 +371,20 @@
                        "Ext.data.Errors"
                    ]
                },
        "Data Proxies": {
            "guide": "data",
                {
                    "name": "Data Readers & Writers",
                    "classes": [
                        "Ext.data.reader.Reader",
                        "Ext.data.reader.Array",
                        "Ext.data.reader.Json",
                        "Ext.data.reader.Xml",
                        "Ext.data.writer.Json",
                        "Ext.data.writer.Writer",
                        "Ext.data.writer.Xml"
                    ]
                },
                {
                    "name": "Data Proxies",
                    "classes": [
                        "Ext.data.proxy.Ajax",
                        "Ext.data.proxy.Client",
@@ -345,20 +404,8 @@
                        "Ext.data.ResultSet"
                    ]
                },
        "Data Readers & Writers": {
            "guide": "data",
            "classes": [
                "Ext.data.reader.Reader",
                "Ext.data.reader.Array",
                "Ext.data.reader.Json",
                "Ext.data.reader.Xml",
                "Ext.data.writer.Json",
                "Ext.data.writer.Writer",
                "Ext.data.writer.Xml"
            ]
        },
        "Data Stores": {
            "guide": "data",
                {
                    "name": "Data Stores",
                    "classes": [
                        "Ext.data.AbstractStore",
                        "Ext.data.StoreManager",
@@ -367,8 +414,8 @@
                        "Ext.data.DirectStore"
                    ]
                },
        "Direct": {
            "guide": "direct",
                {
                    "name": "Direct",
                    "classes": [
                        "Ext.direct.Event",
                        "Ext.direct.ExceptionEvent",
@@ -380,64 +427,14 @@
                        "Ext.direct.RemotingProvider",
                        "Ext.direct.Transaction"
                    ]
        },
        "Application Architecture": {
            "guide": "application_architecture",
            "classes": [
                "Ext.app.Application",
                "Ext.app.Controller",
                "Ext.ModelManager",
                "Ext.state.CookieProvider",
                "Ext.state.Manager",
                "Ext.state.Provider",
                "Ext.state.LocalStorageProvider",
                "Ext.state.Stateful",
                "Ext.util.History"
            ]
        },
        "Draw": {
            "classes": [
                "Ext.draw.Color",
                "Ext.draw.Component",
                "Ext.draw.CompositeSprite",
                "Ext.draw.Sprite",
                "Ext.draw.Surface",
                "Ext.draw.engine.Svg",
                "Ext.draw.engine.Vml"
            ]
        },
        "Charts": {
            "guide": "drawing_and_charting",
            "classes": [
                "Ext.chart.Callout",
                "Ext.chart.Chart",
                "Ext.chart.Highlight",
                "Ext.chart.Legend",
                "Ext.chart.Label",
                "Ext.chart.LegendItem",
                "Ext.chart.Mask",
                "Ext.chart.Navigation",
                "Ext.chart.Tip",
                "Ext.chart.axis.Abstract",
                "Ext.chart.axis.Axis",
                "Ext.chart.axis.Category",
                "Ext.chart.axis.Gauge",
                "Ext.chart.axis.Numeric",
                "Ext.chart.axis.Time",
                "Ext.chart.series.Area",
                "Ext.chart.series.Bar",
                "Ext.chart.series.Cartesian",
                "Ext.chart.series.Column",
                "Ext.chart.series.Gauge",
                "Ext.chart.series.Line",
                "Ext.chart.series.Pie",
                "Ext.chart.series.Radar",
                "Ext.chart.series.Scatter",
                "Ext.chart.series.Series",
                "Ext.chart.theme.Theme"
                }
            ]
        },
        "Native Extensions": {
        {
            "name": "Utilities",
            "groups": [
                {
                    "name": "Native Extensions",
                    "classes": [
                        "Ext.Array",
                        "Ext.Number",
@@ -448,7 +445,8 @@
                        "Ext.Function"
                    ]
                },
        "Utility": {
                {
                    "name": "Utility",
                    "classes": [
                        "Ext.AbstractManager",
                        "Ext.util.Filter",
@@ -467,17 +465,8 @@
                        "Ext.util.Sortable"
                    ]
                },
        "Support": {
            "classes": [
                "Ext.is",
                "Ext.env.Browser",
                "Ext.env.FeatureDetector",
                "Ext.env.OS",
                "Ext.supports",
                "Ext.Version"
            ]
        },
        "Events": {
                {
                    "name": "Events",
                    "classes": [
                        "Ext.TaskManager",
                        "Ext.EventManager",
@@ -488,6 +477,8 @@
                        "Ext.util.TaskRunner"
                    ]
                }
            ]
        }
    ]
}