上週末咱們在JSConf.eu發佈了 Cloud9 IDE ,同時發佈了對應的GitHub項目。在4天時間裏該項目獲得340我的的關注和將近50個fork。Cloud9的口號是由"由Javascripters 爲Javascripters建立的IED",這口號有點遞歸,它意味着你能夠hack這個ide使它變得更強大。Cloud9項目開始之初就尤爲注意考慮這點了;Cloud9中的每個功能點都是一個擴展(extension)。在IED啓動的時候咱們用優秀的 requireJS 庫加載全部的擴展。前端UI使用 ajax.org platform (apf),apf 使咱們輕鬆地模塊化Cloud9的用戶界面。下面開始詳細介紹怎樣爲Cloud9編寫擴展。javascript 一個擴展的生命週期是從它做爲requireJS的模塊開始的。我將簡述requireJS的基本語法,想深刻了解requireJS請參考這個文 檔。一個擴展會依賴其餘的擴展和一些核心模塊。咱們將編寫一個給編輯器中選定的JSON代碼進行格式化的擴展。該擴展依賴核心模塊:core/ide, core/ext, core/util 和編輯器管理擴展:ext/editors/editors.讓咱們稱該擴展爲formatjson,而後將其置於ext文件夾下。html
|
![]() jingxing05
|
require.def第一個參數標識擴展的名字,第二參數中 ide,ext ,util和 editors 表明傳入該擴展依賴的對象引用,formatjson擴展的第五個依賴是加載爲一個文本的xml文件。 ‘text!’ 語法告訴 requireJS 不要將參數引入的文件解析爲 javascript,僅將其中的內容做爲文本返回便可。全部依賴加載完畢後將調用第三個參數表明的回調函數,在回調函數中將咱們的擴展註冊到擴展管理器 中,讓咱們看看擴展文件的結構。
{ name : "JSON Formatter", dev : "Your Name Here", alone : true, type : ext.GENERAL, markup : markup, hook : function(){}, init : function(){}, enable : function(){}, disable : function(){}, destroy : function(){} } 屬性和方法詳解:node 屬性
|
![]() jingxing05
|
方法
|
![]() jingxing05
|
實現 Format JSON擴展好,如今咱們已經有了基本概念,讓咱們開始真正來實現 format json擴展。首先完成咱們須要屬性和方法。我將添加一nodes數組,其中包含該擴展所需的全部UI元素。咱們用hook方法來建立一個菜單來初始化 formatjson擴展,並顯示一個格式化窗口接受用戶輸入的縮進值。代碼以下: { name : "JSON Formatter", dev : "Ajax.org", alone : true, type : ext.GENERAL, markup : markup, nodes : [], hook : function(){ var _self = this; this.nodes.push( mnuEdit.appendChild(new apf.item({ caption : "Format JSON", onclick : function(){ ext.initExtension(_self); _self.winFormat.show(); } })) ); }, init : function(amlNode){ this.winFormat = winFormat; }, enable : function(){ this.nodes.each(function(item){ item.enable(); }); }, disable : function(){ this.nodes.each(function(item){ item.disable(); }); }, destroy : function(){ this.nodes.each(function(item){ item.destroy(true, true); }); this.nodes = []; this.winFormat.destroy(true, true); } } 在hook方法中建立一個菜單依附到mnuEdit。mnuEdit是對編輯器菜單的全局引用。如今咱們的UI元素的名字掛靠在全局命名空間下(可能會在未來的版本中變動)。Cloud9中可用的UI元素表以下,並指定了哪些擴展添加了這個元素。
|
![]() jingxing05
|
還有更多建好的元素。能夠在各自的擴展或經過DOM/XPath操做找到他們。例如在工具欄和狀態欄之間有一個hbox包含3個vbox元素。
<a:hbox> <a:vbox /> <a:vbox /> <a:vbox /> </a:hbox> 能夠用XPath選擇器來訪問元素: vbMain.selectSingleNode("a:hbox/a:vbox[2]"); 這條查詢將定位到hbox中的第二個vbox。這個vbox含有了打開的文件tab和控制檯面板。而後你能夠像咱們在formatjson擴展中對菜單的處理方法同樣將你想要的元素添加到該vbox。 |
![]() jingxing05
|
MarkupUI 標記而後format json 擴展會彈出個窗口給用戶來設置縮進的空格數。咱們用aml標記語法來建立這個窗口。我將aml代碼放到名爲formatjson.xml的xml文件中,並在最外層添加了一個擴展所需的根元素:a:application,看起來像這樣: <a:application xmlns:a="http://ajax.org/2005/aml"> <!-- Your UI markup here --> </a:application> UI標記能夠包含html和 AML元素。咱們使用AML的一個下拉列表spinner和兩個按鈕來描述對json格式化的窗口。 <a:window id = "winFormat" title = "Format JSON" center = "true" modal = "false" buttons = "close" kbclose = "true" width = "200"> <a:vbox> <a:hbox padding="5" edge="10"> <a:label width="100">Indentation</a:label> <a:spinner id="spIndent" flex="1" min="1" max="20" /> </a:hbox> <a:divider /> <a:hbox pack="end" padding="5" edge="10 10 5 10"> <a:button default="2" caption="Format" onclick = " require('ext/formatjson/formatjson').format(spIndent.value); "/> <a:button onclick="winFormat.hide()">Done</a:button> </a:hbox> </a:vbox> </a:window> 格式化按鈕綁定了onclick事件來調用咱們擴展的format方法,它傳入了spinner的值。這就是咱們在擴展中須要實現的方法,讓咱們動手吧。 |
![]() jingxing05
|
自定義函數格式化函數有一個參數,來指定json中縮進的空格數。首先獲取當前選擇的代碼,若是選中的代碼爲有效的json,則對其格式化,更新到當前選中的代碼,不然給用戶一個錯誤提示。 咱們須要加載另外一個依賴來完成該功能,就是ace編輯器的Range模塊。因而我在頂部將ace/Range添加到依賴列表中,而後調用參數"Range"。格式化函數看起來以下(我給每一個部分添加了註解)。 { ... format : function(indent){ //獲取當前編輯器 var editor = editors.currentEditor; //從當前編輯器獲取選中的對象 var sel = editor.getSelection(); //獲取當前的文檔對象引用 var doc = editor.getDocument(); //獲取當前選中對象的range對象 var range = sel.getRange(); //從range對象獲取選中的文本 var value = doc.getTextRange(range); //嘗試將選中的文本轉換爲JSON,並格式化 //而後再回轉爲文本字符串,若是出現錯誤則給用戶顯示錯誤. try{ value = JSON.stringify(JSON.parse(value), null, indent); } catch(e){ util.alert( "Invalid JSON", "The selection contains an invalid or incomplete JSON string", "Please correct the JSON and try again"); return; } //若是格式化成功則用格式化後值替換掉range對象 var end = doc.replace(range, value); //用格式化的值更新當前選中的部分 sel.setSelectionRange(Range.fromPoints(range.start, end)); }, ... } 咱們的擴展示在可使用了,但讓咱們再添加點東西。 |
![]() jingxing05
|
Key快捷鍵綁定我但願使用快捷鍵來使用這個擴展,window使用: Ctrl-Shift-J,mac用Command-Shift-J。Cloud9中用戶能夠自行配置快捷鍵。要實現上述功能,還需幾個步驟。首先在 ext/keybindings_default文件中爲咱們的擴展新添windows和mac的默認鍵綁定部分。 ... "ext" : { ... "formatjson" : { "format" : "Ctrl-Shift-J" // Or "Command-Shift-J" for the mac file }, ... } ... 而後必需要讓快捷鍵管理器知道該擴展對什麼快捷鍵響應和顯示什麼UI元素。添加名爲hotkeys和hotitems的hash表: hotkeys : {"format":1}, hotitems : {}, 如今你有兩種途徑爲鍵綁定添加處理器了。直接的方式是在擴展中添加響應方法,方法的名稱與hotkeys中指定的名稱相同便可,此處就是「format」。由於咱們的json格式化擴展有一個菜單來顯示快捷鍵,我更喜歡將響應方法鏈接到菜單的onclick事件上,這樣當我按下快捷鍵時這個方法被執行。並且當我使用快捷鍵時這個菜單按鈕應該點亮。能夠在hotitems哈希表中添加菜單項來達到目的: this.hotitems["format"] = [this.nodes[0]]; 如今咱們能夠在Tools菜單下的Extendtion Manage中來激活該擴展了,能夠觀看下面這段視頻來看看,如何在3分鐘內完成這個擴展。(視頻下載) |
![]() jingxing05
|
When you need help with creating an extension 在你開發擴展須要幫助的時候請到Cloud9的 Google Group 。能夠向github的issue跟蹤issue tracker of GitHub提交任何你發現的問題。Cloud9的全部開發者在Twitter上十分活躍。在擴展Cloud9的路上祝你好運。我都等不及要看你會擴展出什麼了。 咱們很是樂意將你酷斃了的擴展添加爲Cloud9的子模塊,或者在Github上提交pull request。
玩得開心!