Commit 0b50fa0a authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Read guides from JSON file located in SDK.

--guides option now must point to a JSON file.
--guides-order option removed.

The file is read in, parsed, and the guides listed in it are
copied to output_dir/guides + the usual Markdown conversion.

Additionally the list of guides is written to tree.js as Docs.guides.
So no separate .js file for guides is needed.

The guides HTML is no more written inside index.html
parent 5f24d32f
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -43,9 +43,8 @@ def run_jsduck(extra_options)
    "ruby", "bin/jsduck",
    # --external=Error to ignore the Error class that Ext.Error extends.
    "--external", "Error",
    "--guides", "#{SDK_DIR}/guides",
    "--guides", "#{SDK_DIR}/guides/guides.json",
    "--examples", "#{SDK_DIR}/extjs/doc-resources",
    "--guides-order", "getting,class,application,layouts,data,grid,tree,drawing,forms,components,theming,direct",
    "--categories", "#{SDK_DIR}/extjs/doc-resources/categories.json",
    "--output", "#{OUT_DIR}",
  ].concat(extra_options))
@@ -53,8 +52,7 @@ def run_jsduck(extra_options)
  # Finally copy over the images that documentation links to.
  system "cp -r #{SDK_DIR}/extjs/doc-resources #{OUT_DIR}/doc-resources"
  system "cp -r #{SDK_DIR}/platform/doc-resources/* #{OUT_DIR}/doc-resources"
  # And copy guides.js and videos.js
  system "cp #{SDK_DIR}/guides/guides.js #{OUT_DIR}/guides/"
  # And copy videos.js
  system "cp #{SDK_DIR}/guides/videos.js #{OUT_DIR}/guides/"
end

+4 −5
Original line number Diff line number Diff line
@@ -44,9 +44,9 @@ module JsDuck
      Aliases.new(@relations).resolve_all
      Lint.new(@relations).run

      @guides = Guides.new(get_doc_formatter, @opts.guides_order)
      if @opts.guides_dir
        @timer.time(:parsing) { @guides.parse_dir(@opts.guides_dir) }
      @guides = Guides.new(get_doc_formatter)
      if @opts.guides
        @timer.time(:parsing) { @guides.parse(@opts.guides) }
      end

      @categories = Categories.new(get_doc_formatter, @relations)
@@ -127,7 +127,7 @@ module JsDuck
      icons = TreeIcons.new.extract_icons(tree)
      js = "Docs.classData = " + JSON.generate( tree ) + ";"
      js += "Docs.icons = " + JSON.generate( icons ) + ";"
      js += "Docs.guideData = " + JSON.generate( @guides.to_tree ) + ";"
      js += "Docs.guides = " + JSON.generate( @guides.to_array ) + ";"
      File.open(@opts.output_dir+"/output/tree.js", 'w') {|f| f.write(js) }
    end

@@ -209,7 +209,6 @@ module JsDuck
      html.gsub!("{footer}", "<div id='footer-content' style='display: none'>#{@footer}</div>")
      html.gsub!("{extjs_path}", @opts.extjs_path)
      html.gsub!("{local_storage_db}", @opts.local_storage_db)
      html.gsub!("{guides}", @guides.to_html)
      html.gsub!("{categories}", @categories.to_html)
      html.gsub!("{head_html}", @opts.head_html)
      html.gsub!("{body_html}", @opts.body_html)
+27 −97
Original line number Diff line number Diff line
require 'jsduck/jsonp'
require 'jsduck/logger'
require 'fileutils'
require 'json'

