Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/delibero.git

Greatly simplified Miller Columns algorithm. Fixed numerous bugs.

Author Dave Jarvis <email>
Date 2014-12-29 01:54:32 GMT-0800
Commit 58b21e8769642f8dd7c52afc4b7f468158d696a8
Parent 772f4d5
Delta 131 lines added, 270 lines removed, 139-line decrease
xml/css/tags.css
+@charset "utf-8";
@import url( "css/support.css" );
-/* ***********************************************************************
+/**
*
- * Sets up the tag editor code.
+ * Cascading columns styling.
*
- * ***********************************************************************/
-div.breadcrumb {
- margin-top: 1em;
- border-top-left-radius: 0.4em 0.4em;
- border-top-right-radius: 0.4em 0.4em;
-}
-
-div.toolbar {
- margin-bottom: 1em;
- border-bottom-left-radius: 0.4em 0.4em;
- border-bottom-right-radius: 0.4em 0.4em;
-}
-
+ */
div.columns {
float: left;
}
-div.column {
+/* Display the lists as columns in blocks. */
+ul.column {
+ display: inline-block;
+
vertical-align: top;
overflow: hidden;
- display: inline-block;
+ margin: 0 auto;
+
border-right: 1px solid #666;
- font-size: 0.9em;
- font-family: Arial;
background-color: white;
-
white-space: normal;
+
+ font-size: 0.9em;
}
-div.collapsed {
+/* Setting a list container class to "collapsed" will hide the column. */
+ul.column.collapsed {
display: none;
}
-li.parent:hover {
- color: black;
- background-color: #DDE4E8;
+/* Put some space between the column's list entries. */
+ul.column > li {
+ list-style: none;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ padding-top: 0.25em;
+ padding-bottom: 0.25em;
+
+ min-width: 200px;
}
-/* Ensure the selection hierarchy is highlighted. */
-li.selection {
- background-color: #08C !important;
- color: white !important;
+ul.column > li.parent::after {
+ content: "▶";
+ float: right;
}
-div.breadcrumb, div.toolbar {
- height: 1.25em;
+/* Zebra stripes, which can be overridden. */
+ul.column > li:nth-child(odd) {
+ background-color: #EEE;
}
-div.breadcrumb, div.toolbar {
- background: linear-gradient(#f0f0f0, #d8d8d8);
+/* Highlight while hovering, without allowing selected items to override. */
+ul.column > li:hover {
+ color: black;
+ background-color: #DDE4E8;
+}
+
+/* Ensure all selected nodes in the hierarchy are easily seen. */
+ul.column > li.selection {
+ background-color: #08C;
+ color: white;
}
+/**
+ *
+ * Breadcrumb styling.
+ *
+ */
div.breadcrumb {
+ margin-top: 1em;
+ border-top-left-radius: 0.4em 0.4em;
+ border-top-right-radius: 0.4em 0.4em;
+
border-bottom: 1px solid #666;
}
div.breadcrumb > span {
height: 1.25em;
line-height: 1.25em;
-}
-
-div.toolbar {
- clear: both;
- border-top: 1px solid #666;
-}
-div.breadcrumb > span {
font-size: 0.7em;
font-weight: bold;
padding-left: 0.25em;
color: #666;
}
div.breadcrumb > span::after {
- content: " \25B8";
+ content: " ▸";
}
div.breadcrumb > span:first-child {
padding-left: 1em;
}
div.breadcrumb > span:last-child:after {
content: "";
-}
-
-ul {
- padding: 0;
- margin: 0;
- overflow: auto;
-}
-
-li {
- list-style: none;
- padding-left: 0.5em;
- padding-right: 0.5em;
- padding-top: 0.25em;
- padding-bottom: 0.25em;
- min-width: 150px;
}
-/* Use an arrow to indicate that the parent has child elements. */
-li.parent:after {
- content: "\25B8";
- float: right;
-}
+/**
+ *
+ * Toolbar styling.
+ *
+ */
+div.toolbar {
+ margin-bottom: 1em;
+ border-bottom-left-radius: 0.4em 0.4em;
+ border-bottom-right-radius: 0.4em 0.4em;
-/* Zebra stripes. */
-li:nth-child(odd) {
- background-color: #EEE;
+ clear: both;
+ border-top: 1px solid #666;
}
}
-/* ***********************************************************************
+/**
*
- * Sets up the remainder of the web page.
+ * Breadcrumb and toolbar styling.
*
- * ***********************************************************************/
-h1 {
- font-size: 1.5em;
- padding-bottom: 0.5em;
+ */
+div.breadcrumb, div.toolbar {
+ height: 1.25em;
+ background: linear-gradient(#f0f0f0, #d8d8d8);
}
xml/js/tags.js
-/* ***************************************************************************
- *
- * Miller Columns
- *
- * Transforms an arbitrarily nested unordered list into a series of
- * Miller Columns. The purpose of Miller Columns is to provide a
- * straightforward means to edit hierarchical data. In theory, the
- * same data set could be displayed as a collapsable tree.
- *
- * List items are employed for semantic reasons.
- *
- * The id's must be unique. Usage example:
- *
- * <div class="columns">
- * <ul>
- * <li id="1">Item A</li>
- * <li id="2">Item B</li>
- * <li id="3">Item C
- * <ul>
- * <li id="31">Item CA</li>
- * <li id="32">Item CB</li>
- * <li id="33">Item CC
- * <ul>
- * <li id="331">Item CCA</li>
- * <li id="332">Item CCB</li>
- * <li id="333">Item CCC</li>
- * </ul>
- * </li>
- * <li id="34">Item CD</li>
- * <li id="35">Item CE</li>
- * </ul>
- * </li>
- * </ul>
- * </div>
- *
- * Requirements
- * - jQuery 1.11.1
- * - tags.css
- *
- * ***************************************************************************/
(function( $ ) {
$.fn.millerColumns = function() {
- var $list = $(this).first();
- var $columns = $(this);
+ return this.each( function() {
+ $(this).before( $("<div>").addClass( "breadcrumb" ) );
+ $(this).after( $("<div>").addClass( "toolbar" ) );
+ unnest( $(this) );
+ collapse();
- // Breadth-first traversal to rearrange list items into
- // consecutively ordered div wrapper elements.
- while( ($list = $list.children()).length ) {
- $list.each( function( index, element ) {
- var $parent = $(element).parent();
+ // Expand the requested child node on click.
+ $(this).find( "li" ).on( "click", function() {
+ collapse();
+ $(this).addClass( "selection" ).siblings().removeClass( "selection" );
- if( $(element).is( "li" ) ) {
- $parent = $parent.parent();
+ var $descendant = $(this).data( "descendants" );
+
+ if( $descendant !== undefined ) {
+ $descendant.removeClass( "collapsed" );
+ $descendant.children().removeClass( "selection" );
}
- // Store the parent id for showing child columns.
- var id = $parent.attr( "id" );
+ var $ancestor = $(this);
- if( $(element).is( "ul" ) ) {
- // The parent element shall be marked as 0.
- if( id === undefined ) {
- id = 0;
- }
+ // Reveal (uncollapse) all ancestors to the clicked item.
+ while( $ancestor !== undefined ) {
+ $ancestor.parent().removeClass( "collapsed" );
+ $ancestor = $ancestor.data( "ancestor" );
+ }
- var $item = $("li#" + id);
- $item.addClass( "parent" );
+ breadcrumb();
- $item.on( "click", function() {
- // Hide everything.
- $("div.column[data-parent!=0]").addClass( "collapsed" );
- $("li").removeClass( "selection" );
+ // Ensure the viewport shows the entire newly expanded item.
+ $column.parent().parent().animate(
+ { scrollLeft: $column.offset().left },
+ 500 );
+ });
+ });
+ }
- // The "id" for the clicked list item becomes the start of
- // the ancestral chain.
- var $child = $("div.column[data-parent=" + id + "]" );
- $child.removeClass( "collapsed" );
+ function breadcrumb() {
+ var $breadcrumb = $("div.breadcrumb").empty();
- var $li = $("li.parent[id=" + id + "]");
- var $ancestor = $li.parent().parent();
- var ancestor_id = $ancestor.attr( "data-parent" );
+ // Add the breadcrumb trail.
+ $("li.selection").each( function( _, crumb ) {
+ $breadcrumb.append( "<span>" + $(crumb).text() + "</span>" );
+ });
+ }
- while( ancestor_id !== undefined ) {
- $li.addClass( "selection" );
- $ancestor.removeClass( "collapsed" );
+ /* Convert nested lists into columns using breadth-first traversal. */
+ function unnest( $columns ) {
+ var queue = [];
- $li = $("li.parent[id=" + ancestor_id + "]");
- $ancestor = $li.parent().parent();
- ancestor_id = $ancestor.attr( "data-parent" );
- }
+ // Push the root unordered list item into the queue.
+ queue.push( $columns.children() );
- var $breadcrumb = $("div.breadcrumb").empty();
+ while( queue.length ) {
+ var $node = queue.shift();
- // Add the breadcrumb trail.
- $("li.selection").each( function( _, crumb ) {
- $breadcrumb.append( "<span>" + $(crumb).text() + "</span>" );
- });
- });
-
- var $div = $("<div>").attr( "data-parent", id );
- var $wrapped = $(element).wrapAll( $div );
+ $node.children().each( function( _, el ) {
+ var $descendants = $(this).children();
+ var $ancestor = $(this).parent().parent();
- // Unnest the list items into contiguous div elements.
- $wrapped.parent().detach().appendTo( $columns ).addClass( "column" );
+ // Retain item hierarchy (because it is lost after flattening).
+ if( $ancestor.length && ($(this).data( "ancestor" ) === undefined) ) {
+ $(this).siblings().addBack().data( "ancestor", $ancestor );
}
- });
- }
-
- // When the user clicks an item, select it.
- $(this).find( "li" ).on( "click", function() {
- $(this).addClass( "selection" );
- });
- $columns.before( $("<div>").addClass( "breadcrumb" ) );
- $columns.after( $("<div>").addClass( "toolbar" ) );
+ if( $descendants.length > 0 ) {
+ queue.push( $descendants );
+ $(this).data( "descendants", $descendants );
+ $(this).addClass( "parent" );
+ }
- // Hide all the columns except the root.
- $("div.column[data-parent!=0]").addClass( "collapsed" );
+ // Causes item siblings to have a flattened DOM lineage.
+ $(this).parent().detach().appendTo( $columns ).addClass( "column" );
+ });
+ }
+ }
- return this;
- };
+ /** Hide all the columns and deselect selected items. */
+ function collapse() {
+ $(".column:gt(0)").addClass( "collapsed" );
+ }
+})(jQuery);
- $("div.columns").millerColumns();
-}(jQuery));
+$(document).ready( function() { $("div.columns").millerColumns(); });
xml/tags.css
-div.columns {
- float: left;
- width: 100%;
- height: 200px;
- overflow-x: auto;
- overflow-y: hidden;
- white-space: nowrap;
-
- background-color: #949494;
-}
-
-ul.column {
- display: inline-block;
- float: left;
- padding: 0;
- margin: 0;
-
- vertical-align: top;
- overflow: hidden;
- border-right: 1px solid #666;
- font-size: 0.9em;
- font-family: Arial;
- background-color: white;
-
- white-space: normal;
-}
-
-ul.column.collapsed {
- display: none;
-}
-
-ul.column > li {
- list-style: none;
- padding-left: 0.5em;
- padding-right: 0.5em;
- padding-top: 0.25em;
- padding-bottom: 0.25em;
-}
-
-/* Zebra stripes. */
-ul.column > li:nth-child(odd) {
- background-color: #EEE;
-}
-
-ul.column > li:hover {
- color: black;
- background-color: #DDE4E8;
-}
-
-/* Ensure the selection hierarchy is highlighted. */
-ul.column > li.selection {
- background-color: #08C;
- color: white;
-}
-
xml/tags.js
-(function( $ ) {
- $.fn.millerColumns = function() {
- return this.each( function() {
- unnest( $(this) );
-
- // Expand child node on click.
- $(this).find( "li" ).on( "click", function() {
-
- // In the end, there can only be one selected item per column.
- $(this).addClass( "selection" );
- $(this).siblings().removeClass( "selection" );
- });
- });
- }
-
- /**
- *
- */
- function unnest( column_container ) {
- var queue = [];
- var $columns = column_container;
-
- queue.push( $columns.children( "ul" ) );
-
- while( queue.length > 0 ) {
- var $child = queue.shift();
-
- $child.children( "li" ).each( function( _, el ) {
- var $children = $(this).children( "ul" );
-
- if( $children.length > 0 ) {
- queue.push( $children );
- $(this).addClass( "parent" );
- }
-
- $(this).parent().detach().appendTo( $columns ).addClass( "column" );
- });
- }
-
- // Hide all but the first column.
- $(".column:gt(0)").addClass( "collapsed" );
- }
-})(jQuery);
xml/tags.xsl
</p>
</div>
- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
</xsl:template>