JSFiddle - React, Tailwind, and code Playground

by brandonzylstra

HTML

<body>
  <div class="container">
    <h2>Merchandising Class Structure</h2>
    <div id="columns"></div>
  </div>

  <script>
    $(document).ready(function() {
      var merchandising_class_structure = {
        "a0": [
          { id: "a1", label: "Department Group 1", type: "folder" },
          { id: "2", label: "Department Group 2", type: "folder", url: "http://www.google.com"}
        ],

        "a1": [
          { id: "11", label: "Department 1", type: "folder" },
          { id: 12, label: "Department 2", type: "folder" }
        ],

        "11": [
          { id: "111", label: "Merchandise Group 1", type: "folder" },
          { id: 112, label: "Merchandise Group 2", type: "folder" },
          { id: 113, label: "Merchandise Group 3", type:"folder", url: "http://google.com/" }
        ],

        12: [
          // empty node
        ],

        "111": [
          { id: 1111, label: "Merchandise Category 1", type: "folder" },
          { id: 1112, label: "Merchandise Category 2", type: "folder" }
        ],

        112: [
          { id: 1121, label: "Merchandise Category", type: "link", url: "http://google.com/" }
        ],

        1111: [
          { id: 11111, label: "Merchandise Class 1", type: "link", url: "https://google.com" },
          { id: 11111, label: "Merchandise Class 2", type: "link", url: "https://google.com" }
        ],

      };


      var root_node = "a0";
      $("#columns").hColumns({
        nodeSource: function(node_id, callback) {
          if(node_id === null) {
            node_id = root_node;
          }

          if( !(node_id in merchandising_class_structure) ) {
            // TODO: we probably need to modify this to load new data via AJAX
            // if it's not already in the merchandising_class_structure, and
            // then display this only if we can't load it dynamically
            return callback("This node does not exist");
          }

          return callback(null,...

CSS

/* column view container */
.column-view-container {
	width: 920px /* 100% */;
	height: 500px;
	padding: 0;
	border: 1px solid #ccc;
	background: #FFF;
	display: block;
	overflow-x: auto;
	overflow-y: hidden;
}

/* the composition div for colums */
.column-view-composition {
	display: table;
	white-space: nowrap;
}

/**/
.column {
	display: table-cell;
	border-right: 1px solid #999;
}

.column:last-child {
	border-right: 0;
}

.column:only-child {
	border-right: 1px solid #999;
}

/* for error messages */
.column > p {
	margin: 10px;
	color: #777;
}

/* for column listing */
.column ul {
	margin: 0;
	padding: 0;
	height: 500px;
	width: 183px;
	overflow-y: auto;
	list-style: none;
}

.column ul li {
	position: relative;
	margin: 0;
	padding: 10px 20px 10px 10px;
	overflow: hidden;
	-o-text-overflow: ellipsis;
	text-overflow: ellipsis;
}

.column ul li:hover {
	cursor: pointer;
}

.column ul li i {
	position: absolute;
	top: 9px;
	right: 5px;
}

.column ul li:hover, .column ul li.active {
	background: #999999;
	color: #FFFFFF;
}

.column ul li:hover a, .column ul li.active a {
	color: #FFFFFF;
}

.column ul li.search {
	margin: 0;
	padding: 5px;
}

.column ul li.search input {
	width: 100%;
	margin: 0;
}


/* we could replace the icons with FontAwesome if we want */
[class^="icon-"], [class*=" icon-"] {
	display: inline-block;
	width: 14px;
	height: 14px;
	margin-top: 1px;
	*margin-right: .3em;
	line-height: 14px;
	vertical-align: text-top;
	background-image: url("../img/glyphicons-halflings.png");
	background-position: 14px 14px;
	background-repeat: no-repeat;
}




body {
    background: #cccccc;
}
*, input, body {
    font-family: "Helvetia Neue", "Lucida Grande", sans-serif;
    font-size: 1.05em;
}

.container {
    padding: 1.5em;
}

h1 {
    color: #000;
    font-size: 2em;

    margin: 0.75em 0;
}

h1 small {
    color: #ccc;
    font-size: 0.5em;
}

img {
    margin: 20px;
}

h2 {
    margin: 1em 0;

    font-size: 1.25em;
    color: #ffffff;
}

ol {
   ...

JavaScript

// hColumns by bu <[email protected]>, BSD License
// some modifications made for debugging

function isEllipsisActive(e) {
  return (e.offsetWidth < e.scrollWidth);
}
function isEllipsisActiveJQ($jQueryObject) {
  return ($jQueryObject.width() < $jQueryObject[0].scrollWidth);
}
function debug(message) {
  alert(message);
}


(function($) {
  var defaultConfig = {
    nodeSource: function() {
      return window.alert("dummy source, you need to create a node source");
    },

    noContentString: "There is no node here",
    searchPlaceholderString: "Search...",

    searchable: false,

    customNodeTypeIndicator: {},
    customNodeTypeHandler: {}
  };

  var defaultHandler = {
    folder: function(hColumn, node, data) {
      hColumn.nodeSource( data.id, function(err, data) {
        if(err) {
          return $.error(err);
        }

        return hColumn.columnView._addColumnList(data, hColumn.columnView);
      });
    },

    link: function(hColumn, node, data) {
      return window.open( data.url );
    }
  };

  var defaultIndicator = {
    folder: "icon-chevron-right",
    link: "icon-globe"
  };

  var methods = {
    init: function(options) {
      // extend the original default value with user input
      var settings = $.extend(defaultConfig , options);
      var handlers = $.extend(defaultHandler, settings.customNodeTypeHandler);
      var indicators = $.extend(defaultIndicator, settings.customNodeTypeIndicator);

      // return methods to the chain
      return this.each(function(){
        var self = $(this),
          data = self.data("columnView");

        // bind settings to columnview
        methods.settings = settings;

        // bind columnview and handler to the setings
        settings.columnView = methods;
        settings.handlers = handlers;
        settings.indicators = indicators;

        settings.container_node = this;

        // if this new html node is not activated hColumn
        if (!data) {
          // we assign column view to...