{"_id":"54d5635632d98b0d00384b0e","project":"54d53c7b23010a0d001aca0c","__v":61,"user":"54cfa8e1a8a4fd0d00b7fd1d","category":{"_id":"54d5635632d98b0d00384afd","project":"54d53c7b23010a0d001aca0c","version":"54d5635532d98b0d00384afb","__v":7,"pages":["54d5635632d98b0d00384b03","54d5635632d98b0d00384b04","54d5635632d98b0d00384b05","54d5635632d98b0d00384b06","54d5635632d98b0d00384b07","54d5635632d98b0d00384b08","54d5635632d98b0d00384b09","54d5635632d98b0d00384b0a","54d5635632d98b0d00384b0b","54d5635632d98b0d00384b0c","54d5635632d98b0d00384b0d","54d5635632d98b0d00384b0e","54d5635632d98b0d00384b0f","54e2254d22de1c230094b156","54e2255622de1c230094b158","54e23b349d045721004cbc26","54e65455d8873117005c773f","54e6b5c0ba1a980d00e3ecb0","551c12c781b8563500fd998e"],"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-06T23:43:39.709Z","from_sync":false,"order":7,"slug":"plugin-base-classes","title":"Plugin Base Classes"},"parentDoc":null,"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"},"updates":["57599649919f302d0086001a"],"next":{"pages":[],"description":""},"createdAt":"2015-02-07T00:03:23.726Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"The `PreferencePanel()` base class creates a new plugin that can be used to create a new section in the global preferences editor. Each section gets a top level item in the left side navigation and when activated will display a UI on the right side that allows users to configure something.\n\n# Creating a Preference Panel\n\nA basic preference panel is created like this:\n\n```\nvar plugin = new PreferencePanel(\"Your Name\", main.consumes, {\n    caption: \"Panel Title\",\n    form: true,\n    index: 50\n});\n```\n\nAnd looks like this:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/B6nCWDT4TSirMhcO0Eaj_2015-03-26_0941.png\",\n        \"2015-03-26_0941.png\",\n        \"1570\",\n        \"402\",\n        \"#64acfc\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n# Preference Panel Properties\n\nThe following properties can be passed to the `PreferencePanel()` constructor.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th>caption</th><td>The caption of the navigation item</td></tr>\\n<tr><th>className</th><td>A custom css class name set on the container of the UI elements</td></tr>\\n<tr><th>form</th><td>Boolean specifying whether to enable the integrated form that is displayed on the right side of the preferences.</td></tr>\\n<tr><th>noscroll</th><td>Boolean specifying whether to allow scrolling.</td></tr>\\n<tr><th>index</th><td>The index of the navigation item determines its vertical position.</td></tr>\\n</table>\"\n}\n[/block]\n# Adding your own contents\n\nThe most straightforward way to populate your preference panel is by adding custom html and css. The following example loads css from dialog.css and adds a div element to the body of the dialog.\n\n```\nplugin.on(\"draw\", function(e){\n    // Insert css\n    ui.insertCss(require(\"text!./prefs.css\"), options.staticPrefix, plugin);\n\n    // Set some custom HTML\n    e.html.innerHTML = \"<div class='myCSS'>Hello World</div>\";\n});\n```\n\nHowever all current preference panes use the built-in form.\n\n# Using the built-in form\n\nYou can choose to use the built-in form or not, by enabling the `form` property when creating your panel. When this is enabled you can either create a flat form without any headings and without any navigational items, or you can create two-level headings in the navigation of which the 2nd level heading and the form elements will be displayed on the right.\n\nThe image below shows the use of headings on the left half and the use without headings on the right half.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/IzmaiderRxCxoa7j7xb3_headings-no-headings.png\",\n        \"headings-no-headings.png\",\n        \"2850\",\n        \"772\",\n        \"#61acf8\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## Widgets\n\nThe [form](doc:Form) object allows you to describe widgets declaratively. It adds one widget on each row and pairs it with a label. You determine the sequence of the widgets. In addition you can add custom areas that you manage yourself. \n\n*For information on the different widgets that are supported by the form [see this guide](doc:form)*\n\n### Two-Level Headings\n\nUse the `add()` method on your preference plugin to add headings and widgets to your preference panel. You can also let external plugins use this api to add additional elements to your preference panel.\n\nIn this example a top level navigational item called \"General\" is added at [position 100](doc:positioning-ui-elements). This top-level nav item is only shown in the navigation. This example has two sub headings called \"User Interface\" and \"Tree\" at position 20 and 40 respectively. Both have one widget, a checkbox and a textbox respectively.\n\n```\nprefPanel.add({\n   \"General\" : {\n        position: 100,\n        \"User Interface\" : {\n            position: 20,\n            \"Enable UI Animations\" : {\n                type: \"checkbox\",\n                setting: \"user/general/:::at:::animateui\",\n                position: 100\n            }\n        },\n        \"Tree\": {\n            position: 40,\n            \"Hidden File Pattern\" : {\n               type: \"textbox\",\n               setting: \"user/projecttree/@hiddenFilePattern\",\n               position: 100\n            }\n        }\n    }\n}, plugin);\n```\n\nWhich looks like this:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/pUkgrLySquiZVcfpuUTJ_2015-03-26_1058.png\",\n        \"2015-03-26_1058.png\",\n        \"1570\",\n        \"560\",\n        \"#64abfb\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n### No Headings\n\nThe alternative to using two-level headings is to not use any headings. This can be useful for when you have no need for categorization and is often combined with `noscroll` to set up a UI that fills the entire page - more on that below.\n\nTo get there call `plugin.form.add()` instead of `plugin.add()` and pass an array of widgets to it. In the example below there are two widgets, a button and a dropdown created. Make sure to add the \"flatform\" class to the `className` property in order for this to render correctly.\n\n```\nplugin.form.add([\n    {\n        type: \"button\",\n        title: \"Reset to Default Keybindings\",\n        caption: \"Reset to Defaults\",\n        width: 140,\n        onclick: function(){\n            doReset();\n        },\n        position: 90\n    },\n    {\n        title: \"Keyboard Mode\",\n        type: \"dropdown\",\n        setting: \"user/ace/@keyboardmode\",\n        items: [\n            { caption: \"Default\", value: \"default\" },\n            { caption: \"Vim\", value: \"vim\" },\n            { caption: \"Emacs\", value: \"emacs\" },\n            { caption: \"Sublime\", value: \"sublime\" }\n        ],\n        position: 100\n    }\n], plugin);\n```\n\nWhich looks like this:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/dzAJdqzFRBiJEseB3qcA_2015-03-26_1116.png\",\n        \"2015-03-26_1116.png\",\n        \"1566\",\n        \"310\",\n        \"#64acfc\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n### Custom Widgets\n\nA custom form widget allows you to add a row of any height to the form that you can fill in whichever way you want. The example below creates a custom widget with a `ui.bar` element as the container.\n\n```\n{\n    type: \"custom\",\n    title: \"Keybindings Editor\",\n    position: 120,\n    node: container = new ui.bar({\n        style: \"padding:44px 10px 10px 10px\"\n    })\n}\n```\n\nYou can then proceed to add other elements to the `container` either switching to html\n\n```\ncontainer.$html.innerHTML = \"<strong>Hello</strong>\";\n```\n\nor adding more cloud9 ui elements.\n\n```\ncontainer.appendChild(new ui.button({ caption: \"Hello\" }));\n```\n\n### Intro Widget\n\nThe intro widget is a custom widget that is commonly used by preference panes to set a heading and some supportive text.\n\nThis is the base widget that is used.\n```\n{\n    type: \"custom\",\n    title: \"Introduction\",\n    position: 1,\n    node: intro = new ui.bar({\n        height: 149,\n        class : \"intro\",\n        style: \"padding:12px;position:relative;\"\n    })\n},\n```\nYou can set the height and any style you want as well.\n\nThen populate the contents with html as follows.\n```\nintro.$html.innerHTML = \n    '<h1>Keybindings</h1><p>Change these settings to configure '\n    + 'how Cloud9 responds to your keyboard commands.</p>'\n    + '<p>You can also manually edit <a href=\"javascript:void(0)\" '\n    + '>your keymap file</a>.</p>'\n    + '<p class=\"hint\">Hint: Double click on the keystroke cell in the table below to change the keybinding.</p>';\n\nintro.$html.querySelector(\"a\").onclick = function(){ editUserKeys(); };\n```\n\nThat looks like this:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/a9mQxeKfTsalwb4epdO6_2015-03-26_1238.png\",\n        \"2015-03-26_1238.png\",\n        \"1570\",\n        \"286\",\n        \"#64acfc\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n# No Scroll\n\nSome preferences panels are not scrolling pages but instead keep a fixed height, with usually, a scrolling container such as a datagrid taking up the remainder of the space. A good example is the key bindings editor as well as the plugin manager.\n\nSet `noscroll` to `true` to prevent scroll. If you are using form elements, set the positioning of your custom element such that it takes the rest of the space. Here's how you can do that with a last element of a form.\n\n```\n{\n    type: \"custom\",\n    title: \"Keybindings Editor\",\n    position: 120,\n    node: container = new ui.bar({\n        anchors: \"269 0 0 0\"\n    })\n}\n```\n\nThe anchors are set to a fixed distance from the top and then 0 pixels from the left right and bottom position.\n\n# Events\n\nA preference panel has three additional events added to it's life cycle. The first one we mentioned above already is the `draw` event. The other two are `activate` and `resize`\n\n### Activate\n\nThe `activate` event is fired every time the panel is selected in the navigation.\n\n```\nplugin.on(\"activate\", function(e) {\n    datagrid && datagrid.resize();\n});\n```\n\n### Resize\n\nThe `resize` event is fired every time the panel's width and/or height changes.\n\nplugin.on(\"resize\", function(e) {\n    datagrid && datagrid.resize();\n});","excerpt":"","slug":"preference-panel","type":"basic","title":"Preference Panel"}
The `PreferencePanel()` base class creates a new plugin that can be used to create a new section in the global preferences editor. Each section gets a top level item in the left side navigation and when activated will display a UI on the right side that allows users to configure something. # Creating a Preference Panel A basic preference panel is created like this: ``` var plugin = new PreferencePanel("Your Name", main.consumes, { caption: "Panel Title", form: true, index: 50 }); ``` And looks like this: [block:image] { "images": [ { "image": [ "https://files.readme.io/B6nCWDT4TSirMhcO0Eaj_2015-03-26_0941.png", "2015-03-26_0941.png", "1570", "402", "#64acfc", "" ] } ] } [/block] # Preference Panel Properties The following properties can be passed to the `PreferencePanel()` constructor. [block:html] { "html": "<table>\n<tr><th>caption</th><td>The caption of the navigation item</td></tr>\n<tr><th>className</th><td>A custom css class name set on the container of the UI elements</td></tr>\n<tr><th>form</th><td>Boolean specifying whether to enable the integrated form that is displayed on the right side of the preferences.</td></tr>\n<tr><th>noscroll</th><td>Boolean specifying whether to allow scrolling.</td></tr>\n<tr><th>index</th><td>The index of the navigation item determines its vertical position.</td></tr>\n</table>" } [/block] # Adding your own contents The most straightforward way to populate your preference panel is by adding custom html and css. The following example loads css from dialog.css and adds a div element to the body of the dialog. ``` plugin.on("draw", function(e){ // Insert css ui.insertCss(require("text!./prefs.css"), options.staticPrefix, plugin); // Set some custom HTML e.html.innerHTML = "<div class='myCSS'>Hello World</div>"; }); ``` However all current preference panes use the built-in form. # Using the built-in form You can choose to use the built-in form or not, by enabling the `form` property when creating your panel. When this is enabled you can either create a flat form without any headings and without any navigational items, or you can create two-level headings in the navigation of which the 2nd level heading and the form elements will be displayed on the right. The image below shows the use of headings on the left half and the use without headings on the right half. [block:image] { "images": [ { "image": [ "https://files.readme.io/IzmaiderRxCxoa7j7xb3_headings-no-headings.png", "headings-no-headings.png", "2850", "772", "#61acf8", "" ] } ] } [/block] ## Widgets The [form](doc:Form) object allows you to describe widgets declaratively. It adds one widget on each row and pairs it with a label. You determine the sequence of the widgets. In addition you can add custom areas that you manage yourself. *For information on the different widgets that are supported by the form [see this guide](doc:form)* ### Two-Level Headings Use the `add()` method on your preference plugin to add headings and widgets to your preference panel. You can also let external plugins use this api to add additional elements to your preference panel. In this example a top level navigational item called "General" is added at [position 100](doc:positioning-ui-elements). This top-level nav item is only shown in the navigation. This example has two sub headings called "User Interface" and "Tree" at position 20 and 40 respectively. Both have one widget, a checkbox and a textbox respectively. ``` prefPanel.add({ "General" : { position: 100, "User Interface" : { position: 20, "Enable UI Animations" : { type: "checkbox", setting: "user/general/@animateui", position: 100 } }, "Tree": { position: 40, "Hidden File Pattern" : { type: "textbox", setting: "user/projecttree/@hiddenFilePattern", position: 100 } } } }, plugin); ``` Which looks like this: [block:image] { "images": [ { "image": [ "https://files.readme.io/pUkgrLySquiZVcfpuUTJ_2015-03-26_1058.png", "2015-03-26_1058.png", "1570", "560", "#64abfb", "" ] } ] } [/block] ### No Headings The alternative to using two-level headings is to not use any headings. This can be useful for when you have no need for categorization and is often combined with `noscroll` to set up a UI that fills the entire page - more on that below. To get there call `plugin.form.add()` instead of `plugin.add()` and pass an array of widgets to it. In the example below there are two widgets, a button and a dropdown created. Make sure to add the "flatform" class to the `className` property in order for this to render correctly. ``` plugin.form.add([ { type: "button", title: "Reset to Default Keybindings", caption: "Reset to Defaults", width: 140, onclick: function(){ doReset(); }, position: 90 }, { title: "Keyboard Mode", type: "dropdown", setting: "user/ace/@keyboardmode", items: [ { caption: "Default", value: "default" }, { caption: "Vim", value: "vim" }, { caption: "Emacs", value: "emacs" }, { caption: "Sublime", value: "sublime" } ], position: 100 } ], plugin); ``` Which looks like this: [block:image] { "images": [ { "image": [ "https://files.readme.io/dzAJdqzFRBiJEseB3qcA_2015-03-26_1116.png", "2015-03-26_1116.png", "1566", "310", "#64acfc", "" ] } ] } [/block] ### Custom Widgets A custom form widget allows you to add a row of any height to the form that you can fill in whichever way you want. The example below creates a custom widget with a `ui.bar` element as the container. ``` { type: "custom", title: "Keybindings Editor", position: 120, node: container = new ui.bar({ style: "padding:44px 10px 10px 10px" }) } ``` You can then proceed to add other elements to the `container` either switching to html ``` container.$html.innerHTML = "<strong>Hello</strong>"; ``` or adding more cloud9 ui elements. ``` container.appendChild(new ui.button({ caption: "Hello" })); ``` ### Intro Widget The intro widget is a custom widget that is commonly used by preference panes to set a heading and some supportive text. This is the base widget that is used. ``` { type: "custom", title: "Introduction", position: 1, node: intro = new ui.bar({ height: 149, class : "intro", style: "padding:12px;position:relative;" }) }, ``` You can set the height and any style you want as well. Then populate the contents with html as follows. ``` intro.$html.innerHTML = '<h1>Keybindings</h1><p>Change these settings to configure ' + 'how Cloud9 responds to your keyboard commands.</p>' + '<p>You can also manually edit <a href="javascript:void(0)" ' + '>your keymap file</a>.</p>' + '<p class="hint">Hint: Double click on the keystroke cell in the table below to change the keybinding.</p>'; intro.$html.querySelector("a").onclick = function(){ editUserKeys(); }; ``` That looks like this: [block:image] { "images": [ { "image": [ "https://files.readme.io/a9mQxeKfTsalwb4epdO6_2015-03-26_1238.png", "2015-03-26_1238.png", "1570", "286", "#64acfc", "" ] } ] } [/block] # No Scroll Some preferences panels are not scrolling pages but instead keep a fixed height, with usually, a scrolling container such as a datagrid taking up the remainder of the space. A good example is the key bindings editor as well as the plugin manager. Set `noscroll` to `true` to prevent scroll. If you are using form elements, set the positioning of your custom element such that it takes the rest of the space. Here's how you can do that with a last element of a form. ``` { type: "custom", title: "Keybindings Editor", position: 120, node: container = new ui.bar({ anchors: "269 0 0 0" }) } ``` The anchors are set to a fixed distance from the top and then 0 pixels from the left right and bottom position. # Events A preference panel has three additional events added to it's life cycle. The first one we mentioned above already is the `draw` event. The other two are `activate` and `resize` ### Activate The `activate` event is fired every time the panel is selected in the navigation. ``` plugin.on("activate", function(e) { datagrid && datagrid.resize(); }); ``` ### Resize The `resize` event is fired every time the panel's width and/or height changes. plugin.on("resize", function(e) { datagrid && datagrid.resize(); });