{"_id":"54dd1324ca1e5219007e9dac","version":{"_id":"54d5635532d98b0d00384afb","project":"54d53c7b23010a0d001aca0c","__v":10,"forked_from":"54d53c7c23010a0d001aca0f","createdAt":"2015-02-07T00:59:01.934Z","releaseDate":"2015-02-07T00:59:01.934Z","categories":["54d5635632d98b0d00384afc","54d5635632d98b0d00384afd","54d5635632d98b0d00384afe","54d5635632d98b0d00384aff","54d5635632d98b0d00384b00","54d5635632d98b0d00384b01","54d5635632d98b0d00384b02","54d652097e05890d006f153e","54dd1315ca1e5219007e9daa","54e21e2b22de1c230094b147","54e68e62a43fe13500db3879","54fa1d3fe7a0ba2f00306309","551c453a23a1ee190034d19a","551df586e52a0b23000c62b6","551f39be6886f8230055f02a","55a6720751457325000e4d97"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"0.1.0","version":"0.1"},"parentDoc":null,"user":"54cfa8e1a8a4fd0d00b7fd1d","category":{"_id":"54dd1315ca1e5219007e9daa","pages":["54dd1324ca1e5219007e9dac","54e26fe6dd4c990d00479bef","5516e2d97f5d0919007d0701"],"version":"54d5635532d98b0d00384afb","project":"54d53c7b23010a0d001aca0c","__v":3,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-12T20:54:45.914Z","from_sync":false,"order":8,"slug":"user-interface","title":"User Interface"},"project":"54d53c7b23010a0d001aca0c","__v":165,"updates":["55a2520da542720d00a2109d"],"next":{"pages":[],"description":""},"createdAt":"2015-02-12T20:55:00.314Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"When creating a complex user interfaces it's often required to add elements that allow to the user to select one or more items. The `AceTree` widget can act as a [list](#section-as-a-list), a [tree](#section-as-a-tree), a [datagrid](#section-as-a-datagrid) and a [datagrid-tree](#section-as-a-datagrid-tree). It is available as the `List`, `Tree` and `Datagrid` plugin in Cloud9.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Based on Ace\",\n  \"body\": \"The AceTree is based on [Ace](http://ace.c9.io), which is the text editor that Cloud9 uses and is developed by the Cloud9 core team. The Ace editor uses a method called 'virtual viewport' to render it's content. This makes it possible to load a document with 4 million lines in ace. We have used the same technique for AceTree. You can therefore load enormous amounts of data into these widgets without any impact on performance. This makes this ui element especially suited for building professional, scalable UIs.\"\n}\n[/block]\n# Topics\n- [Events and Interaction](#section-events-interaction)\n- [Selection](#section-selection)\n- [Reloading Data](#section-reloading-the-data)\n- [Renaming and Editing](#section-renaming-and-editing)\n- [Expanding](#section-expanding)\n- [Sorting](#section-sorting)\n- [Filtering](#section-filtering)\n- [Checkboxes](#section-checkboxes)\n- [Resizing](#section-resizing)\n- [Theming](#section-theming)\n- [Drag&Drop](#section-drag-drop)\n- [Commands](#section-commands)\n- [Misc](#section-misc)\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Example Code\",\n  \"body\": \"In the next examples we'll load the UI elements inside a dialog. For more information on creating a dialog see the [dialog guide](doc:dialog).\"\n}\n[/block]\n# As a List\n\nThe most basic form the `AceTree` widget can take is that of a list. Let's start of with a simple example and then add more advanced features to show you what the API looks like. \n\nA very basic list rendering two items.\n```\nvar simpleList = new List({}, plugin);\nsimpleList.attachTo(htmlParent);\nsimpleList.setRoot([\"Item 1\", \"Item 2\"]);\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/y67ILyUpQy8csxiKRDLb_2015-02-17_1618.png\",\n        \"2015-02-17_1618.png\",\n        \"1564\",\n        \"488\",\n        \"#5cabfb\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThe object passed as first argument of the constructor allows you to configure the style and behavior of the list. In the next example we'll set the `container` of the list explicitly so that we don't have to call `attachTo()`, in addition we configure the list to read data from objects instead of strings.\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"Every config property can also be set as a property on the widget\",\n  \"body\": \"You can set these properties both when creating the widget in it's constructor or by setting them directly on the widget after creation.\"\n}\n[/block]\n```javascript\nvar myList = new List({\n    container: htmlParent,\n    emptyMessage: \"No items found\",\n    dataType: \"object\"\n}, plugin);\n\nmyList.setRoot([\n    { label: \"Item 1\" }, \n    { label: \"Item 2\" } \n]);\n```\n\nThis list looks exactly the same as the one in the previous example. A big difference is that you now control the objects that are manipulated by the list. The `myList.selectedNode` will return your object.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Objects are extended!\",\n  \"body\": \"Be aware that `AceTree` adds a small set of properties to your objects. If you want to prevent this, make sure you create copies of your objects before calling `setRoot()` with them.\"\n}\n[/block]\n## Custom Renderer\n\nOne of the key features of `AceTree`, besides it's scalability, is your ability to determine how it renders your data. The following example loads a set of custom objects and renders them using a custom row renderer which generates the html that is used to display each item.\n\n```javascript\ncustomList = new List({\n    container: htmlParent,\n    rowHeight : 38,\n    dataType: \"object\",\n\n    renderRow: function(row, html, config){ \n        var node = this.root.items[row];\n        var isSelected = this.isSelected(node);\n    \n        html.push(\"<div class='\" + (isSelected ? \"selected \" : \"\") + \"'\"\n            + \" style='height:28px;padding:5px;'>\" \n            + \"<strong>\" + node.head + \"</strong><br />\"\n            + node.body + \"</div>\");\n    }\n}, plugin);\n\ncustomList.setRoot([\n    { head: \"Hey You All!\", body: \"This is a longer way to say hi to all of you folks!\" }, \n    { head: \"Buy More!\", body: \"Buying more has been long known to improve health and longevity\" } \n]);\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/QrXYzyb0Sg6d8x6fELMJ_2015-02-17_1706.png\",\n        \"2015-02-17_1706.png\",\n        \"1570\",\n        \"472\",\n        \"#5cabfa\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nAs an alternative to `renderRow()` there is a set of functions that allow you to set specific html for the caption, icon and other elements. We'll show case those functions when customizing the tree.\n\n# As a Tree\n\nThe next form the `AceTree` widget can take is that of a tree. Let's start of with a simple example and then add more advanced features to show you what the API looks like. \n\nA very basic tree rendering two items.\n```javascript\nvar simpleTree = new Tree({}, plugin);\nsimpleTree.attachTo(htmlParent);\n\nsimpleTree.setRoot({\n    label: \"root\",\n    items: [{\n        label: \"test\",\n        items: [\n            { label: \"sub1\" },\n            { label: \"sub2\" }\n        ]\n    }, { label: \"test2\" } ]});\n});\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/aFFfIWZ6RTGL5XKeme2M_2015-02-17_1715.png\",\n        \"2015-02-17_1715.png\",\n        \"1570\",\n        \"474\",\n        \"#5cabfb\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou might have noticed that we didn't use `dataType`. This is because the `Tree` and `Datagrid` always expect objects as data.\n\n## Custom Renderer\n\nYou can customize the tree in the same way as we've done with the list in the examples above. This time, instead of using the `renderRow()` function, we'll define custom renders for only a part of the item, in this case the icon. We have defined three classes in our css called `.folder`, `.default` and `.loading`. We'll set these classes in our `getIconHTML()` function to set the icon of each row.\n\n```javascript\nvar customTree = new Tree({\n    container: htmlParent,\n    \n    getIconHTML: function(node) {\n        var icon = node.isFolder ? \"folder\" : \"default\";\n        if (node.status === \"loading\") icon = \"loading\";\n        return \"<span class='ace_tree-icon \" + icon + \"'></span>\";\n    }\n}, plugin);\n\ncustomTree.setRoot({\n    label: \"root\",\n    items: [{\n        label: \"test\",\n        isFolder: true,\n        items: [\n            { label: \"sub1\" },\n            { label: \"sub2\" }\n        ]\n    }, { label: \"test2\", isFolder: true } ]});\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/CNxv9xjsT42Em4s89lEg_2015-02-17_1726.png\",\n        \"2015-02-17_1726.png\",\n        \"1570\",\n        \"460\",\n        \"#5cabfa\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n# As a Datagrid\n\nThe next form the `AceTree` widget can take is that of a tree. The columns array specifies each of the columns. The `caption` determines the text displayed on the column header. The `value` is used as the property read from each node. You can mix widths specified in percentage and in pixels, just make sure the percentage totals to 100%.\n\nA basic datagrid rendering two items.\n```javascript\nvar simpleDatagrid = new Datagrid({\n    container: htmlParent,\n\n    columns : [\n        {\n            caption: \"Property\",\n            value: \"label\",\n            width: \"40%\",\n        }, \n        {\n            caption: \"Value\",\n            value: \"value\",\n            width: \"60%\",\n        }, \n        {\n            caption: \"Type\",\n            value: \"type\",\n            width: \"55\"\n        },\n        {\n            caption: \"CPU\",\n            getText: function(node) { return node.cpu + \"%\"; },\n            width: \"50\",\n        }\n    ]\n}, plugin);\n\nmyDatagrid.setRoot([\n    { label: \"test\", value: \"Example Value\", type: \"50\", cpu: \"20\" }, \n    { label: \"test2\", value: \"Example Value 2\", type: \"50\", cpu: \"50\" } \n]);\n```\n\nThe `getText()` function can be used instead of the `value` attribute. The value that is returned by the `getText()` function is used as the contents of a cell.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/h2yXYVNQSDqjlb71Rjpo_2015-02-17_1836.png\",\n        \"2015-02-17_1836.png\",\n        \"1570\",\n        \"482\",\n        \"#5cabfa\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"rowHeight is calculated automatically!\",\n  \"body\": \"Note that for the datagrid the `rowHeight` is measured based on the css. You can override this behavior by setting `rowHeight` explicitly.\"\n}\n[/block]\n# As a Datagrid-Tree\n\nThe last form the `AceTree` widget can take is that of a combined datagrid and tree.\n\nA basic datagrid-tree with a few sub nodes and an icon handler.\n```javascript\nvar simpleDatagridTree = new Datagrid({\n    container: htmlParent,\n\n    columns : [\n        {\n            caption: \"Property\",\n            value: \"name\",\n            defaultValue: \"Scope\",\n            width: \"40%\",\n            type: \"tree\"\n        }, \n        {\n            caption: \"Value\",\n            value: \"value\",\n            width: \"60%\"\n        }, \n        {\n            caption: \"Type\",\n            value: \"type\",\n            width: \"55\"\n        },\n        {\n            caption: \"CPU\",\n            getText: function(node) { return (node.cpu || 0) + \"%\"; },\n            width: \"50\",\n        }\n    ],\n    \n    getIconHTML: function(node) {\n        return \"<span class='dbgVarIcon'></span>\";\n    }\n}, plugin);\n\nsimpleDatagridTree.setRoot({\n    label: \"root\",\n    items: [{\n        label: \"test\",\n        items: [\n            {label: \"sub1\", value: \"Example Value\", type: \"50\", cpu: \"20\" },\n            {label: \"sub2\", value: \"Example Value\", type: \"50\", cpu: \"20\" }\n        ]\n    }, {label: \"test2\", value: \"Example Value\", type: \"50\", cpu: \"20\" } ]});\n});\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ycDtFuZ7TNS8evB1083U_2015-02-17_1850.png\",\n        \"2015-02-17_1850.png\",\n        \"1570\",\n        \"570\",\n        \"#5caaf8\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n# Events & Interaction\n\nThe `AceTree` widgets fire 20 events. In this section we'll discuss 6 commonly used once. We'll mention many of the other events in the sections below.\n\n## Click event\n\nThe click is fired whenever the user clicks on the widget. You get information about the x and y position of the click as well as access to the native browser event.\n\n```\nsimpleTree.on(\"click\", function(e){\n    console.log(\"The user clicked at \", e.x, \", \", e.y);\n});\n```\n\n## Delete event\n\nThe delete event is called when the user deletes an item from the widget, for instance by hitting the DEL button. Note that the widget won't actually manipulate your data object. That is up to you. If you don't remove the selected nodes from the data, they will still be there.\n\n```\nsimpleList.on(\"delete\", function(){\n    // Manipulate data object here\n});\n```\n\n## Scroll event\n\nThe scroll event is called when the user vertically scrolls through the widget. Remember that these widgets have a virtual viewport and thus only render the content that is on the screen.\n\n```\nmyDatagrid.on(\"scroll\", function(){\n    console.log(\"The scroll position is\", myDatagrid.scrollTop);\n});\n```\n\nTo set the scroll simply set the scrollTop property.\n```\nmyDatagrid.scrollTop = 100;\n```\n\n## Resize event\n\nThe resize event is called when the `resize()` method is called and the size is actually changed.\n\n```\nmyDatagrid.on(\"resize\", function(){\n    console.log(\"This was an actual resize\");\n});\n```\n\n## Expand & collapse events\n\nThere are two events that are specific to the tree (and datagrid-tree). These are `expand` and `collapse` events. They'll fire when the user expands or collapses an item.\n\n```\nsimpleTree.on(\"expand\", function(node){\n    console.log(\"You expanded\", node.label);\n});\n```\n\n# Selection\n\nThe selection allows you to manipulate the selection through the `select()` method. Selection is done by reference and you can select one node or an array of multiple nodes.\n\n```javascript\nmyList.select(data[5]); // Select the 5th item\nmyList.select(data); // Selects all items\n```\n\nAt any time retrieve the current selection via one of two properties. \n\n```javascript\nmyList.selectedNodes.forEach(function(node){\n    console.log(node.label, \"is selected);\n});\n\nconsole.log(myList.selectedNode.label, \"is the caret\");\n```\n\nListen to the user selecting items using the `select` events.\n```javascript\nmyList.on(\"select\", function(){\n    console.log(\"The user selected a node\", myList.selectedNode.label);\n});\n```\n\n# Reloading the data\n\nCloud9 plugins often want to update the data loaded in the widget. As you update your dataset you need to call the `refresh()` method to update the widgets view.\n\n```\nsimpleTree.root.items[0].label = \"New Name\";\nsimpleTree.refresh();\n```\n\n# Renaming and Editing\n\nThe `AceTree` widgets have a built-in feature that allows renaming nodes in the `List` and `Tree` and to edit a cell in the `Datagrid`.\n\nFor both the `Tree` and the `List` simple enable rename to enable this behavior.\n```javascript\nmyTree.enableRename = true;\n```\n\nNow a user can hit F2 or click once on an already selected node to start renaming the item. You can also programmatically trigger renaming.\n\n```javascript\nmyList.startRename(myList.selectedNode);\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/tW6sp1F3RTmzlWLyM4Sa_Screen%20Shot%202015-02-17%20at%208.57.50%20PM.png\",\n        \"Screen Shot 2015-02-17 at 8.57.50 PM.png\",\n        \"1470\",\n        \"478\",\n        \"#64abfb\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThe `Datagrid` allows you to configure a cell as editable. Simply set the `editor` property to \"textbox\" of the appropriate column. You *must* set `enableRename` to `true` to make editing work.\n\n```javascript\n{\n    caption: \"Value\",\n    value: \"value\",\n    width: \"60%\",\n    editor: \"textbox\"\n},\n```\n\nNow a user can double click on a cell to start renaming the item. You can also programmatically trigger renaming.\n\n```javascript\ndatagrid.startRename(myList.selectedNode, 1); // The 2nd argument is the column index\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/o2XPIv3PS0ulLRQEzU4o_2015-02-17_2111.png\",\n        \"2015-02-17_2111.png\",\n        \"1570\",\n        \"480\",\n        \"#5daaf8\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## Rename Events\n\nThere are two events related to renaming; `beforeRename` and `afterRename`. Use the `beforeRename` event to validate whether your plugin allows renaming the selected node. You can call `e.preventDefault()` to disable renaming before it starts. The `afterRename` event is called when the rename is complete. Just like with the `delete` event you are responsible for updating the dataset and refreshing the widget.\n\n```javascript\ndatagrid.on(\"beforeRename\", function(e) {\n    if (e.column.caption == \"Value\" && e.node.isFolder)\n        return e.preventDefault();\n});\ndatagrid.on(\"afterRename\", function(e) {\n    sendToServer(e.node.id, e.value, function(err){\n        e.node.label = e.value;\n        datagrid.refresh();\n    });\n});\n```\n\n# Expanding\n\nTo expand a node when setting the data, so before it is loaded in the tree, set `isOpen` to `true`.\n\n```\nsimpleDatagridTree.setRoot({\n    items: [{\n        label: \"test\",\n        isOpen: true,\n        items: [\n            {label: \"sub1\", value: \"Example Value\", type: \"50\", cpu: \"20\" },\n            {label: \"sub2\", value: \"Example Value\", type: \"50\", cpu: \"20\" }\n        ]\n    }]\n});\n```\n\n# Sorting\n\nTo influence the sorting of the widget simply add a sort function. This function gets all children of a node (or all nodes for the list) and allows you to sort the list in any way you like.\n\nThis example sorts a list alphabetical and makes sure that any *folders* are at the top of the list.\n```\nsort: function(children) {\n    var compare = simpleTree.model.alphanumCompare;\n    return children.sort(function(a, b) {\n        var aIsSpecial = a.tagName == \"folder\";\n        var bIsSpecial = b.tagName == \"folder\";\n        if (aIsSpecial && !bIsSpecial) return 1;\n        if (!aIsSpecial && bIsSpecial) return -1;\n        if (aIsSpecial && bIsSpecial) return a.index - b.index;\n        \n        return compare(a.name + \"\", b.name + \"\");\n    });\n};\n```\n\n# Filtering\n\nOne of the common interactions, that you'll find throughout the Cloud9 UI is to let the user filter the data in a widget. We've added a very simple way to filter based on a single keyword. \n\nThis example combines a textbox with a tree and allows the user to search for items in the tree by typing in the textbox.\n```\nhtmlParent.innerHTML = \"<input class='my-style' />\"\nhtmlParent.firstChild.addEventListener(\"keyup\", function(){\n    simpleTree.filterKeyword = this.value;\n});\n\nvar simpleTree = new Tree({\n    container: htmlParent\n}, plugin);\n\nsimpleTree.setRoot({\n    label: \"root\",\n    items: [{\n        label: \"test\",\n        items: [\n            {label: \"sub1\"},\n            {label: \"sub2\"}\n        ]\n    }, {label: \"test2\"} ]});\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/blkoINJjQU2PmkrskE46_2015-02-18_1059.png\",\n        \"2015-02-18_1059.png\",\n        \"1570\",\n        \"528\",\n        \"#f0f0f0\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNow a user can type into the textbox to only show those elements matching the characters typed.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/VwjoBrU1Sz2ZTWffpMZ5_2015-02-18_1059b.png\",\n        \"2015-02-18_1059b.png\",\n        \"1570\",\n        \"532\",\n        \"#4d6d8e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThere are two properties that you can set to configure the filter. The `filterCaseInsensitive` property when set to `false` will filter based on case sensitive characters. The `filterProperty` can be set to a string containing the name of the property on your objects to use for filtering. If this property is not set either `label` or `name` are used.\n\n# Checkboxes\n\nTo enable checkboxes in your list, tree or datagrid set `enableCheckboxes` to `true`. Each row will display a checkbox which can be set to checked, unchecked and half checked.\n\n```\ndatagrid = new Datagrid({\n    container: htmlParent,\n    enableCheckboxes: true,\n    \n    columns : [\n        {\n            caption: \"Name\",\n            value: \"label\",\n            width: \"35%\",\n            type: \"tree\"\n        }, \n        {\n            caption: \"Description\",\n            value: \"description\",\n            width: \"65%\"\n        }\n    ]\n}, plugin);\n\nsimpleDatagridTree.setRoot({\n    items: [{\n        label: \"test\",\n        isChecked: true\n        items: [\n            { label: \"sub1\", description: \"Example Value\" },\n            { label: \"sub2\", description: \"Example Value\" }\n        ]\n    });\n});\n```\n\nSetting `isChecked` to `true` on a item will display it as checked. Set it to `-1` to have it half-checked and `false` for unchecked. By default the widget will only toggle between fully checked and unchecked. Setting items as half-checked will require custom code.\n\nThis is what that looks like in the [Cloud9 installer](doc:adding-an-installer).\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/IkpVM8hRRFaVlxCR5vVe_2015-04-01_0830.png\",\n        \"2015-04-01_0830.png\",\n        \"1570\",\n        \"882\",\n        \"#64acfb\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## Checkbox methods\n\nTo check an item call the `check()` method.\n\n```\ndatagrid.check(item);\n```\n\nSimilarly to uncheck an item call the `uncheck()` method.\n\n```\ndatagrid.uncheck(item);\n```\n\n## Checkbox events\n\nWhen one or more items are checked and unchecked their respective events are called.\n\n```\ndatagrid.on(\"check\", function(items){\n    console.log(\"checked\", items.map(function(n){ return n.label; }).join(\" \"));\n});\ndatagrid.on(\"uncheck\", function(items){\n    console.log(\"unchecked\", items.map(function(n){ return n.label; }).join(\" \"));\n});\n```\n\n# Resizing\n\nIt is important to know that the `AceTree` widgets don't resize automatically. Make sure to call the `resize()` method whenever they should recalculate their size. By default the `resize()` method will only trigger if the dimensions of the container have changed, so you can call it as many times as you want. It will also only recompute the area that actually needs it.\n\nThis resizes the tree when the browser resizes.\n```\nlayout.on(\"resize\", function(){\n    simpleTree.resize();\n}, plugin);\n```\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Check the `resize` event of your container\",\n  \"body\": \"Most Cloud9 UI plugins such as Dialogs and Panels offer a `resize` event. Simply hook that event and call `widget.resize()` to make sure your widget is always correctly rendered.\"\n}\n[/block]\n# Theming\n\nTheming of these widgets is done through css. By default the `.custom-tree` class is applied for `List` and `Tree` and the `.blackdg` class for `Datagrid`. You can choose to override this and use your own class by setting the `theme` property. Note that the default themes are configured using the Cloud9 main theme. *More information on theming will be documented soon.*\n\n```\nwidget.theme = \"my-own-class\"; // Or set theme in the constructor options\n```\n\n# Drag & Drop\n\nThe `AceTree` widgets support drag&drop out of the box. Simply enable it by setting the `enableDragDrop` property to `true`.\n\n```\nwidget.enableDragDrop = true;\n```\n\n## Drag & Drop Styling\n\nYou control the look of the drag highlighting via css. Simply reference the classes that are used and overwrite any styling you want.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th>dragOver</th><td>is set on the container when dragging</td></tr>\\n<tr><th>dragImage</th><td>class of the node which is dragged</td></tr>\\n<tr><th>dropTarget</th><td>class of the parent item that the node is hovering over</td></tr>\\n<tr><th>dragHighlight</th><td>class of the children container of the parent that the node is hovering over</td></tr>\\n</table>\"\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/sMxIR8rTTtWE0KV2z78F_Screen-Shot-2015-02-18-at-10.27.09-AM.png\",\n        \"Screen-Shot-2015-02-18-at-10.27.09-AM.png\",\n        \"1570\",\n        \"482\",\n        \"#5babfa\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## Drag & Drop Events\n\nThe following events allow you to control the drag&drop operations. Similar to the `delete` and `rename` events it is your responsibility to update the underlying data. \n\n```javascript\nsimpleTree.on(\"drop\", function(e) {\n    if (e.target && e.selectedNodes) {\n        if (e.isCopy)\n            copy(e.selectedNodes, e.target);\n        else\n            move(e.selectedNodes, e.target);\n    }\n});\n```\n\nThe `isCopy` property is set when the user hold the `Ctrl` or `Command` key.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th>drop</th><td>Fired when the node or nodes are dropped</td></tr>\\n<tr><th>dragIn</th><td>Fires when a node is dragging into the widget</td></tr>\\n<tr><th>dragOut</th><td>Fires when a node is dragging out of the widget</td></tr>\\n<tr><th>dragMoveOutside</th><td>Fires when the node is moves outside of the widget</td></tr>\\n<tr><th>folderDragEnter</th><td>Fires when a node drags onto a parent</td></tr>\\n<tr><th>folderDragLeave</th><td>Fires when a node drags out of a parent</td></tr>\\n<tr><th>dropOutside</th><td>Fires when a node is dropped outside of the widget</td></tr>\\n</table>\"\n}\n[/block]\n# Commands\n\nSimilar to `Ace` and Cloud9 itself, the `AceTree` widgets have a set of commands that you can execute on the widget.\n\n```\nsimpleTree.execCommand(\"selectAll\");\n```\n\nThe following table lists all the commands available.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th>selectAll</th><td>Selects all the elements in the widget</td></tr>\\n<tr><th>centerselection</th><td>Scrolls the selection into the center of the widget</td></tr>\\n<tr><th>closeOrlevelUp</th><td>Collapses the selected node or moves the caret one level up</td></tr>\\n<tr><th>levelUp</th><td>Moves the caret one level up</td></tr>\\n<tr><th>levelDown</th><td>Moves the caret one level down</td></tr>\\n<tr><th>goToStart</th><td>Moves the caret to the start</td></tr>\\n<tr><th>goToEnd</th><td>Moves the caret to the end</td></tr>\\n<tr><th>closeAllFromSelected</th><td>Collapses all selected nodes</td></tr>\\n<tr><th>openAllFromSelected</th><td>Expand all selected nodes</td></tr>\\n<tr><th>pageup</th><td>Scroll one page up</td></tr>\\n<tr><th>gotopageup</th><td>Move the caret one page up</td></tr>\\n<tr><th>pagedown</th><td>Scroll one page down</td></tr>\\n<tr><th>gotopageDown</th><td>Move the caret one page down</td></tr>\\n<tr><th>scrollup</th><td>Scroll up</td></tr>\\n<tr><th>scrolldown</th><td>Scroll down</td></tr>\\n<tr><th>goUp</th><td>Move the caret one position up</td></tr>\\n<tr><th>goDown</th><td>Move the caret one position down</td></tr>\\n<tr><th>selectUp</th><td>Select up</td></tr>\\n<tr><th>selectDown</th><td>Select down</td></tr>\\n<tr><th>selectToUp</th><td>unselect current node and select node above, keeping other selected nodes</td></tr>\\n<tr><th>selectToDown</th><td>unselect current node and select node below, keeping other selected nodes</td></tr>\\n<tr><th>selectMoreUp</th><td>select node above cursor, keeping all other nodes selected</td></tr>\\n<tr><th>selectMoreDown</th><td>select node below cursor, keeping all other nodes selected</td></tr>\\n<tr><th>rename</th><td>Start rename</td></tr>\\n<tr><th>chose</th><td>Select and call the choose event</td></tr>\\n<tr><th>delete</th><td>Call the delete event</td></tr>\\n</table>\"\n}\n[/block]\n# Misc\n\nOne last edge case we found useful when building the Debugger UI was to disable the scrolling behavior of the datagrid and instead have it render all the content. To enable this use the `minLines` and `maxLines` properties to set the minimum and maximum amount of lines that should be rendered by the widget before it starts showing a scrollbar.\n\n```javascript\nvar myDatagrid = new Datagrid({\n    container: htmlParent,\n    minLines: 3,\n    maxLines: 200\n}, plugin);\n\nmyDatagrid.setRoot(dataset);\n```","excerpt":"","slug":"ace-tree","type":"basic","title":"Ace List, Tree, Datagrid"}

Ace List, Tree, Datagrid


When creating a complex user interfaces it's often required to add elements that allow to the user to select one or more items. The `AceTree` widget can act as a [list](#section-as-a-list), a [tree](#section-as-a-tree), a [datagrid](#section-as-a-datagrid) and a [datagrid-tree](#section-as-a-datagrid-tree). It is available as the `List`, `Tree` and `Datagrid` plugin in Cloud9. [block:callout] { "type": "info", "title": "Based on Ace", "body": "The AceTree is based on [Ace](http://ace.c9.io), which is the text editor that Cloud9 uses and is developed by the Cloud9 core team. The Ace editor uses a method called 'virtual viewport' to render it's content. This makes it possible to load a document with 4 million lines in ace. We have used the same technique for AceTree. You can therefore load enormous amounts of data into these widgets without any impact on performance. This makes this ui element especially suited for building professional, scalable UIs." } [/block] # Topics - [Events and Interaction](#section-events-interaction) - [Selection](#section-selection) - [Reloading Data](#section-reloading-the-data) - [Renaming and Editing](#section-renaming-and-editing) - [Expanding](#section-expanding) - [Sorting](#section-sorting) - [Filtering](#section-filtering) - [Checkboxes](#section-checkboxes) - [Resizing](#section-resizing) - [Theming](#section-theming) - [Drag&Drop](#section-drag-drop) - [Commands](#section-commands) - [Misc](#section-misc) [block:callout] { "type": "warning", "title": "Example Code", "body": "In the next examples we'll load the UI elements inside a dialog. For more information on creating a dialog see the [dialog guide](doc:dialog)." } [/block] # As a List The most basic form the `AceTree` widget can take is that of a list. Let's start of with a simple example and then add more advanced features to show you what the API looks like. A very basic list rendering two items. ``` var simpleList = new List({}, plugin); simpleList.attachTo(htmlParent); simpleList.setRoot(["Item 1", "Item 2"]); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/y67ILyUpQy8csxiKRDLb_2015-02-17_1618.png", "2015-02-17_1618.png", "1564", "488", "#5cabfb", "" ] } ] } [/block] The object passed as first argument of the constructor allows you to configure the style and behavior of the list. In the next example we'll set the `container` of the list explicitly so that we don't have to call `attachTo()`, in addition we configure the list to read data from objects instead of strings. [block:callout] { "type": "success", "title": "Every config property can also be set as a property on the widget", "body": "You can set these properties both when creating the widget in it's constructor or by setting them directly on the widget after creation." } [/block] ```javascript var myList = new List({ container: htmlParent, emptyMessage: "No items found", dataType: "object" }, plugin); myList.setRoot([ { label: "Item 1" }, { label: "Item 2" } ]); ``` This list looks exactly the same as the one in the previous example. A big difference is that you now control the objects that are manipulated by the list. The `myList.selectedNode` will return your object. [block:callout] { "type": "danger", "title": "Objects are extended!", "body": "Be aware that `AceTree` adds a small set of properties to your objects. If you want to prevent this, make sure you create copies of your objects before calling `setRoot()` with them." } [/block] ## Custom Renderer One of the key features of `AceTree`, besides it's scalability, is your ability to determine how it renders your data. The following example loads a set of custom objects and renders them using a custom row renderer which generates the html that is used to display each item. ```javascript customList = new List({ container: htmlParent, rowHeight : 38, dataType: "object", renderRow: function(row, html, config){ var node = this.root.items[row]; var isSelected = this.isSelected(node); html.push("<div class='" + (isSelected ? "selected " : "") + "'" + " style='height:28px;padding:5px;'>" + "<strong>" + node.head + "</strong><br />" + node.body + "</div>"); } }, plugin); customList.setRoot([ { head: "Hey You All!", body: "This is a longer way to say hi to all of you folks!" }, { head: "Buy More!", body: "Buying more has been long known to improve health and longevity" } ]); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/QrXYzyb0Sg6d8x6fELMJ_2015-02-17_1706.png", "2015-02-17_1706.png", "1570", "472", "#5cabfa", "" ] } ] } [/block] As an alternative to `renderRow()` there is a set of functions that allow you to set specific html for the caption, icon and other elements. We'll show case those functions when customizing the tree. # As a Tree The next form the `AceTree` widget can take is that of a tree. Let's start of with a simple example and then add more advanced features to show you what the API looks like. A very basic tree rendering two items. ```javascript var simpleTree = new Tree({}, plugin); simpleTree.attachTo(htmlParent); simpleTree.setRoot({ label: "root", items: [{ label: "test", items: [ { label: "sub1" }, { label: "sub2" } ] }, { label: "test2" } ]}); }); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/aFFfIWZ6RTGL5XKeme2M_2015-02-17_1715.png", "2015-02-17_1715.png", "1570", "474", "#5cabfb", "" ] } ] } [/block] You might have noticed that we didn't use `dataType`. This is because the `Tree` and `Datagrid` always expect objects as data. ## Custom Renderer You can customize the tree in the same way as we've done with the list in the examples above. This time, instead of using the `renderRow()` function, we'll define custom renders for only a part of the item, in this case the icon. We have defined three classes in our css called `.folder`, `.default` and `.loading`. We'll set these classes in our `getIconHTML()` function to set the icon of each row. ```javascript var customTree = new Tree({ container: htmlParent, getIconHTML: function(node) { var icon = node.isFolder ? "folder" : "default"; if (node.status === "loading") icon = "loading"; return "<span class='ace_tree-icon " + icon + "'></span>"; } }, plugin); customTree.setRoot({ label: "root", items: [{ label: "test", isFolder: true, items: [ { label: "sub1" }, { label: "sub2" } ] }, { label: "test2", isFolder: true } ]}); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/CNxv9xjsT42Em4s89lEg_2015-02-17_1726.png", "2015-02-17_1726.png", "1570", "460", "#5cabfa", "" ] } ] } [/block] # As a Datagrid The next form the `AceTree` widget can take is that of a tree. The columns array specifies each of the columns. The `caption` determines the text displayed on the column header. The `value` is used as the property read from each node. You can mix widths specified in percentage and in pixels, just make sure the percentage totals to 100%. A basic datagrid rendering two items. ```javascript var simpleDatagrid = new Datagrid({ container: htmlParent, columns : [ { caption: "Property", value: "label", width: "40%", }, { caption: "Value", value: "value", width: "60%", }, { caption: "Type", value: "type", width: "55" }, { caption: "CPU", getText: function(node) { return node.cpu + "%"; }, width: "50", } ] }, plugin); myDatagrid.setRoot([ { label: "test", value: "Example Value", type: "50", cpu: "20" }, { label: "test2", value: "Example Value 2", type: "50", cpu: "50" } ]); ``` The `getText()` function can be used instead of the `value` attribute. The value that is returned by the `getText()` function is used as the contents of a cell. [block:image] { "images": [ { "image": [ "https://files.readme.io/h2yXYVNQSDqjlb71Rjpo_2015-02-17_1836.png", "2015-02-17_1836.png", "1570", "482", "#5cabfa", "" ] } ] } [/block] [block:callout] { "type": "success", "title": "rowHeight is calculated automatically!", "body": "Note that for the datagrid the `rowHeight` is measured based on the css. You can override this behavior by setting `rowHeight` explicitly." } [/block] # As a Datagrid-Tree The last form the `AceTree` widget can take is that of a combined datagrid and tree. A basic datagrid-tree with a few sub nodes and an icon handler. ```javascript var simpleDatagridTree = new Datagrid({ container: htmlParent, columns : [ { caption: "Property", value: "name", defaultValue: "Scope", width: "40%", type: "tree" }, { caption: "Value", value: "value", width: "60%" }, { caption: "Type", value: "type", width: "55" }, { caption: "CPU", getText: function(node) { return (node.cpu || 0) + "%"; }, width: "50", } ], getIconHTML: function(node) { return "<span class='dbgVarIcon'></span>"; } }, plugin); simpleDatagridTree.setRoot({ label: "root", items: [{ label: "test", items: [ {label: "sub1", value: "Example Value", type: "50", cpu: "20" }, {label: "sub2", value: "Example Value", type: "50", cpu: "20" } ] }, {label: "test2", value: "Example Value", type: "50", cpu: "20" } ]}); }); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/ycDtFuZ7TNS8evB1083U_2015-02-17_1850.png", "2015-02-17_1850.png", "1570", "570", "#5caaf8", "" ] } ] } [/block] # Events & Interaction The `AceTree` widgets fire 20 events. In this section we'll discuss 6 commonly used once. We'll mention many of the other events in the sections below. ## Click event The click is fired whenever the user clicks on the widget. You get information about the x and y position of the click as well as access to the native browser event. ``` simpleTree.on("click", function(e){ console.log("The user clicked at ", e.x, ", ", e.y); }); ``` ## Delete event The delete event is called when the user deletes an item from the widget, for instance by hitting the DEL button. Note that the widget won't actually manipulate your data object. That is up to you. If you don't remove the selected nodes from the data, they will still be there. ``` simpleList.on("delete", function(){ // Manipulate data object here }); ``` ## Scroll event The scroll event is called when the user vertically scrolls through the widget. Remember that these widgets have a virtual viewport and thus only render the content that is on the screen. ``` myDatagrid.on("scroll", function(){ console.log("The scroll position is", myDatagrid.scrollTop); }); ``` To set the scroll simply set the scrollTop property. ``` myDatagrid.scrollTop = 100; ``` ## Resize event The resize event is called when the `resize()` method is called and the size is actually changed. ``` myDatagrid.on("resize", function(){ console.log("This was an actual resize"); }); ``` ## Expand & collapse events There are two events that are specific to the tree (and datagrid-tree). These are `expand` and `collapse` events. They'll fire when the user expands or collapses an item. ``` simpleTree.on("expand", function(node){ console.log("You expanded", node.label); }); ``` # Selection The selection allows you to manipulate the selection through the `select()` method. Selection is done by reference and you can select one node or an array of multiple nodes. ```javascript myList.select(data[5]); // Select the 5th item myList.select(data); // Selects all items ``` At any time retrieve the current selection via one of two properties. ```javascript myList.selectedNodes.forEach(function(node){ console.log(node.label, "is selected); }); console.log(myList.selectedNode.label, "is the caret"); ``` Listen to the user selecting items using the `select` events. ```javascript myList.on("select", function(){ console.log("The user selected a node", myList.selectedNode.label); }); ``` # Reloading the data Cloud9 plugins often want to update the data loaded in the widget. As you update your dataset you need to call the `refresh()` method to update the widgets view. ``` simpleTree.root.items[0].label = "New Name"; simpleTree.refresh(); ``` # Renaming and Editing The `AceTree` widgets have a built-in feature that allows renaming nodes in the `List` and `Tree` and to edit a cell in the `Datagrid`. For both the `Tree` and the `List` simple enable rename to enable this behavior. ```javascript myTree.enableRename = true; ``` Now a user can hit F2 or click once on an already selected node to start renaming the item. You can also programmatically trigger renaming. ```javascript myList.startRename(myList.selectedNode); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/tW6sp1F3RTmzlWLyM4Sa_Screen%20Shot%202015-02-17%20at%208.57.50%20PM.png", "Screen Shot 2015-02-17 at 8.57.50 PM.png", "1470", "478", "#64abfb", "" ] } ] } [/block] The `Datagrid` allows you to configure a cell as editable. Simply set the `editor` property to "textbox" of the appropriate column. You *must* set `enableRename` to `true` to make editing work. ```javascript { caption: "Value", value: "value", width: "60%", editor: "textbox" }, ``` Now a user can double click on a cell to start renaming the item. You can also programmatically trigger renaming. ```javascript datagrid.startRename(myList.selectedNode, 1); // The 2nd argument is the column index ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/o2XPIv3PS0ulLRQEzU4o_2015-02-17_2111.png", "2015-02-17_2111.png", "1570", "480", "#5daaf8", "" ] } ] } [/block] ## Rename Events There are two events related to renaming; `beforeRename` and `afterRename`. Use the `beforeRename` event to validate whether your plugin allows renaming the selected node. You can call `e.preventDefault()` to disable renaming before it starts. The `afterRename` event is called when the rename is complete. Just like with the `delete` event you are responsible for updating the dataset and refreshing the widget. ```javascript datagrid.on("beforeRename", function(e) { if (e.column.caption == "Value" && e.node.isFolder) return e.preventDefault(); }); datagrid.on("afterRename", function(e) { sendToServer(e.node.id, e.value, function(err){ e.node.label = e.value; datagrid.refresh(); }); }); ``` # Expanding To expand a node when setting the data, so before it is loaded in the tree, set `isOpen` to `true`. ``` simpleDatagridTree.setRoot({ items: [{ label: "test", isOpen: true, items: [ {label: "sub1", value: "Example Value", type: "50", cpu: "20" }, {label: "sub2", value: "Example Value", type: "50", cpu: "20" } ] }] }); ``` # Sorting To influence the sorting of the widget simply add a sort function. This function gets all children of a node (or all nodes for the list) and allows you to sort the list in any way you like. This example sorts a list alphabetical and makes sure that any *folders* are at the top of the list. ``` sort: function(children) { var compare = simpleTree.model.alphanumCompare; return children.sort(function(a, b) { var aIsSpecial = a.tagName == "folder"; var bIsSpecial = b.tagName == "folder"; if (aIsSpecial && !bIsSpecial) return 1; if (!aIsSpecial && bIsSpecial) return -1; if (aIsSpecial && bIsSpecial) return a.index - b.index; return compare(a.name + "", b.name + ""); }); }; ``` # Filtering One of the common interactions, that you'll find throughout the Cloud9 UI is to let the user filter the data in a widget. We've added a very simple way to filter based on a single keyword. This example combines a textbox with a tree and allows the user to search for items in the tree by typing in the textbox. ``` htmlParent.innerHTML = "<input class='my-style' />" htmlParent.firstChild.addEventListener("keyup", function(){ simpleTree.filterKeyword = this.value; }); var simpleTree = new Tree({ container: htmlParent }, plugin); simpleTree.setRoot({ label: "root", items: [{ label: "test", items: [ {label: "sub1"}, {label: "sub2"} ] }, {label: "test2"} ]}); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/blkoINJjQU2PmkrskE46_2015-02-18_1059.png", "2015-02-18_1059.png", "1570", "528", "#f0f0f0", "" ] } ] } [/block] Now a user can type into the textbox to only show those elements matching the characters typed. [block:image] { "images": [ { "image": [ "https://files.readme.io/VwjoBrU1Sz2ZTWffpMZ5_2015-02-18_1059b.png", "2015-02-18_1059b.png", "1570", "532", "#4d6d8e", "" ] } ] } [/block] There are two properties that you can set to configure the filter. The `filterCaseInsensitive` property when set to `false` will filter based on case sensitive characters. The `filterProperty` can be set to a string containing the name of the property on your objects to use for filtering. If this property is not set either `label` or `name` are used. # Checkboxes To enable checkboxes in your list, tree or datagrid set `enableCheckboxes` to `true`. Each row will display a checkbox which can be set to checked, unchecked and half checked. ``` datagrid = new Datagrid({ container: htmlParent, enableCheckboxes: true, columns : [ { caption: "Name", value: "label", width: "35%", type: "tree" }, { caption: "Description", value: "description", width: "65%" } ] }, plugin); simpleDatagridTree.setRoot({ items: [{ label: "test", isChecked: true items: [ { label: "sub1", description: "Example Value" }, { label: "sub2", description: "Example Value" } ] }); }); ``` Setting `isChecked` to `true` on a item will display it as checked. Set it to `-1` to have it half-checked and `false` for unchecked. By default the widget will only toggle between fully checked and unchecked. Setting items as half-checked will require custom code. This is what that looks like in the [Cloud9 installer](doc:adding-an-installer). [block:image] { "images": [ { "image": [ "https://files.readme.io/IkpVM8hRRFaVlxCR5vVe_2015-04-01_0830.png", "2015-04-01_0830.png", "1570", "882", "#64acfb", "" ] } ] } [/block] ## Checkbox methods To check an item call the `check()` method. ``` datagrid.check(item); ``` Similarly to uncheck an item call the `uncheck()` method. ``` datagrid.uncheck(item); ``` ## Checkbox events When one or more items are checked and unchecked their respective events are called. ``` datagrid.on("check", function(items){ console.log("checked", items.map(function(n){ return n.label; }).join(" ")); }); datagrid.on("uncheck", function(items){ console.log("unchecked", items.map(function(n){ return n.label; }).join(" ")); }); ``` # Resizing It is important to know that the `AceTree` widgets don't resize automatically. Make sure to call the `resize()` method whenever they should recalculate their size. By default the `resize()` method will only trigger if the dimensions of the container have changed, so you can call it as many times as you want. It will also only recompute the area that actually needs it. This resizes the tree when the browser resizes. ``` layout.on("resize", function(){ simpleTree.resize(); }, plugin); ``` [block:callout] { "type": "warning", "title": "Check the `resize` event of your container", "body": "Most Cloud9 UI plugins such as Dialogs and Panels offer a `resize` event. Simply hook that event and call `widget.resize()` to make sure your widget is always correctly rendered." } [/block] # Theming Theming of these widgets is done through css. By default the `.custom-tree` class is applied for `List` and `Tree` and the `.blackdg` class for `Datagrid`. You can choose to override this and use your own class by setting the `theme` property. Note that the default themes are configured using the Cloud9 main theme. *More information on theming will be documented soon.* ``` widget.theme = "my-own-class"; // Or set theme in the constructor options ``` # Drag & Drop The `AceTree` widgets support drag&drop out of the box. Simply enable it by setting the `enableDragDrop` property to `true`. ``` widget.enableDragDrop = true; ``` ## Drag & Drop Styling You control the look of the drag highlighting via css. Simply reference the classes that are used and overwrite any styling you want. [block:html] { "html": "<table>\n<tr><th>dragOver</th><td>is set on the container when dragging</td></tr>\n<tr><th>dragImage</th><td>class of the node which is dragged</td></tr>\n<tr><th>dropTarget</th><td>class of the parent item that the node is hovering over</td></tr>\n<tr><th>dragHighlight</th><td>class of the children container of the parent that the node is hovering over</td></tr>\n</table>" } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/sMxIR8rTTtWE0KV2z78F_Screen-Shot-2015-02-18-at-10.27.09-AM.png", "Screen-Shot-2015-02-18-at-10.27.09-AM.png", "1570", "482", "#5babfa", "" ] } ] } [/block] ## Drag & Drop Events The following events allow you to control the drag&drop operations. Similar to the `delete` and `rename` events it is your responsibility to update the underlying data. ```javascript simpleTree.on("drop", function(e) { if (e.target && e.selectedNodes) { if (e.isCopy) copy(e.selectedNodes, e.target); else move(e.selectedNodes, e.target); } }); ``` The `isCopy` property is set when the user hold the `Ctrl` or `Command` key. [block:html] { "html": "<table>\n<tr><th>drop</th><td>Fired when the node or nodes are dropped</td></tr>\n<tr><th>dragIn</th><td>Fires when a node is dragging into the widget</td></tr>\n<tr><th>dragOut</th><td>Fires when a node is dragging out of the widget</td></tr>\n<tr><th>dragMoveOutside</th><td>Fires when the node is moves outside of the widget</td></tr>\n<tr><th>folderDragEnter</th><td>Fires when a node drags onto a parent</td></tr>\n<tr><th>folderDragLeave</th><td>Fires when a node drags out of a parent</td></tr>\n<tr><th>dropOutside</th><td>Fires when a node is dropped outside of the widget</td></tr>\n</table>" } [/block] # Commands Similar to `Ace` and Cloud9 itself, the `AceTree` widgets have a set of commands that you can execute on the widget. ``` simpleTree.execCommand("selectAll"); ``` The following table lists all the commands available. [block:html] { "html": "<table>\n<tr><th>selectAll</th><td>Selects all the elements in the widget</td></tr>\n<tr><th>centerselection</th><td>Scrolls the selection into the center of the widget</td></tr>\n<tr><th>closeOrlevelUp</th><td>Collapses the selected node or moves the caret one level up</td></tr>\n<tr><th>levelUp</th><td>Moves the caret one level up</td></tr>\n<tr><th>levelDown</th><td>Moves the caret one level down</td></tr>\n<tr><th>goToStart</th><td>Moves the caret to the start</td></tr>\n<tr><th>goToEnd</th><td>Moves the caret to the end</td></tr>\n<tr><th>closeAllFromSelected</th><td>Collapses all selected nodes</td></tr>\n<tr><th>openAllFromSelected</th><td>Expand all selected nodes</td></tr>\n<tr><th>pageup</th><td>Scroll one page up</td></tr>\n<tr><th>gotopageup</th><td>Move the caret one page up</td></tr>\n<tr><th>pagedown</th><td>Scroll one page down</td></tr>\n<tr><th>gotopageDown</th><td>Move the caret one page down</td></tr>\n<tr><th>scrollup</th><td>Scroll up</td></tr>\n<tr><th>scrolldown</th><td>Scroll down</td></tr>\n<tr><th>goUp</th><td>Move the caret one position up</td></tr>\n<tr><th>goDown</th><td>Move the caret one position down</td></tr>\n<tr><th>selectUp</th><td>Select up</td></tr>\n<tr><th>selectDown</th><td>Select down</td></tr>\n<tr><th>selectToUp</th><td>unselect current node and select node above, keeping other selected nodes</td></tr>\n<tr><th>selectToDown</th><td>unselect current node and select node below, keeping other selected nodes</td></tr>\n<tr><th>selectMoreUp</th><td>select node above cursor, keeping all other nodes selected</td></tr>\n<tr><th>selectMoreDown</th><td>select node below cursor, keeping all other nodes selected</td></tr>\n<tr><th>rename</th><td>Start rename</td></tr>\n<tr><th>chose</th><td>Select and call the choose event</td></tr>\n<tr><th>delete</th><td>Call the delete event</td></tr>\n</table>" } [/block] # Misc One last edge case we found useful when building the Debugger UI was to disable the scrolling behavior of the datagrid and instead have it render all the content. To enable this use the `minLines` and `maxLines` properties to set the minimum and maximum amount of lines that should be rendered by the widget before it starts showing a scrollbar. ```javascript var myDatagrid = new Datagrid({ container: htmlParent, minLines: 3, maxLines: 200 }, plugin); myDatagrid.setRoot(dataset); ```