UNPKG

jquery.fancytree

Version:

jQuery tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag'n'drop, and lazy loading

401 lines (377 loc) 11.3 kB
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> <title>Multiple Extensions - Fancytree</title> <link href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"> <script src="//code.jquery.com/jquery-3.2.1.min.js"></script> <script src="//code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <!-- jquery-contextmenu (https://github.com/mar10/jquery-ui-contextmenu/) --> <script src="//cdn.jsdelivr.net/jquery.ui-contextmenu/1/jquery.ui-contextmenu.min.js"></script> <link href="../src/skin-win8/ui.fancytree.css" rel="stylesheet"> <script src="../src/jquery.fancytree.js"></script> <script src="../src/jquery.fancytree.dnd.js"></script> <script src="../src/jquery.fancytree.edit.js"></script> <script src="../src/jquery.fancytree.gridnav.js"></script> <script src="../src/jquery.fancytree.table.js"></script> <!-- <script src="../../build/jquery.fancytree-all.min.js"></script> --> <!-- Start_Exclude: This block is not part of the sample code --> <link href="../lib/prettify.css" rel="stylesheet"> <script src="../lib/prettify.js"></script> <link href="../demo/sample.css" rel="stylesheet"> <script src="../demo/sample.js"></script> <!-- End_Exclude --> <style type="text/css"> .ui-menu { width: 180px; font-size: 63%; } .ui-menu kbd { /* Keyboard shortcuts for ui-contextmenu titles */ float: right; } /* custom alignment (set by 'renderColumns'' event) */ td.alignRight { text-align: right; } td.alignCenter { text-align: center; } td input[type=input] { width: 40px; } </style> <script type="text/javascript"> var CLIPBOARD = null; /* SOURCE = [ {title: "node 1", folder: true, expanded: true, children: [ {title: "node 1.1", foo: "a"}, {title: "node 1.2", foo: "b"} ]}, {title: "node 2", folder: true, expanded: false, children: [ {title: "node 2.1", foo: "c"}, {title: "node 2.2", foo: "d"} ]} ]; */ $(function(){ $("#tree").fancytree({ checkbox: true, titlesTabbable: true, // Add all node titles to TAB chain quicksearch: true, // Jump to nodes when pressing first character // source: SOURCE, source: { url: "ajax-tree-products.json"}, extensions: ["edit", "dnd", "table", "gridnav"], dnd: { preventVoidMoves: true, preventRecursiveMoves: true, autoExpandMS: 400, dragStart: function(node, data) { return true; }, dragEnter: function(node, data) { // return ["before", "after"]; return true; }, dragDrop: function(node, data) { data.otherNode.moveTo(node, data.hitMode); } }, edit: { triggerStart: ["f2", "shift+click", "mac+enter"], close: function(event, data) { if( data.save && data.isNew ){ // Quick-enter: add new nodes until we hit [enter] on an empty title $("#tree").trigger("nodeCommand", {cmd: "addSibling"}); } } }, table: { indentation: 20, nodeColumnIdx: 2, checkboxColumnIdx: 0 }, gridnav: { autofocusInput: false, handleCursorKeys: true }, lazyLoad: function(event, data) { data.result = {url: "../demo/ajax-sub2.json"}; }, createNode: function(event, data) { var node = data.node, $tdList = $(node.tr).find(">td"); // Span the remaining columns if it's a folder. // We can do this in createNode instead of renderColumns, because // the `isFolder` status is unlikely to change later if( node.isFolder() ) { $tdList.eq(2) .prop("colspan", 6) .nextAll().remove(); } }, renderColumns: function(event, data) { var node = data.node, $tdList = $(node.tr).find(">td"); // (Index #0 is rendered by fancytree by adding the checkbox) // Set column #1 info from node data: $tdList.eq(1).text(node.getIndexHier()); // (Index #2 is rendered by fancytree) // Set column #3 info from node data: $tdList.eq(3).find("input").val(node.key); $tdList.eq(4).find("input").val(node.data.foo); // Static markup (more efficiently defined as html row template): // $tdList.eq(3).html("<input type='input' value='" + "" + "'>"); // ... } }).on("nodeCommand", function(event, data){ // Custom event handler that is triggered by keydown-handler and // context menu: var refNode, moveMode, tree = $(this).fancytree("getTree"), node = tree.getActiveNode(); switch( data.cmd ) { case "moveUp": refNode = node.getPrevSibling(); if( refNode ) { node.moveTo(refNode, "before"); node.setActive(); } break; case "moveDown": refNode = node.getNextSibling(); if( refNode ) { node.moveTo(refNode, "after"); node.setActive(); } break; case "indent": refNode = node.getPrevSibling(); if( refNode ) { node.moveTo(refNode, "child"); refNode.setExpanded(); node.setActive(); } break; case "outdent": if( !node.isTopLevel() ) { node.moveTo(node.getParent(), "after"); node.setActive(); } break; case "rename": node.editStart(); break; case "remove": refNode = node.getNextSibling() || node.getPrevSibling() || node.getParent(); node.remove(); if( refNode ) { refNode.setActive(); } break; case "addChild": node.editCreateNode("child", ""); break; case "addSibling": node.editCreateNode("after", ""); break; case "cut": CLIPBOARD = {mode: data.cmd, data: node}; break; case "copy": CLIPBOARD = { mode: data.cmd, data: node.toDict(function(n){ delete n.key; }) }; break; case "clear": CLIPBOARD = null; break; case "paste": if( CLIPBOARD.mode === "cut" ) { // refNode = node.getPrevSibling(); CLIPBOARD.data.moveTo(node, "child"); CLIPBOARD.data.setActive(); } else if( CLIPBOARD.mode === "copy" ) { node.addChildren(CLIPBOARD.data).setActive(); } break; default: alert("Unhandled command: " + data.cmd); return; } // }).on("click dblclick", function(e){ // console.log( e, $.ui.fancytree.eventToString(e) ); }).on("keydown", function(e){ var cmd = null; // console.log(e.type, $.ui.fancytree.eventToString(e)); switch( $.ui.fancytree.eventToString(e) ) { case "ctrl+shift+n": case "meta+shift+n": // mac: cmd+shift+n cmd = "addChild"; break; case "ctrl+c": case "meta+c": // mac cmd = "copy"; break; case "ctrl+v": case "meta+v": // mac cmd = "paste"; break; case "ctrl+x": case "meta+x": // mac cmd = "cut"; break; case "ctrl+n": case "meta+n": // mac cmd = "addSibling"; break; case "del": case "meta+backspace": // mac cmd = "remove"; break; // case "f2": // already triggered by ext-edit pluging // cmd = "rename"; // break; case "ctrl+up": cmd = "moveUp"; break; case "ctrl+down": cmd = "moveDown"; break; case "ctrl+right": case "ctrl+shift+right": // mac cmd = "indent"; break; case "ctrl+left": case "ctrl+shift+left": // mac cmd = "outdent"; } if( cmd ){ $(this).trigger("nodeCommand", {cmd: cmd}); // e.preventDefault(); // e.stopPropagation(); return false; } }); /* * Tooltips */ // $("#tree").tooltip({ // content: function () { // return $(this).attr("title"); // } // }); /* * Context menu (https://github.com/mar10/jquery-ui-contextmenu) */ $("#tree").contextmenu({ delegate: "span.fancytree-node", menu: [ {title: "Edit <kbd>[F2]</kbd>", cmd: "rename", uiIcon: "ui-icon-pencil" }, {title: "Delete <kbd>[Del]</kbd>", cmd: "remove", uiIcon: "ui-icon-trash" }, {title: "----"}, {title: "New sibling <kbd>[Ctrl+N]</kbd>", cmd: "addSibling", uiIcon: "ui-icon-plus" }, {title: "New child <kbd>[Ctrl+Shift+N]</kbd>", cmd: "addChild", uiIcon: "ui-icon-arrowreturn-1-e" }, {title: "----"}, {title: "Cut <kbd>Ctrl+X</kbd>", cmd: "cut", uiIcon: "ui-icon-scissors"}, {title: "Copy <kbd>Ctrl-C</kbd>", cmd: "copy", uiIcon: "ui-icon-copy"}, {title: "Paste as child<kbd>Ctrl+V</kbd>", cmd: "paste", uiIcon: "ui-icon-clipboard", disabled: true } ], beforeOpen: function(event, ui) { var node = $.ui.fancytree.getNode(ui.target); $("#tree").contextmenu("enableEntry", "paste", !!CLIPBOARD); node.setActive(); }, select: function(event, ui) { var that = this; // delay the event, so the menu can close and the click event does // not interfere with the edit control setTimeout(function(){ $(that).trigger("nodeCommand", {cmd: ui.cmd}); }, 100); } }); }); </script> </head> <body class="example"> <h1>Example: tree grid with keyboard navigation, DnD, and editing capabilites </h1> <div class="description"> Bringing it all together: this sample combines different extensions and custom events to implement an editable tree grid: <ul> <li>'ext-dnd' to re-order nodes using drag-and-drop.</li> <li>'ext-table' + 'ext-gridnav' to implement a tree grid.<br> Try <kbd>UP / DOWN / LEFT / RIGHT</kbd>, <kbd>TAB</kbd>, <kbd>Shift+TAB</kbd> to navigate between grid cells. Note that embedded input controls remain functional. </li> <li>'ext-edit': inline editing.<br> Try <kbd>F2</kbd> to rename a node.<br> <kbd>Ctrl+N</kbd>, <kbd>Ctrl+Shift+N</kbd> to add nodes (Quick-enter: add new nodes until [enter] is hit on an empty title). </li> <li>Extended keyboard shortcuts:<br> <kbd>Ctrl+C</kbd>, <kbd>Ctrl+X</kbd>, <kbd>Ctrl+P</kbd> for copy/paste,<br> <kbd>Ctrl+UP</kbd>, <kbd>Ctrl+DOWN</kbd>, <kbd>Ctrl+LEFT</kbd>, <kbd>Ctrl+RIGHT</kbd> to move nodes around and change indentation. </li> <li>3rd-party <a href="https://github.com/mar10/jquery-ui-contextmenu">contextmenu</a> for additional edit commands</li> </ul> </div> <div> <label for="skinswitcher">Skin:</label> <select id="skinswitcher"></select> </div> <h1>Table Tree</h1> <div> <label>Fake input:<input id="input1"/></label> </div> <table id="tree"> <colgroup> <col width="30px"> <col width="50px"> <col width="350px"> <col width="50px"> <col width="50px"> <col width="30px"> <col width="30px"> <col width="50px"> </colgroup> <thead> <tr> <th></th> <th>#</th> <th></th> <th>Ed1</th> <th>Ed2</th> <th>Rb1</th> <th>Rb2</th> <th>Cb</th></tr> </thead> <tbody> <!-- Define a row template for all invariant markup: --> <tr> <td class="alignCenter"></td> <td></td> <td></td> <td><input name="input1" type="input"></td> <td><input name="input2" type="input"></td> <td class="alignCenter"><input name="cb1" type="checkbox"></td> <td class="alignCenter"><input name="cb2" type="checkbox"></td> <td> <select name="sel1" id=""> <option value="a">A</option> <option value="b">B</option> </select> </td> </tr> </tbody> </table> <!-- Start_Exclude: This block is not part of the sample code --> <hr> <p class="sample-links no_code"> <a class="hideInsideFS" href="https://github.com/mar10/fancytree">jquery.fancytree.js project home</a> <a class="hideOutsideFS" href="#">Link to this page</a> <a class="hideInsideFS" href="index.html">Example Browser</a> <a href="#" id="codeExample">View source code</a> </p> <pre id="sourceCode" class="prettyprint" style="display:none"></pre> <!-- End_Exclude --> </body> </html>