JSON schema jQuery-ui horizontal menu

This is some code for building a jquery ui horizontal menu. It is based on code by https://codepen.io/seungjaeryanlee/ and modified for icon support and to create a menu automatically from a JSON schema. It’s pretty useful for HTML5 app development.

menu created from JSON
Menu created from JSON schema

HTML

This is how the menu would look be structured if just coded in html

<ul id="menubar">
  <li><div class="icon"><span class="ui-icon ui-icon-folder-open"></span><a href="#">Alpha</a></div>
     <ul>
      <li><div><a href="#">Beta 1</a></div></li>
      <li>
        <div class="icon"><span class="ui-icon ui-icon-folder-open"></span><a href="#">Beta 2</a></div>
        <ul>
          <li><div class="icon"><span class="ui-icon ui-icon-folder-open"></span><a href="#">Beta 2a</a></div></li>
          <li><div><a href="#">Beta 2b</a></div></li>
        </ul>
      </li>
      <li><div><a href="#">Beta 3</a></div></li>
    </ul>
  </li>
  <li>
    <div><a href="#">Beta</a></div>
    <ul>
      <li><div><a href="#">Beta 1</a></div></li>
      <li>
        <div><a href="#">Beta 2</a></div>
        <ul>
          <li><div><a href="#">Beta 2a</a></div></li>
          <li><div><a href="#">Beta 2b</a></div></li>
        </ul>
      </li>
      <li><div><a href="#">Beta 3</a></div></li>
    </ul>
  </li>
  <li><div><a href="#">Gamma</a></div></li>
  <li><div><a href="#">Delta</a></div></li>
 </ul>

javascript

menuStructure is the JSON menu descriptor, the code setUpMenuHTML and addMenuHTML create HTML from this schema in the format of the html above.

var menuStructure = {menu: [
                        { name: "file",  
                          menu: [
                              {name: "Open", icon: "ui-icon ui-icon-folder-open"}, 
                              {name: "save", icon: "ui-icon ui-icon-disk"}
                          ]
                         },
                        {name: "ImageProcessing", icon: "ui-icon ui-icon-image",
                         menu: [
                             {name: "Invert"}, 
                             {name: "threshold"}, 
                             {name: "binary", 
                              menu: [
                                    {name: "erode"}, 
                                    {name: "open"}, 
                                    {name: "close"}
                                    ]
                             }
                            ]
                        },
                        {name: "help", icon: "ui-icon ui-icon-help"}
                    ]};
    

