Commit 40bebff2 authored by Nick Poulden's avatar Nick Poulden
Browse files

Merge hover menu buttons

parent 72513b7c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ elsif File.exists?(app.output_dir) && !File.directory?(app.output_dir)
  puts "Oh noes!  The output directory is not really a directory at all :("
  exit(1)
elsif !File.exists?(File.dirname(app.output_dir))
  puts "Oh noes!  The parent directory for #{output_dir} doesn't exist."
  puts "Oh noes!  The parent directory for #{app.output_dir} doesn't exist."
  exit(1)
elsif !File.exists?(app.template_dir + "/extjs")
  puts "Oh noes!  The template directory does not contain extjs/ directory :("
+124 −0
Original line number Diff line number Diff line
/**
 * Toolbar button with menu that appears when hovered over.
 */
Ext.define('Docs.view.class.HoverMenuButton', {
    extend: 'Ext.toolbar.TextItem',
    componentCls: "hover-menu-button",

    /**
     * @cfg {[String]} links
     * Array of HTML anchor elements to be shown in menu.
     */
    links: [],
    
    menus: [],

    statics: {
        // Global list of all menus.
        // So we can hide all other menus while showing a specific one.
        menus: []
    },

    initComponent: function() {
        this.addEvents(
            /**
             * @event click
             * Fired when button clicked.
             */
            "click"
        );

        // Append links count to button text
        this.text += ' <span class="num">' + this.links.length + '</span>';

        this.callParent(arguments);
    },

    onRender: function() {
        var me = this;
        
        this.callParent(arguments);

        this.renderMenu();

        this.getEl().on({
            click: function() {
                this.fireEvent("click");
            },
            mouseover: function() {
                // hide other menus
                Ext.Array.forEach(me.menus, function(menu) {
                    if (menu !== this.menu) {
                        menu.setStyle({display: "none"});
                    }
                });
                // stop pending menuhide process
                clearTimeout(this.hideTimeout);
                // position menu right below button and show it
                var p = this.getEl().getXY();
                this.menu.setStyle({
                    left: p[0]+"px",
                    top: (p[1]+23)+"px",
                    display: "block"
                });
            },
            mouseout: this.deferHideMenu,
            scope: this
        });

        this.menu.on({
            mouseover: function() {
                clearTimeout(this.hideTimeout);
            },
            mouseout: this.deferHideMenu,
            scope: this
        });
    },

    onDestroy: function() {
        // clean up DOM
        this.menu.remove();
        // remove from global menu list
        Ext.Array.remove(this.menus, this.menu);

        this.callParent(arguments);
    },

    renderMenu: function() {
        this.menu = Ext.get(Ext.core.DomHelper.append(document.body, {
            html: this.renderMenuHtml(),
            cls: 'hover-menu-menu'
        }));
        this.menus.push(this.menu);
    },

    renderMenuHtml: function() {
        // divide links into columns with at most 25 links in one column
        var columns = [];
        for (var i=0; i<this.links.length; i+=25) {
            columns.push(this.links.slice(i, i+25));
        }

        var tpl = new Ext.XTemplate(
            '<table>',
                '<tr>',
                    '<tpl for="columns">',
                        '<td>',
                            '<tpl for=".">',
                                '{.}',
                            '</tpl>',
                        '</td>',
                    '</tpl>',
                '</tr>',
            '</table>'
        );
        return tpl.apply({columns: columns});
    },

    deferHideMenu: function() {
        this.hideTimeout = Ext.Function.defer(function() {
            this.menu.setStyle({display: "none"});
        }, 200, this);
    }

});
+35 −44
Original line number Diff line number Diff line
@@ -7,6 +7,12 @@ Ext.define('Docs.view.class.Toolbar', {
    cls: 'member-links',
    padding: '3 5',

    /**
     * @cfg {Object} docClass
     * Documentation for a class.
     */
    docClass: {},

    initComponent: function() {
        this.items = [];

@@ -20,18 +26,15 @@ Ext.define('Docs.view.class.Toolbar', {
            var members = this.docClass[type];
            if (members.length) {
                this.items.push(this.createMemberButton({
                    items: members,
                    text: memberTitles[type],
                    type: type,
                    title: memberTitles[type]
                    members: members
                }));
            }
        }

        if (this.docClass.subclasses.length) {
            this.items.push(this.createSubClassesButton({
                items: this.docClass.subclasses,
                title: "Sub Classes"
            }));
            this.items.push(this.createSubClassesButton(this.docClass.subclasses));
        }

        this.items = this.items.concat([
@@ -70,53 +73,41 @@ Ext.define('Docs.view.class.Toolbar', {
    },

    createMemberButton: function(cfg) {
        var menu = Ext.create('Ext.menu.Menu', {
            items: Ext.Array.map(cfg.items, function(m) {
                return {
                    text: m.name,
                    memberName: cfg.type + '-' + m.name
                };
            }),
            plain: true,
            listeners: {
                click: function(menu, item) {
                    Ext.getCmp('doc-overview').scrollToEl("#" + item.memberName);
                }
            }
        });

        return Ext.create('Ext.button.Split', {
            cls: cfg.type,
            iconCls: 'icon-' + cfg.type,
            text: cfg.title + ' <span class="num">' + cfg.items.length + '</span>',
        return Ext.create('Docs.view.class.HoverMenuButton', {
            text: cfg.text,
            cls: 'icon-'+cfg.type,
            links: Ext.Array.map(cfg.members, function(m) {
                return this.createLink(this.docClass.name, m);
            }, this),
            listeners: {
                click: function() {
                    Ext.getCmp('doc-overview').scrollToEl("#m-" + cfg.type);
                }
            }
        });
    },
            menu: menu

    createSubClassesButton: function(subclasses) {
        return Ext.create('Docs.view.class.HoverMenuButton', {
            text: "Sub Classes",
            cls: 'icon-subclass',
            links: Ext.Array.map(subclasses, function(cls) {
                return this.createLink(cls);
            }, this)
        });
    },

    createSubClassesButton: function(cfg) {
        var menu = Ext.create('Ext.menu.Menu', {
            items: Ext.Array.map(cfg.items, function(className) {
                return {text: className, clsName: className};
            }),
            plain: true,
            listeners: {
                click: function(menu, item) {
                    Docs.ClassLoader.load(item.clsName);
    // Creates HTML link to class (and optionally to class member)
    createLink: function(cls, member) {
        if (member) {
            var url = cls+"-"+member.tagname+"-"+member.name;
            var label = member.name;
        }
        else {
            var url = cls;
            var label = cls;
        }
        });

        return Ext.create('Ext.button.Button', {
            cls: 'subcls',
            iconCls: 'icon-subclass',
            text: cfg.title + ' <span class="num">' + cfg.items.length + '</span>',
            menu: menu
        });
        return Ext.String.format('<a href="#/api/{0}" rel="{0}" class="docClass">{1}</a>', url, label);
    },

    hideInherited: function(el) {
+45 −0
Original line number Diff line number Diff line
@@ -485,3 +485,48 @@ a:hover {
  background: url(../images/expandcollapse.png) no-repeat -14px 2px !important; }
.collapseAllMembers {
  background: url(../images/expandcollapse.png) no-repeat 2px 2px !important; }

.member-links {
  border-width: 0 0 1px 0;
  border-style: solid;
  border-color: #bfbfbf;
  // @include vertical-gradient(#e8e8e8, #eaeaea)
  .num {
    font-size: 0.8em;
    position: relative;
    top: -4px; }
  .expandAllMembers {
    background: url(../images/expandcollapse.png) no-repeat -14px 2px; }
  .collapseAllMembers {
    background: url(../images/expandcollapse.png) no-repeat 2px 2px; } }
.hover-menu-button {
  padding-left: 20px;
  cursor: pointer; }
.hover-menu-menu {
  display: none; // hide initially
  font-size: 12px;
  position: absolute;
  padding: 5px 15px 10px;
  background: #eaeaea;
  z-index: 8;
  top: 21px;
  line-height: 1.3em;
  border: 1px solid #bfbfbf;
  border-top: 1px solid #eaeaea;
  left: -16px;
  border-radius-bottom: 5px;
  h2 {
    font-weight: bold;
    text-decoration: underline;
    padding-bottom: 5px; }
  a {
    display: block;
    position: relative;
    padding: 2px 30px 2px 0;
    color: #0464bb;
    white-space: nowrap;
    &:hover {
      color: #083772;
      text-decoration: underline; } }
  td {
    vertical-align: top; } }