-1

i want to display the following Post in 3 different sections. The first section is the table of content. The second is the summary and the third is the theory. Is like a multipage post but each page has a section, as I don't want to show all the information in a single page. Thanks in advance enter image description here

chenci
  • 103
  • 1
  • 8

1 Answers1

1

The way I have come up with this is this way.

I'm only posting these because I have it all setup so I can basically copy and paste it in. Next time I want to see more effort on your part.

Create a new JS file. well call it mytabs.js in that file put this:

;( function( $, window, document, undefined ) {
    "use strict";
    $( document ).ready( function() {
         var loadTabOrder = function(id){
            //  Define friendly data store name
            var dataStore = window.sessionStorage;
            var oldIndex = 0;
            //  Start magic!
            try {
                // getter: Fetch previous value
                oldIndex = dataStore.getItem(id);
            } catch(e) {}
            return oldIndex;
        };

        var saveTabOrder = function(id, currentIndex){
            //  Define friendly data store name
            var dataStore = window.sessionStorage;
            //  Start magic!
            try {
                dataStore.setItem( id, currentIndex );
            } catch(e) {}
        };

        $('.ui-tabs-vertical').each(function(){  
            var id = $(this).prop('id');
            if(!id) $.error('.ui-tabs-vertical requires an id');

            var element = $( "#"+id );

            var options = {
                active: loadTabOrder(id),
                activate: function(event, ui) {
                    saveTabOrder(id, ui.newTab.parent().children().index(ui.newTab));               
                }
            };

            element.tabs(options).addClass( "ui-helper-clearfix" );
            var nav = element.find('> .ui-tabs-nav > li');
            nav.removeClass( "ui-corner-top" ).addClass( "ui-corner-left" );

            var height = 0;
            nav.each(function(){
                height += $(this).outerHeight();
            });

            element.find('> .ui-tabs-panel').css(
                'min-height',
                height+'px'
            );

        }); 
    } );

 } ) ( jQuery, window, document );

Somewhere in your theme/pllugin put this:

  //ui css
  wp_enqueue_style('jquery-ui');
  //jquery
  wp_enqueue_script('jquery'); 
  //jquery-ui
  wp_enqueue_script('jquery-ui');
  //you only need to do the above it you dont have them included already

  //add our JS page.
  wp_enqueue_script('mytabs', plugin_dir_url(__FILE__).'mytabs.php', ['juery-ui']);
  //in my case this is in a plugin file, obviously use your path to your JS file

In your CSS file add these, make sure your CSS loads after jQuery UI

