diff --git a/lib/jsduck/guides.rb b/lib/jsduck/guides.rb index 3814e789658621f6f466bcec5ebd59565675c6e4..dfa4e19a913a8bc73b6b11b2f7502df4c0a0d1d1 100644 --- a/lib/jsduck/guides.rb +++ b/lib/jsduck/guides.rb @@ -55,11 +55,34 @@ module JsDuck @formatter.doc_context = {:filename => guide_file, :linenr => 0} name = File.basename(in_dir) @formatter.img_path = "guides/#{name}" - html = @formatter.format(IO.read(guide_file)) + html = add_toc(guide, @formatter.format(IO.read(guide_file))) JsonDuck.write_jsonp(out_dir+"/README.js", name, {:guide => html, :title => guide["title"]}) end + # Creates table of contents at the top of guide by looking for

elements in HTML. + def add_toc(guide, html) + toc = [ + "

Contents

", + "" + # Inject TOC at below first heading + new_html.insert(1, toc) + new_html.flatten.join + end + # Returns all guides as array def to_array @guides diff --git a/template/app/controller/Guides.js b/template/app/controller/Guides.js index 3662f7a6b38bf607dc52164597d294530d10575c..8e87acc292f9a434a53e79ec4448a96f68a9763b 100644 --- a/template/app/controller/Guides.js +++ b/template/app/controller/Guides.js @@ -18,6 +18,10 @@ Ext.define('Docs.controller.Guides', { { ref: 'tree', selector: '#guidetree' + }, + { + ref: 'guide', + selector: '#guide' } ], @@ -56,9 +60,15 @@ Ext.define('Docs.controller.Guides', { }, '#guide': { afterrender: function(cmp) { - cmp.el.addListener('scroll', function(cmp, el) { + cmp.el.addListener('click', function(event, el) { this.setScrollState(this.activeUrl, el.scrollTop); }, this); + cmp.el.addListener('click', function(event, el) { + this.handleUrlClick(el.href, event); + }, this, { + preventDefault: true, + delegate: 'ul.toc > li > a' + }); } } }); @@ -96,12 +106,15 @@ Ext.define('Docs.controller.Guides', { loadGuide: function(url, noHistory) { Ext.getCmp('card-panel').layout.setActiveItem('guide'); Ext.getCmp('treecontainer').showTree('guidetree'); - var name = url.match(/^#!\/guide\/(.*)$/)[1]; + var m = url.match(/^#!\/guide\/(.*?)(-section-[0-9]+)?$/); + var name = m[1]; + var section = m[2]; + url = "#!/guide/"+name; // ignore section in URL noHistory || Docs.History.push(url); if (this.cache[name]) { - this.showGuide(this.cache[name], url, name); + this.showGuide(this.cache[name], url, name, section); } else { this.cache[name] = "in-progress"; @@ -110,7 +123,7 @@ Ext.define('Docs.controller.Guides', { callbackName: name, success: function(json) { this.cache[name] = json; - this.showGuide(json, url, name); + this.showGuide(json, url, name, section); }, failure: function(response, opts) { this.cache[name] = false; @@ -126,9 +139,10 @@ Ext.define('Docs.controller.Guides', { * * @param {Object} json Guide json * @param {String} url URL of the guide - * @param {Boolean} name Name of the guide + * @param {String} name Name of the guide + * @param {String} [section] Section name */ - showGuide: function(json, url, name) { + showGuide: function(json, url, name, section) { var reRendered = false; if (json === "in-progress") { @@ -143,13 +157,9 @@ Ext.define('Docs.controller.Guides', { reRendered = true; } this.activeUrl = url; - this.scrollContent(); + section ? this.getGuide().scrollToEl(name+section) : this.getGuide().scrollToTop(); this.fireEvent('showGuide', name, { reRendered: reRendered }); this.getTree().selectUrl(url); - }, - - scrollContent: function() { - Ext.get('guide').scrollTo('top', this.getScrollState(this.activeUrl)); } }); diff --git a/template/app/view/guides/Container.js b/template/app/view/guides/Container.js index e881d8a54555fd38393c711f15d464751645274c..512adf9f562e47bc2c1803a71005f537bd1dc454 100644 --- a/template/app/view/guides/Container.js +++ b/template/app/view/guides/Container.js @@ -19,6 +19,28 @@ Ext.define('Docs.view.guides.Container', { this.callParent(arguments); }, + /** + * Scrolls the specified element into view + * + * @param {String} id ID of elemnt to scroll to. + */ + scrollToEl: function(id) { + var el = Ext.get(id); + if (el) { + var scrollOffset = el.getY() - 100; + var currentScroll = this.getEl().getScroll()['top']; + this.getEl().scrollTo('top', currentScroll + scrollOffset); + el.highlight(); + } + }, + + /** + * Scrolls guide to the top + */ + scrollToTop: function() { + this.getEl().scrollTo('top'); + }, + /** * Loads guide into the page. * @param {Object} guide