function addMenuHTML(ME, $selector)
{
    var $ulOuter = $selector;
    
    if(!$selector.is('#menubar'))
        $ulOuter = $("
    ").appendTo($selector); for(var j=0;j").appendTo($ulOuter); if(ME.menu[j].icon) { str = '
    '+ME.menu[j].name+'
    '; } else{ str = '
    ' + ME.menu[j].name + '
    '; } $(str).appendTo($liInner); // call recursively on nested menu elements if(ME.menu[j].menu) addMenuHTML(ME.menu[j], $liInner); } } function setUpMenuHTML() { var $menu = $('#menubar'); $menu.empty(); addMenuHTML(menuStructure, $menu); } function setUpMenu() { $('#menubar').menu(); $('#menubar').menu({ position: { my: 'left top', at: 'left bottom' }, blur: function() { $(this).menu('option', 'position', { my: 'left top', at: 'left bottom' }); }, focus: function(e, ui) { if ($('#menubar').get(0) !== $(ui).get(0).item.parent().get(0)) { $(this).menu('option', 'position', { my: 'left top', at: 'right top' }); } }, }); } $(document).ready(function() { setUpMenuHTML(); setUpMenu(); });

    css

    the CSS ensures that the menuu is horizonal and that the icons are correctly displayed next to the menu names and that the sub menus also indent correctly

    #menubar {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
    }
    
    ul > li a{
      max-width:100%;
      color: inherit; /* blue colors for links too */
      text-decoration: inherit; /* no underline */
    }
    
    li > div {
      white-space: nowrap;
      overflow: hidden;
    }
    
    /* Make jQuery UI Menu into a horizontal menubar with vertical dropdown */
    #menubar > li { /* Menubar buttons */
      #text-align: center;
      display: inline-block;
    }
    
    #menubar li > div:not(.icon) {
      padding-left: 0.3em !important;
    }
    
    #menubar li > div.icon {
      padding-left: 1.5em;
    }
    
    #menubar > li > ul > li { /* Menubar buttons inside dropdown */
      display: block;
    }
    
    /* Change dropdown carets to correct direction */
    #menubar > li > div > span.ui-icon-caret-1-e {
      /* Caret on menubar */
      background:url(https://www.drupal.org/files/issues/ui-icons-222222-256x240.png) no-repeat -64px -16px !important;
    }
    #menubar ul li div span.ui-icon-caret-1-e {
      /* Caret on dropdowns */
      background:url(https://www.drupal.org/files/issues/ui-icons-222222-256x240.png) no-repeat -32px -16px !important;
    }

    how to use pdf.js to display pdf documents

    pdf.js is a great cross platform pdf viewer solution, here I explain how to use it

    Install PDF.js viewer on your server

    Instructions 1 to 7 are to install node as a webserver for the PDFViewer, they not necessary if you are already running a webserver (i.e. Apache).

    1) install git

    sudo yum install git

    2) make or use a pdf.js install directory on your server

    mkdir libs/ cd libs

    3) Now you have a server directory /home/user/public_html/libs, for example. Clone the git project into this directory

    git clone git://github.com/mozilla/pdf.js.git pdfjs

    4) there will be a new directory created called pdfjs which is the project directory, cd into this directory. Then we have to install the node server

    sudo yum install nodejs

    5) then run the server (in the background so we can carry on), to do this robustly I am using forever its runs the server in the background robustly, to install this we first have to install the node package manager (npm) then use npm to install forever

    sudo yum install npm;
    sudo npm install forever --global

    6) then we can start the pdf server

    forever start make.js server

    7) you can check that it is running with

    forever list

    8) then we can display the pdf with the following html code

    <iframe style="width:100%;height:500px" src="https://www.mydomain.com/libs/pdfjs/web/viewer.html?file=http://www.mydomain.com/mypdf.pdf"></iframe>

    You now have a nice pdf viewer for your website guests that doesn’t depend on any plugins.

    You can see the finished pdfs on the bottom of these webpages image analysis of crystals and steerable filters for detecting crystals

    Using PDF.js as a fallback for native pdf viewer plugin

    PDF.js is at the moment a bit buggy, (ie. printing support is not available – hopefully this will change in the future!).

    In order to provide the best experience for all users we shall: use the native pdf viewer plugin (i.e. adobe) and if not available use pdf.js as a fallback.

    9) Download pdfobject.min.js from the pdfobject Github site , save to lib directory

    10) Add the following code to the header region of your webpage (change the width, height in the style to suit)

    <script>
    var pdf_url="http://www.mydomain.com/mypdf.pdf";
    
      window.onload = function (){
            var myPDF = new PDFObject({ url: pdf_url }).embed("pdfdoc")
    
    if(!myPDF){
    document.getElementById('pdfdoc').innerHTML += '<iframe style="width:100%;height:500px" src="https://www.mydomain.com/libs/pdfjs/web/viewer.html?file='+pdf_url+'"></iframe>';
    }
          };

    11) Then in the body section of your html page replace the iframe html code (from section 8) with the following html code

    <div id="pdfdoc" style="width:100%;height:500px"></div>

    then you are good to go!

    * Code conversion to HTML friendly display format was done using the Code2HTML converter

    Javascript technique to center image in DIV for flexible webdesign

    First make sure the DrawCentered function is called after the image loads as below

    <div>
    <ul>
     <li>
          <img src="exampleimage.png" onload="DrawCentered(this);"/>
     </li>
    </ul>
    </div>

    Then add the resizing code below to your html file (for example: in document load function). The images will allways be centered within the container DIV, regardless of image size or page width.

    
        window.onresize = function() { 
                $( "li img" ).each(function( index ) {
                DrawCentered(this); 
           });
        }
    
        function DrawCentered(im)
        {
    	var gScaledHeight, gScaledWidth;
    
            var iWidth=im.width, iHeight=im.height; 
            var cWidth=$(im).closest("div").width(); 
            var cHeight=$(im).closest("div").height();
    
    	gScaledWidth = iWidth*(cHeight/iHeight);
    	
    	// see which is the image's biggest dimension
    	if( cWidth > gScaledWidth ) //scale cHeight
    	{
    		// ratio of new to old cWidth
    		gScale = gScaledWidth/iWidth;
    		
    		gScaledHeight = gScale*iHeight;
    		
    		gOffY = 0;
    		gOffX = (cWidth-gScaledWidth)/2.0
    	}
    	else
    	{
    		gScaledHeight = iHeight*(cWidth/iWidth);
    		
    		gScale = gScaledHeight/iHeight;
    		
    		gScaledWidth = gScale*iWidth;
    	
    		gOffX = 0;
    		gOffY = (cHeight-gScaledHeight)/2.0;
    	}
        
    	$(im).css("width",gScaledWidth);
            $(im).css("height",gScaledHeight);
            $(im).css("padding-top",gOffY+"px");
            $(im).css("padding-left",gOffX+"px");
        }