.ui-tabs.ui-tabs-vertical {
    padding: 0;
    height: 100%;
    width: calc(100% - 15px);
    position: relative;
}
.ui-tabs.ui-tabs-vertical .ui-widget-header {
    border: none;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav {
    float: left;
    width: 10em;
    background: #EEE;
    border-radius: 4px 0 0 4px;
    border-right: 1px solid gray;
    position: absolute;
    top : 0;
    bottom: 0;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li {
    clear: left;
    width: 100%;
    margin: 0.2em 0;
    border: 1px solid gray;
    border-width: 1px 0 1px 1px;
    border-radius: 4px 0 0 4px;
    overflow: hidden;
    position: relative;
    right: -2px;
    z-index: 2;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a {
    display: block;
    width: 100%;
    padding: 0.6em 1em;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover {
    cursor: pointer;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
    margin-bottom: 0.2em;
    padding-bottom: 0;
    border-right: 1px solid white;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child {
    margin-bottom: 10px;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-panel {
    float: left;
    margin-left: 150px;
    width: calc(100% - 200px);
    min-width: 600px;
    border-radius: 0;
    position: relative;
    left: -1px;
}

.ui-tabs.ui-tabs-vertical .ui-tabs-panel .panel-title{
    padding: 0px;
    margin: 0px;
    margin-bottom: 10px;
    font-size: 22px;
}

In your HTML add something like this

<div id="myttabs" class="ui-tabs-vertical">
  <ul>
    <li><a href="#settings-panel">General</a></li>
    <li><a href="#foo-panel">Foo</a></li>
  </ul>
  <div id="settings-panel">
      <p>Here is some settings</p>
  </div>
  <div id="foo-panel">
      <p>Here is some foo</p>
  </div>
</div>

Overview

How it works. In the above HTML you will notice ui-tabs-vertical class. Then in our mytabs.js we do this:

 $('.ui-tabs-vertical').each(function(){  ... }

In short what this does is any element that has the ui-tabs-vertical class will get the ui-tabs added automagially. This is especially nice for wordpress as we can get into a real mess trying to put JS in a post (for example). So we want it as clean an free as possible. This trick with some variation can be used on any of the UI elements that create similar stuff, same type of popup, or anything we can normalize to a common format, so we don't have too many arguments.

Pass options -via- data attributes

One way to pass options to the JS, that I didn't need here is to simply put them in a data- attribute on the main element or any element that makes sense. For example you can set .tabs({hide:true}) to hide the tabs.

So if I wanted to do that I would do something like this:

 //in our HTML add the data attribute to the main element 
<div id="myttabs" class="ui-tabs-vertical" data-hide="true" >

//in myscript.js - change the options object.
    var element = $( "#"+id )

    var options = {
            hide: element.data('hide') | false,
            active: loadTabOrder(id),
            activate: function(event, ui) {
                window.saveTabOrder(id, ui.newTab.parent().children().index(ui.newTab));                
            }
        };

The active tag will be remembered by the users browser by making use of some simple Session Storage stuff in there. These are keyed off the ID of the main HTML element for the tabs. This makes that ID required, so there is a bit of code to issue an error to the console, for development purposes. Its important to use the tabs ID, because that way each tab will have it's own settings remembered. If we mixed them we would probably get some errors for missing tab indexes etc..

There are also some modifications to the vertical CSS to expand the area behind the Tabs. I probably spent the most time on this piece and its a relatively minor visual issue. But I cant have that in my work. This is actually quite tricky to do, as you will see below. It looks way better with the full width background.

You can see this issue even on the jQuery example page.

enter image description here

enter image description here

The way I fixed it was

  1. position:absolute on the navigation box with a top:0 and bottom:0, the parent element should be position:relative. This alone basally solves the 100% height issue, now we have to deal with the side effects of absolute positioning.
  2. A few tricks like this width: calc(100% - 200px); to dynamically get the width set up. Absolute elements are not part of the Box Model of the DOM, so it's very hard to account for them with just CSS as they don't hold any space in the container.
  3. Now all we need to do is set the min-height. The only reason we need to do this is everything goes janky if you have a lot of menu item (absolute) but no content in the tab (height is smaller then the nav). Which will bust it out of the bottom of the ui-tabs container because its absolute positioned. This is because with the top:0 and bottom:0 we are tying the width of the navigation menu to the main ui-tabs container. When the panel is empty that container will be shorter then the menu, which is a problem with many menu items and tiny panels. It can also cause some issues if you load content -via- AJAX, as you may see this error for second while the request goes. 4 So with the last bit of JS we just need to set min-height to apx the same height as the navigation's height. Because the navigation is absolute and tied to the parent container (as I said above, its height is dependent on .ui-tabs), so we can't simply get the height of that. The only option I saw was to sum the height of it's contents, the li elements themselves. This is a bit harder but we only need to do it one time for each ui-tabs.
  4. The absolute position stuff will dynamically adjust the height (with just CSS) if the tab height changes, such as loading content via AJAX or other dynamic stuff.
  5. The .ui-tabs-panel are set to float:left with a margin apx the width of the tab navigation. This accounts for the horizontal space the navigation takes up. Then to get something resembling a proper 100% width, we can use width: calc(100% - 200px); again because the nav is absolute we are sort of stuck manually offsetting for it. So This has 150px for the menus width offset, (or the left-margin on the panel, about the same width as the nav) and an extra 50 for things like the margin on the right and some other padding etc. We could have used negative margins for some of these (but I didn't think about that tell now)
  6. Now having the panel width dynamic and like a real 100% width, all we need to do to make the panel smaller is adjust the width of the container around the main UI-Tabs element. This way we can adjust it without sending any arguments to .tabs() or changing any thing with JS.

As I said that menu thing is a hard problem to solve, this is mainly due to the fact were limited in what we can do structure wise, or we will just break the ui-tabs. So we cant really change that, and that leave only JS and CSS. CSS is preferable because then we don't have to write yet more JS, and we would need to keep watch on the contents changing to resize it. Even then there would be some lag in the change. For example using an setInterval to keep an eye on it, this is something we want to avoid as it can affect performance too, and is more of a headache then the minor visual problem that this is.

Summery

I basically just pasted this from my own plugin, so I can't grantee that I covered everything. I cant stand little quirky things like the images above so I always fix that stuff. And I try to make my life easier later so now we just make the HTML and add the ui-tabs-vertical and mytabs.js takes care of the rest. Lastly we should never have to mess with mytabs.js and anytime we want a tab setup we just add the HTML with that class.

There is probably a tiny performance penalty to this (maybe) but in Wordpress it can be really hard to call JS from posts or other content in a "clean" way. So this just encapsulates all that code and make it a lot cleaner and easier to maintain IMO because, you are not mixing HTML and JS and CSS etc.

Hope it helps:

PS if the way I start my JS looks funny please see this question:

What advantages does using (function(window, document, undefined) { ... })(window, document) confer?

And this one:

How does this JavaScript/JQuery Syntax work: (function( window, undefined ) { })(window)?

Basically its a self executing function that keeps our global JS space clean, so we don't get any conflicts from other plugins, or scripts that may use the same variable names as we are.

I do a fair amount of plugin development, so its a bit more common to use it for that, but I just basically copy and paste it now, so... Also I feel I should mention this is part of a much larger script that dynamically adds a bunch of UI stuff for me. That way when I'm working on HTML, I can just work on HTML etc...

For the final result check this out:

;( function( $, window, document, undefined ) {
    "use strict";
    $( document ).ready( function() {
         var loadTabOrder = function(id){
            /*//  Define friendly data store name
            var dataStore = window.sessionStorage;
            var oldIndex = 0;
            //  Start magic!
            try {
                // getter: Fetch previous value
                oldIndex = dataStore.getItem(id);
            } catch(e) {}
            return oldIndex;*/
        };

        var saveTabOrder = function(id, currentIndex){
            /*//  Define friendly data store name
            var dataStore = window.sessionStorage;
            //  Start magic!
            try {
                dataStore.setItem( id, currentIndex );
            } catch(e) {}*/
        };

        $('.ui-tabs-vertical').each(function(){  
            var id = $(this).prop('id');
            if(!id) $.error('.ui-tabs-vertical requires an id');

            var element = $( "#"+id );

            var options = {
                active: loadTabOrder(id),
                activate: function(event, ui) {
                    saveTabOrder(id, ui.newTab.parent().children().index(ui.newTab));                
                }
            };

            element.tabs(options).addClass( "ui-helper-clearfix" );
            var nav = element.find('> .ui-tabs-nav > li');
            nav.removeClass( "ui-corner-top" ).addClass( "ui-corner-left" );

            var height = 0;
            nav.each(function(){
                height += $(this).outerHeight();
            });

            element.find('> .ui-tabs-panel').css(
                'min-height',
                height+'px'
            );

        }); 
        
        $('#expand').click(function(){
            $('#'+$( "#mytabs li.ui-tabs-active" ).attr('aria-controls')+' p').css({"height":'300px'});
         });
         
         $('#shrink').click(function(){
           $('#'+$( "#mytabs li.ui-tabs-active" ).attr('aria-controls')+' p').css({"height":''});
         });
        
        
    } );

 } ) ( jQuery, window, document );
.ui-tabs.ui-tabs-vertical {
    padding: 0;
    height: 100%;
    width: calc(100% - 15px);
    position: relative;
}
.ui-tabs.ui-tabs-vertical .ui-widget-header {
    border: none;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav {
    float: left;
    width: 10em;
    background: #EEE;
    border-radius: 4px 0 0 4px;
    border-right: 1px solid gray;
    position: absolute;
    top : 0;
    bottom: 0;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li {
    clear: left;
    width: 100%;
    margin: 0.2em 0;
    border: 1px solid gray;
    border-width: 1px 0 1px 1px;
    border-radius: 4px 0 0 4px;
    overflow: hidden;
    position: relative;
    right: -2px;
    z-index: 2;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a {
    display: block;
    width: 100%;
    padding: 0.6em 1em;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover {
    cursor: pointer;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
    margin-bottom: 0.2em;
    padding-bottom: 0;
    border-right: 1px solid white;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child {
    margin-bottom: 10px;
}
.ui-tabs.ui-tabs-vertical .ui-tabs-panel {
    float: left;
    margin-left: 150px;
    width: calc(100% - 200px);
    min-width: 600px;
    border-radius: 0;
    position: relative;
    left: -1px;
}

.ui-tabs.ui-tabs-vertical .ui-tabs-panel .panel-title{
    padding: 0px;
    margin: 0px;
    margin-bottom: 10px;
    font-size: 22px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" rel="stylesheet"/>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>

<div id="mytabs" class="ui-tabs-vertical">
  <ul>
    <li><a href="#settings-panel">General</a></li>
    <li><a href="#foo-panel">Foo</a></li>
  </ul>
  <div id="settings-panel">
      <p>Here is some settings</p>
  </div>
  <div id="foo-panel">
      <p>Here is some foo</p>
  </div>
</div>

<div style="margin-top: 20px">
  <button id="expand" >Click here to expand the panel</button>
  <button id="shrink" >Click here to shrink the panel</button>
</div>

The only notes here, is I added the buttons to showcase how the gray nav background resizes automatically and Stack Overflow wont let me use the sessionStorge here. So I had no choice but to comment it out.

Sense there is so much code, most of it is pretty simple stuff really, I didn't want it all in the snip-it windows, as its a bit harder to read there. So forgive the lengthy post, but I wanted it to all make sense.

Enjoy!

ArtisticPhoenix
  • 20,683
  • 2
  • 18
  • 34