Library for browser based outliner
http://stackoverflow.com/q/257188/154877
by Marcel
HTML
<script src="http://mjsarfatti.com/sandbox/nestedSortable/jquery.mjs.nestedSortable.js"></script>
<div id="wrap">
<header>
<h1>Nested Editable Sortables with jQuery</h1>
</header>
<section>
<p>While a field is focused, press <kbd>↑</kbd> to collapse it's children and <kbd>↓</kbd> to expand them, or double-click the field to toggle. Use <kbd>Tab</kbd> and <kbd>Shift+Tab</kbd> to move between fields and <kbd>Return</kbd> to tick/untick an item.</p>
<ol id="outline"></ol>
<div class="btns">
<button class="add">Add item</button>
<button class="sve">Save List</button>
</div>
<pre id="output"></pre>
</section>
<footer>This is a code example for the Stack Overflow question <br><a href="http://stackoverflow.com/q/257188/154877">"Library for browser based outliner"</a></footer>
</div>
CSS
body { color:#222; background:#fafafa; font:13px/1.4 'segoe ui', sans-serif; }
h1, h2 { margin:0 0 .75em; font:700 2.2em/1 'myriad pro', sans-serif; } h2 { color:#999; margin: 1em 0 .25em; font-size:1.6em; }
a { color:#06c; transition:.2s linear; -webkit-transition:.2s linear; } a:hover { color:#39f; }
p { margin:1em 0; } footer { color:#999; margin:3em 0 0; text-align:center; } footer a { color:#777; }
kbd { color:#096; }
#wrap { width:500px; margin:1em auto; padding:1.5em; background:#fff; box-shadow:0 1em 2em rgba(0,0,0,.2); }
.btns { margin:.5em 1em; }
#outline, #outline ol { margin:0 0 0 2em; list-style-type:none; }
#outline { margin:.5em 0; }
#outline li { padding:0; margin:.5em 0 0 0; }
#outline li div { margin:0; padding:.25em; position:relative; border:1px solid #aaa; }
#outline li div .drg { cursor:move; padding:1px; margin:0 .5em 0 0; border-left:2px dotted #bbb; border-right:2px dotted #bbb; }
#outline li div input.txt { border:0; outline:0; width:90%; background:transparent; }
#outline li div input.chk { top:1px; margin:0 .2em; position:relative; }
#outline li div input.chk:checked + input.txt { color:#999; text-decoration:line-through; }
#outline li div a.del { color:#ccc; top:-5px; right:5px; cursor:pointer; font-size:20px; position:absolute; text-decoration:none; }
#outline li div a.del:hover { color:#c33; }
#outline li.rem > div { border:1px solid #000; }
.placeholder { background:#eee; }
.nesttoodeep { background:#ffdedd; }
JavaScript
$('#outline').nestedSortable({
revert:250,
tabSize:25,
opacity:.6,
maxLevels:5,
items:'li',
handle:'div .drg',
tolerance:'pointer',
toleranceElement:'> div',
errorClass:'nesttoodeep',
disableNesting:'no-nest',
placeholder:'placeholder',
forcePlaceholderSize:true
});
$('button.add').click(function() {
$('ol#outline').append('<li><div><b class="drg"></b> <input class="chk" type="checkbox" tabindex="-1"> <input class="txt" placeholder="New item"> <a class="del">×</a></div></li>');
});
$('button.sve').click(function() {
alert('TODO: Properly formatted output would help.');
});
$('#outline')
.delegate('a.del', 'click', function() {
if (confirm("This item and all of it's children will be deleted. Is that OK?")){
$(this).closest('li').slideUp('slow', function(){ $(this).remove(); });
}
})
.delegate('input', 'dblclick', function(){
$(this).closest('li').toggleClass('rem').find('ol').first().slideToggle();
})
.delegate('input', 'keydown', function(e) {
var keyCode = e.keyCode || e.which,
kbkey = { up: 38, down: 40, right: 39, left: 37, enter: 13 };
switch (keyCode) {
case kbkey.up:
$(this).closest('li').addClass('rem').find('ol').first().slideUp();
break;
case kbkey.down:
$(this).closest('li').removeClass('rem').find('ol').first().slideDown();
break;
case kbkey.right:
alert('TODO: Indent item (maybe)');
break;
case kbkey.left:
alert('TODO: Un-indent item (maybe)');
break;
case kbkey.enter:
$(this).prev().attr('checked', !$(this).prev().attr('checked'));
break;
}
});