上周末我们在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编写扩展。

一个扩展的生命周期是从它作为requireJS的模块开始的。我将简述requireJS的基本语法,想深入了解requireJS请参考这个文 档。一个扩展会依赖其他的扩展和一些核心模块。我们将编写一个给编辑器中选定的JSON代码进行格式化的扩展。该扩展依赖核心模块:core/ide, core/ext, core/util 和编辑器管理扩展:ext/editors/editors.让我们称该扩展为formatjson,然后将其置于ext文件夹下。

01 require.def("ext/formatjson/formatjson",
02     ["core/ide",
03      "core/ext",
04      "core/util",
05      "ext/editors/editors",
06      "text!ext/formatjson/formatjson.xml"],
07     function(ide, ext, util, editors, markup) {
08  
09 return ext.register("ext/formatjson/formatjson", {
10         //Object definition
11 });
12  
13     }
14 );

jingxing05
翻译于 昨天(12:55)

0人顶

 翻译的不错哦!

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(){}
}

属性和方法详解:

属性

属性名 是否必须 描述
name 必须 扩展的名字,供管理器中显示
dev 可选 开发者名字,供扩展管理器中显示,主要是表彰开发者的荣誉
alone 可选 Boolean值,标识该扩展是个独立的扩展还是某个扩展的子扩展
type 可选 扩展类型,现在只支持 ext.GENERAL和ext.EDITOR,这个属性极有可能在未来版本中弃用
markup 可选 String,该扩展的UI定义的标记文本
visible 可选 Boolean值标识该扩展在加载时是否可见,该属性仅对 Panel 扩展有效

jingxing05
翻译于 昨天(13:25)

0人顶

 翻译的不错哦!

方法

方法名 必须 描述
hook 可选 在扩展注册时调用该方法,允许你延迟该扩展的初始化。 例如你可以添加一个菜单项来初始化该扩展。 初始化的时候, markup
参数的值被解析然后调用
init方法。如果没有定义hook方法,则扩展注册时会立即初始化。当你指定hook后,就要自己全权负责扩展的初始化。扩展的初始化是由调用
ext.initExtension(_self);完成的,其中 _self 是.Panel 扩展一个个引用。对于panel hook函数 通常只有一单单的一个声明:panels.register(this);
init 必须 初始化时解析完UI markup标记字符串后 调用该函数。使所有markup中引入的该扩展的元素可用,并可以对应到其正确的位置。在扩展管理器中启动该扩展时也会调用该函数。

对editor 型扩展,第一个参数是tab page元素,指示该扩展可以用之填充到自己的UI.Panel 对panel ,第一个参数应该给this.panel传一个在Cloud9 UI的panel元素 (通常是window元素)。

enable 必须 前端启用该扩展时调用。这个函数是通过在前端菜单中点击某个panel扩展时被立即调用的(例如点击完某个菜单项后显现勾勾的这个动作)。不要与在扩展管理器中的启用和禁用扩展混淆,启禁扩展调用的是 destroy和init方法
disable 必须  前端停用扩展时调用。这个函数是通过在前端菜单中点击隐藏panel扩展时被立即调用的(例如点击完某个菜单项后勾勾不显示的这个动作)。不要与在扩展管理器中的启用和禁用扩展混淆,启禁扩展调用的是 destroy和init方法
destroy 必须 注销扩展时调用。注销时清除引入的UI元素,事件处理器,和其他状态等。在扩展管理器中禁用扩展时调用。

jingxing05
翻译于 昨天(14:41)

0人顶

 翻译的不错哦!

实现 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元素表如下,并指定了哪些扩展添加了这个元素。

Name Extension Purpose
mnuFile 顶部菜单栏的 File 菜单
mnuEdit 顶部菜单栏的 Edit 菜单
mnuView 顶部菜单栏的 View菜单
mnuEditors view菜单的 editors
mnuModes Window菜单的布局菜单
mnuPanels ext/panels/panels 顶部菜单栏的windows菜单
vbMain 布局的主vbox
tbMain 主菜单栏
barMenu 菜单
barTools 主菜单栏的第一栏
sbMain 底部的状态栏
mnuFile
mnuFile
winDbgConsole ext/console/console 控制台面板
tabConsole ext/console/console 控制台窗口的tab元素
winFilesViewer ext/tree/tree 树面板
trFiles ext/tree/tree 树面板中的树元素

jingxing05
翻译于 昨天(15:07)

0人顶

 翻译的不错哦!

还有更多建好的元素。可以在各自的扩展或通过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
翻译于 昨天(15:15)

0人顶

 翻译的不错哦!

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
翻译于 昨天(15:34)

0人顶

 翻译的不错哦!

自定义函数

格式化函数有一个参数,来指定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
翻译于 昨天(17:27)

0人顶

 翻译的不错哦!

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
翻译于 昨天(18:04)

0人顶

 翻译的不错哦!

其他资源