module JsDuck

  # Reads in guides and converts them to JsonP files
  class Guides
    def initialize(formatter, order=nil)
      @guides = []
    def initialize(formatter)
      @formatter = formatter
      @order = order
    end

    # Looks for guide in each subdir of given directory.
    def parse_dir(guides_dir)
      Dir.glob(guides_dir + "/*").each do |dir|
        if File.directory?(dir)
          parse_guide(dir)
        end
      end

      if @order
        # When order specified, place guides into that order and
        # exclude those guides that aren't listed in @order
        @guides = @order.map {|name| @guides.find {|g| g[:name] =~ Regexp.new("^"+Regexp.escape(name)) } }
      else
        # Otherwise sort guides alphabetically
        @guides.sort! {|a, b| a[:title] <=> b[:title] }
      end
      @guides = []
    end

    def parse_guide(dir)
      guide_file = dir + "/README.md"
      unless File.exists?(guide_file)
        return Logger.instance.warn("README.md not found in #{dir}")
      end

      Logger.instance.log("Parsing guide #{guide_file} ...")
      markdown = IO.read(guide_file)
      name = File.basename(dir)
      # Treat the first line of file as title
      title = markdown.match(/^#\s*([^\n]*?)(\r?\n|$)/)[1]

      @formatter.doc_context = {:filename => guide_file, :linenr => 0}
      html = @formatter.format(markdown)
      html.gsub!(/<img src="/, "<img src=\"guides/#{name}/")

      @guides << {
        :dir => dir,
        :name => name,
        :title => title,
        :icon => File.exists?(dir+"/icon.png"),
        :html => html,
      }
    # Parses guides config file
    def parse(filename)
      @path = File.dirname(filename)
      @guides = JSON.parse(IO.read(filename))
    end

    # Writes all guides to given dir in JsonP format
    def write(dir)
      # Skip it all when we have no guides
      FileUtils.mkdir(dir) if @guides.length > 0
      return if @guides.length == 0

      @guides.each do |guide|
        out_dir = dir+"/"+guide[:name]
        FileUtils.cp_r(guide[:dir], out_dir)
        # Write the JsonP file
        JsonP.write(out_dir+"/README.js", guide[:name], {:guide => guide[:html]})
      end
      FileUtils.mkdir(dir)
      @guides.each {|group| group["items"].each {|g| write_guide(g, dir) } }
    end

    # Returns HTML listing of guides
    def to_html
      return "" if @guides.length == 0
    def write_guide(guide, dir)
      in_dir = @path + "/" + guide["name"]
      out_dir = dir + "/" + guide["name"]
      return Logger.instance.warn("Guide #{in_dir} not found") unless File.exists?(in_dir)
      guide_file = in_dir + "/README.md"
      return Logger.instance.warn("README.md not found in #{in_dir}") unless File.exists?(guide_file)

      links = @guides.map do |g|
        style = g[:icon] ? "style='background: url(guides/#{g[:name]}/icon.png) no-repeat'" : ""
        "<a class='guide' rel='#{g[:name]}' #{style} href='#/guide/#{g[:name]}'>#{g[:title]}</a>"
      end

      # Divide to three columns: lft, mid, rgt
      col_height = (links.length / 3.0).ceil
      return <<-EOHTML
        <div id='guides-content' style='display:none'>
            <div class="lft">
                #{links.slice(0, col_height).join("\n")}
            </div>
            <div class="mid">
                #{links.slice(col_height, col_height).join("\n")}
            </div>
            <div class="rgt">
                #{links.slice(col_height*2, col_height).join("\n")}
            </div>
        </div>
      EOHTML
    end
      Logger.instance.log("Writing guide #{out_dir} ...")
      # Copy the whole guide dir over
      FileUtils.cp_r(in_dir, out_dir)

    # Creates tree-structure containing all guides
    def to_tree
      return {} if @guides.length == 0

      return {
        :text => 'Guides',
        :children => @guides.map do |g|
          {
            :text => g[:title],
            :url => "/guide/"+g[:name],
            :iconCls => "icon-guide",
            :leaf => true
          }
        end
      }
    end
      @formatter.doc_context = {:filename => guide_file, :linenr => 0}
      html = @formatter.format(IO.read(guide_file))
      name = File.basename(in_dir)
      html.gsub!(/<img src="/, "<img src=\"guides/#{name}/")

    # Iterates over each guide
    def each(&block)
      @guides.each &block
      JsonP.write(out_dir+"/README.js", name, {:guide => html})
    end

    # Returns number of guides
    def length
      @guides.length
    # Returns all guides as array
    def to_array
      @guides
    end

  end
+8 −17
Original line number Diff line number Diff line
@@ -18,8 +18,7 @@ module JsDuck
    attr_accessor :footer
    attr_accessor :head_html
    attr_accessor :body_html
    attr_accessor :guides_dir
    attr_accessor :guides_order
    attr_accessor :guides
    attr_accessor :categories_path
    attr_accessor :examples_dir
    attr_accessor :link_tpl
@@ -48,8 +47,7 @@ module JsDuck
      @footer = 'Generated with <a href="https://github.com/senchalabs/jsduck">JSDuck</a>.'
      @head_html = ""
      @body_html = ""
      @guides_dir = nil
      @guides_order = nil
      @guides = nil
      @categories_path = nil
      @examples_dir = nil
      @link_tpl = '<a href="#/api/%c%-%m" rel="%c%-%m" class="docClass">%a</a>'
@@ -128,19 +126,12 @@ module JsDuck
          @body_html = html
        end

        opts.on('--guides=PATH', "Path to guides directory.",
          "Each subdirectory of that is treated as a guide",
          "and is expectd to contain a REAME.md file,",
          "which will be converted into a README.js.", " ") do |path|
          @guides_dir = path
        end

        opts.on('--guides-order=a,b,c', Array,
          "The order in which the guides should appear. When",
          "a guide name is not specified here, it will be excluded.",
          "You don't have to write the whole name of the guide,",
          "just the beginning of it, as long as it's unique.", " ") do |list|
          @guides_order = list
        opts.on('--guides=PATH',
          "Path to JSON file describing the guides. The file",
          "should be in a dir containing the actual guides.",
          "A guide is a dir containing README.md, icon.png,",
          "and other images referenced by the README.md file.", " ") do |path|
          @guides = path
        end

        opts.on('--categories=PATH',
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ Ext.define('Docs.controller.Classes', {
        },
        {
            ref: 'tree',
            selector: 'classtree[cmpName=classtree]'
            selector: 'classtree'
        },
        {
            ref: 'favoritesGrid',
Loading