生活随笔
收集整理的這篇文章主要介紹了
如何编写 Cloud9 JavaScript IDE 的功能扩展
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上周末我們?cè)贘SConf.eu發(fā)布了?Cloud9 IDE?,同時(shí)發(fā)布了對(duì)應(yīng)的GitHub項(xiàng)目。在4天時(shí)間里該項(xiàng)目得到340個(gè)人的關(guān)注和將近50個(gè)fork。Cloud9的口號(hào)是由"由Javascripters 為Javascripters創(chuàng)建的IED",這口號(hào)有點(diǎn)遞歸,它意味著你可以hack這個(gè)ide使它變得更強(qiáng)大。Cloud9項(xiàng)目開始之初就尤其注意考慮這點(diǎn)了;Cloud9中的每一個(gè)功能點(diǎn)都是一個(gè)擴(kuò)展(extension)。 在IED啟動(dòng)的時(shí)候我們用優(yōu)秀的? requireJS?庫(kù) 加載所有的擴(kuò)展。前端UI使用? ajax.org platform?(apf),apf 使我們輕松地模塊化Cloud9的用戶界面。下面開始詳細(xì)介紹怎樣為Cloud9編寫擴(kuò)展。
一個(gè)擴(kuò)展的生命周期是從它作為requireJS的模塊開始的。我將簡(jiǎn)述requireJS的基本語(yǔ)法,想深入了解requireJS請(qǐng)參考這個(gè)文 檔。一個(gè)擴(kuò)展會(huì)依賴其他的擴(kuò)展和一些核心模塊。我們將編寫一個(gè)給編輯器中選定的JSON代碼進(jìn)行格式化的擴(kuò)展。該擴(kuò)展依賴核心模塊:core/ide, core/ext, core/util 和編輯器管理擴(kuò)展:ext/editors/editors.讓我們稱該擴(kuò)展為formatjson,然后將其置于ext文件夾下。
01 require.def("ext/formatjson/formatjson",
05 ?????"ext/editors/editors",
06 ?????"text!ext/formatjson/formatjson.xml"],
07 ????function(ide, ext, util, editors, markup) {
09 return ext.register("ext/formatjson/formatjson", {
10 ????????//Object definition
jingxing05 翻譯于 昨天(12:55) 0人頂
頂?翻譯的不錯(cuò)哦!
require.def第一個(gè)參數(shù)標(biāo)識(shí)擴(kuò)展的名字,第二參數(shù)中 ide,ext ,util和 editors 代表傳入該擴(kuò)展依賴的對(duì)象引用,formatjson擴(kuò)展的第五個(gè)依賴是加載為一個(gè)文本的xml文件。?‘text!’ 語(yǔ)法告訴 requireJS 不要將參數(shù)引入的文件解析為 javascript,僅將其中的內(nèi)容作為文本返回即可。所有依賴加載完畢后將調(diào)用第三個(gè)參數(shù)代表的回調(diào)函數(shù),在回調(diào)函數(shù)中將我們的擴(kuò)展注冊(cè)到擴(kuò)展管理器 中,讓我們看看擴(kuò)展文件的結(jié)構(gòu)。 {name : "JSON Formatter",dev : "Your Name Here",alone : true,type : ext.GENERAL,markup : markup,hook : function(){},init : function(){},enable : function(){},disable : function(){},destroy : function(){}
} 屬性和方法詳解:
屬性 屬性名是否必須描述 name 必須 擴(kuò)展的名字,供管理器中顯示 dev 可選 開發(fā)者名字,供擴(kuò)展管理器中顯示,主要是表彰開發(fā)者的榮譽(yù) alone 可 選 Boolean值,標(biāo)識(shí)該擴(kuò)展是個(gè)獨(dú)立的擴(kuò)展還是某個(gè)擴(kuò)展的子擴(kuò)展 type 可 選 擴(kuò)展類型,現(xiàn)在只支持 ext.GENERAL和ext.EDITOR,這個(gè)屬性極有可能在未來(lái)版本中棄用 markup 可 選 String,該擴(kuò)展的UI定義的標(biāo)記文本 visible 可 選 Boolean值標(biāo)識(shí)該擴(kuò)展在加載時(shí)是否可見(jiàn),該屬性僅對(duì)?Panel 擴(kuò)展有效
jingxing05 翻譯于 昨天(13:25) 0人頂
頂?翻譯的不錯(cuò)哦!
方法 方法名 必須 描述 hook 可選 在擴(kuò)展注冊(cè)時(shí)調(diào)用該方法,允許你延遲該擴(kuò)展的初始化。?例如你可以添加一個(gè)菜單項(xiàng)來(lái)初始化該擴(kuò)展。?初始化的時(shí)候, markup 參數(shù)的值被解析然后調(diào)用 init方法。如果沒(méi)有定義hook方法,則擴(kuò)展注冊(cè)時(shí)會(huì)立即初始化。當(dāng)你指定hook后,就要自己全權(quán)負(fù)責(zé)擴(kuò)展的初始化。擴(kuò)展的初始化是由調(diào)用 ext.initExtension(_self);完成的,其中 _self 是.Panel 擴(kuò)展 一個(gè)個(gè)引用。對(duì)于panel hook函數(shù) 通常只有一單單的一個(gè)聲明:panels.register(this); init 必須 初始化時(shí)解析完UI markup標(biāo)記字符串后 調(diào)用該函數(shù)。使所有markup中引入的該擴(kuò)展的元素可用,并可以對(duì)應(yīng)到其正確的位置。在擴(kuò)展管理器中啟動(dòng)該擴(kuò)展時(shí)也會(huì)調(diào)用該函數(shù)。 對(duì)editor 型擴(kuò)展,第一個(gè)參數(shù)是tab page元素,指示該擴(kuò)展可以用之填充到自己的UI.Panel 對(duì) panel ,第一個(gè)參數(shù)應(yīng)該給this.panel傳一個(gè)在Cloud9 UI的panel元素 (通常是window元素)。
enable 必須 前端啟用該擴(kuò)展時(shí)調(diào)用。這個(gè)函數(shù)是通過(guò)在前端菜單中點(diǎn)擊某個(gè) panel擴(kuò)展時(shí)被立即調(diào)用的(例如點(diǎn)擊完某個(gè)菜單項(xiàng)后顯現(xiàn)勾勾的這個(gè)動(dòng)作)。 不要與在擴(kuò)展管理器中的啟用和禁用擴(kuò)展混淆,啟禁 擴(kuò)展調(diào)用的是?destroy和init方法 disable 必須? 前端停用擴(kuò)展時(shí)調(diào)用。這個(gè)函數(shù)是 通過(guò)在前端菜單中點(diǎn)擊隱藏 panel擴(kuò)展時(shí)被立即調(diào)用的 (例如點(diǎn)擊完某個(gè)菜單項(xiàng)后勾勾不顯示的這個(gè)動(dòng)作)。 不要與在擴(kuò)展管理器中的啟用和禁用擴(kuò)展混淆,啟 禁 擴(kuò)展調(diào)用的是 ?destroy和init方法 destroy 必須 注銷擴(kuò)展時(shí)調(diào)用。注銷時(shí)清除引入的UI元素,事件處理器,和其他狀態(tài)等。在擴(kuò)展管理器中禁用擴(kuò)展時(shí)調(diào)用。
jingxing05 翻譯于 昨天(14:41) 0人頂
頂?翻譯的不錯(cuò)哦!
實(shí)現(xiàn) Format JSON擴(kuò)展 好,現(xiàn)在我們已經(jīng)有了基本概念,讓我們開始真正來(lái)實(shí)現(xiàn) format json擴(kuò)展。首先完成我們需要屬性和方法。我將添加一nodes數(shù)組,其中包含該擴(kuò)展所需的所有UI元素。我們用hook方法來(lái)創(chuàng)建一個(gè)菜單來(lái)初始化 formatjson擴(kuò)展,并顯示一個(gè)格式化窗口接受用戶輸入的縮進(jìn)值。代碼如下:
{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方法中創(chuàng)建一個(gè)菜單依附到mnuEdit。mnuEdit是對(duì)編輯器菜單的全局引用。現(xiàn)在我們的UI元素的名字掛靠在全局命名空間下(可能會(huì)在將來(lái)的版本中變更)。Cloud9中可用的UI元素表如下,并指定了哪些擴(kuò)展添加了這個(gè)元素。
NameExtensionPurpose mnuFile 頂部菜單欄的 File 菜單 mnuEdit 頂部菜單欄的 Edit 菜單 mnuView 頂部菜單欄的 View菜單 mnuEditors view菜單的 editors mnuModes Window菜單的布局菜單 mnuPanels ext/panels/panels 頂部菜單欄的windows菜單 vbMain 布局的主vbox tbMain 主菜單欄 barMenu 菜單 barTools 主菜單欄的第一欄 sbMain 底部的狀態(tài)欄 mnuFile mnuFile winDbgConsole ext/console/console 控制臺(tái)面板 tabConsole ext/console/console 控制臺(tái)窗口的tab元素 winFilesViewer ext/tree/tree 樹面板 trFiles ext/tree/tree 樹面板中的樹元素
jingxing05 翻譯于 昨天(15:07) 0人頂
頂?翻譯的不錯(cuò)哦!
還有更多建好的元素。可以在各自的擴(kuò)展或通過(guò)DOM/XPath操作找到他們。例如在工具欄和狀態(tài)欄之間有一個(gè)hbox包含3個(gè)vbox元素。 <a:hbox><a:vbox /><a:vbox /><a:vbox />
</a:hbox> 可以用XPath選擇器來(lái)訪問(wèn)元素:
vbMain.selectSingleNode("a:hbox/a:vbox[2]"); 這條查詢將定位到hbox中的第二個(gè)vbox。這個(gè)vbox含有了打開的文件tab和控制臺(tái)面板。然后你可以像我們?cè)趂ormatjson擴(kuò)展中對(duì)菜單的處理方法一樣將你想要的元素添加到該vbox。
jingxing05 翻譯于 昨天(15:15) 0人頂
頂?翻譯的不錯(cuò)哦!
MarkupUI 標(biāo)記 然后format json 擴(kuò)展會(huì)彈出個(gè)窗口給用戶來(lái)設(shè)置縮進(jìn)的空格數(shù)。我們用aml標(biāo)記語(yǔ)法來(lái)創(chuàng)建這個(gè)窗口。我將aml代碼放到名為formatjson.xml的xml文件中,并在最外層添加了一個(gè)擴(kuò)展所需的根元素:a:application,看起來(lái)像這樣:
<a:application xmlns:a="http://ajax.org/2005/aml"><!-- Your UI markup here -->
</a:application> UI標(biāo)記可以包含html和 AML元素。我們使用AML的一個(gè)下拉列表spinner和兩個(gè)按鈕來(lái)描述對(duì)json格式化的窗口。
<a:windowid = "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 οnclick="winFormat.hide()">Done</a:button></a:hbox></a:vbox>
</a:window> 格式化按鈕綁定了onclick事件來(lái)調(diào)用我們擴(kuò)展的format方法,它傳入了spinner的值。這就是我們?cè)跀U(kuò)展中需要實(shí)現(xiàn)的方法,讓我們動(dòng)手吧。
jingxing05 翻譯于 昨天(15:34) 0人頂
頂?翻譯的不錯(cuò)哦!
自定義函數(shù) 格式化函數(shù)有一個(gè)參數(shù),來(lái)指定json中縮進(jìn)的空格數(shù)。首先獲取當(dāng)前選擇的代碼,如果選中的代碼為有效的json,則對(duì)其格式化,更新到當(dāng)前選中的代碼,否則給用戶一個(gè)錯(cuò)誤提示。
我們需要加載另一個(gè)依賴來(lái)完成該功能,就是ace編輯器的Range模塊。于是我在頂部將ace/Range添加到依賴列表中,然后調(diào)用參數(shù)"Range"。格式化函數(shù)看起來(lái)如下(我給每個(gè)部分添加了注解)。
{...format : function(indent){//獲取當(dāng)前編輯器var editor = editors.currentEditor;//從當(dāng)前編輯器獲取選中的對(duì)象var sel = editor.getSelection();//獲取當(dāng)前的文檔對(duì)象引用var doc = editor.getDocument();//獲取當(dāng)前選中對(duì)象的range對(duì)象var range = sel.getRange();//從range對(duì)象獲取選中的文本var value = doc.getTextRange(range);//嘗試將選中的文本轉(zhuǎn)換為JSON,并格式化 //然后再回轉(zhuǎn)為文本字符串,如果出現(xiàn)錯(cuò)誤則給用戶顯示錯(cuò)誤.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對(duì)象var end = doc.replace(range, value);//用格式化的值更新當(dāng)前選中的部分 sel.setSelectionRange(Range.fromPoints(range.start, end));
},...
} 我們的擴(kuò)展現(xiàn)在可以使用了,但讓我們?cè)偬砑狱c(diǎn)東西。
jingxing05 翻譯于 昨天(17:27) 0人頂
頂?翻譯的不錯(cuò)哦!
Key快捷鍵綁定 我希望使用快捷鍵來(lái)使用這個(gè)擴(kuò)展,window使用: Ctrl-Shift-J,mac用Command-Shift-J。Cloud9中用戶可以自行配置快捷鍵。要實(shí)現(xiàn)上述功能,還需幾個(gè)步驟。首先在 ext/keybindings_default文件中為我們的擴(kuò)展新添windows和mac的默認(rèn)鍵綁定部分。
..."ext" : {..."formatjson" : {"format" : "Ctrl-Shift-J" // Or "Command-Shift-J" for the mac file},...
}... 然后必須要讓快捷鍵管理器知道該擴(kuò)展對(duì)什么快捷鍵響應(yīng)和顯示什么UI元素。添加名為hotkeys和hotitems的hash表:
hotkeys : {"format":1},hotitems : {}, 現(xiàn)在你有兩種途徑為鍵綁定添加處理器了。直接的方式是在擴(kuò)展中添加響應(yīng)方法,方法的名稱與hotkeys中指定的名稱相同即可,此處就是“format”。因?yàn)槲覀兊膉son格式化擴(kuò)展有一個(gè)菜單來(lái)顯示快捷鍵,我更喜歡將響應(yīng)方法連接到菜單的onclick事件上,這樣當(dāng)我按下快捷鍵時(shí)這個(gè)方法被執(zhí)行。而且當(dāng)我使用快捷鍵時(shí)這個(gè)菜單按鈕應(yīng)該點(diǎn)亮。可以在hotitems哈希表中添加菜單項(xiàng)來(lái)達(dá)到目的:
this.hotitems["format"] = [this.nodes[0]]; 現(xiàn)在我們可以在Tools菜單下的Extendtion Manage中來(lái)激活該擴(kuò)展了,可以觀看下面這段視頻來(lái)看看,如何在3分鐘內(nèi)完成這個(gè)擴(kuò)展。( 視頻下載)
jingxing05 翻譯于 昨天(18:04) 0人頂
頂?翻譯的不錯(cuò)哦!
其他資源 When you need help with creating an extension 在你開發(fā)擴(kuò)展需要幫助的時(shí)候請(qǐng)到Cloud9的?Google Group?。可以向github的issue跟蹤issue tracker of GitHub提交任何你發(fā)現(xiàn)的問(wèn)題。Cloud9的所有開發(fā)者在Twitter上十分活躍。在擴(kuò)展Cloud9的路上祝你好運(yùn)。我都等不及要看你會(huì)擴(kuò)展出什么了。 ?我們非常樂(lè)意將你酷斃了的擴(kuò)展添加為Cloud9的子模塊,或者在Github上提交pull request。
玩得開心 !
總結(jié)
以上是生活随笔 為你收集整理的如何编写 Cloud9 JavaScript IDE 的功能扩展 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。