When you need help with creating an extension 在你开发扩展需要帮助的时候请到Cloud9的 Google Group 。可以向github的issue跟踪issue tracker of GitHub提交任何你发现的问题。Cloud9的所有开发者在Twitter上十分活跃。在扩展Cloud9的路上祝你好运。我都等不及要看你会扩展出什么了。 我们非常乐意将你酷毙了的扩展添加为Cloud9的子模块,或者在Github上提交pull request。

玩得开心!

如何编写 Cloud9 JavaScript IDE 的功能扩展的更多相关文章

  1. 【javascript】html5中使用canvas编写头像上传截取功能

    [javascript]html5中使用canvas编写头像上传截取功能 本人对canvas很是喜欢,于是想仿照新浪微博头像上传功能(前端使用canvas) 本程序目前在谷歌浏览器和火狐浏览器测试可用 ...

  2. Javascript自定义事件功能与用法实例分析

    原文地址:https://www.jb51.net/article/127776.htm 本文实例讲述了javascript自定义事件功能与用法.分享给大家供大家参考,具体如下: 概述 自定义事件很难 ...

  3. 哪些JavaScript IDE最好用?

    阅读本文之前,分享大家一张图片,看图会发现JavaScript开发需求最高,占比达到42.84%,因此掌握JavaScript语言好工作就不愁啦,工欲善其事必先利其器,那么选择IDE来开发是至关重要的 ...

  4. JavaScript IDE 大盘点,让选择不再难

      文章来源:http://gcdn.gcpowertools.com.cn/showtopic-24110-1-3.html 阅读本文之前,分享大家一张图片,看图会发现JavaScript开发需求最 ...

  5. JavaScript IDE

    哪些JavaScript IDE最好用?   阅读本文之前,分享大家一张图片,看图会发现JavaScript开发需求最高,占比达到42.84%,因此掌握JavaScript语言好工作就不愁啦,工欲善其 ...

  6. ApplicationContext(四)BeanFactory 功能扩展

    ApplicationContext(四)BeanFactory 功能扩展 上节我们提到容器刷新的第二步初始化 BeanFactory 工厂并解析配制文件,但此时 BeanFactory 的功能还很简 ...

  7. ReportViewer工具栏功能扩展[手动设置打印/导出按钮]

    ReportViewer在IE11后打印按钮就存在兼容问题,火狐,谷歌也存在打印按钮显示的兼容性问题,本资料就是解决ReportViewer打印按钮显示的问题, 通过自己写脚本添加到DOM里面让所有浏 ...

  8. Javascript中暂停功能的实现

    <script language="javascript"> /*Javascript中暂停功能的实现 Javascript本身没有暂停功能(sleep不能使用)同时 ...

  9. VS功能扩展--扩展介绍

    使用Eclipse的朋友都知道Eclipse是一个完全可扩展的IDE,那么在windows程序开发时,我们常使用的IDE(Visual studio)是否具有功能的扩展性呢?毫无疑问,回答是肯定的.我 ...

随机推荐

  1. css3中单位px,em,rem,vh,vw,vmin,vmax的区别及浏览器支持情况

    原文地址: http://blog.csdn.net/jyy_12/article/details/42557241 px:绝对单位,页面按精确像素展示 em:相对单位,基准点为父节点字体的大小,如果 ...

  2. new(C# 参考)

    在 C# 中,new 关键字可用作运算符.修饰符或约束. new 运算符 用于创建对象和调用构造函数. new 修饰符 用于隐藏基类中被继承的成员. new 约束 用于在泛型声明中约束可能用作类型参数 ...

  3. solr安装笔记与定时器任务

    一:solr启动 目前solr最高版本为5.5.0版本,很多solr安装都是说将server文件copy到tomcat中,但是solr版本自带有jetty的启动方式 首先下载solr-5.5.0版本, ...

  4. MySQL中优化常用的查询sql语

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索 ...

  5. DIV+CSS常用的网页布局代码

    单行一列以下是引用片段:body { margin: 0px; padding: 0px; text-align: center; }#content { margin-left:auto; marg ...

  6. 关于Linux 下 Mysql 远程访问时出现的Access denied for user '用户名'@'IP地址' (using password:NO)

    大概是因为MySQL不允许远程访问时候不带密码吧,所以还是设定一个密码 如下这样做: 打开终端 ,即terminal的那个(RedHat5.x为例 在左上角(可能会移位)那个带着红帽的家伙点击,--- ...

  7. IIS7.5 由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面

    IIS7.5中将一网站应用程序池托管管道模式改为经典后,网站页面打不开,错误信息: 引用内容 HTTP 错误 404.2 - Not Found由于 Web 服务器上的“ISAPI 和 CGI 限制” ...

  8. 产生NaN

    1.数学运算失败  数字+undefind=NaN 2.数据类型转化失败产生NaN isNaN()检查 是不是一个有效数字,是NaN 返回 ture  ,正常数字返回false.

  9. 用nexus搭建maven私服

    首先介绍一下背景,公司访问外网有限制,项目组大部分人员不能访问maven的central repository,因此在局域网里找一台有外网权限的机器,搭建nexus私服,然后开发人员连到这台私服上 环 ...

  10. python核心编程(第二版)习题

    重新再看一遍python核心编程,把后面的习题都做一下.