在Eclipse RCP中集成HTML/CSS/Javascript (Integrate HTML/CSS/Javascript in Eclipse RCP)

新项目对UI的要求很高,产品负责人常常要求实现比较Fancy的功能。基于Eclipse RCP平台,用SWT/JFace实现起来比较麻烦,而且组里人手也不够,逼得我们常常要找替代方案。

Eclipse RCP虽然在Look & Feel上有所提高,但它的强项且不是前端,而是在于代码组织(模块,服务),功能扩展等方面。但如果能在RCP环境中集成Web前端的技术(HTML/CSS/Javascript),那实现这些Fancy的功能就容易的多。顺着这个思路我做了些实践,做了一个小页面,可以选择本地图片,再做PS处理。

webkit_sample

基本方案 – 使用Browser控件

SWT支持Browser控件,到3.7M2之后开始支持各平台下WebKit。各平台对WebKit要求不同,要参考SWT FAQ。我的体会是Mac(Safari),Linux平台(GTK+ WebKit)很好,Windows比较差。此控件也支持MOZILLA(比较旧的版本),但效果很差,很多CSS库无法运行。(本文多在Linux下WebKit的实践。)

首先要嵌入Browser,

之后,Browser就会显示Google主页的内容。

本地的HTML/CSS/JS文件

当然我们不是要做真正的浏览器,目标是使用本地的文件。实现思路也很清楚,就是要访问RCP Bundle里的文件。RCP也是支持的,可以用如下代码。

假设有如下目录结构:

web_folder

但这里要注意一个问题,我们的HTML常常会用到JS或CSS等外部文件。如果这些文件全都打包在Jar文件里,HTML文件内容可以被正常访问,但CSS等就无法被引用了。

解决的方法也很简单,就是不打包这部分文件,可以使用Feature加Fragment的方法。

code_structure

webkit_test是Host Plugin, webkit_test_webfiles是它的Fragment,webkit_test_feature是包括这两个Plugin的Feature。在Feature的设置中,打开“Unpack这个Fragment在安装时”。这样就可以得到一个Folder而不是Jar。

feature_setup

如何和Java代码互通呢?

这是个大问题。用了HTML,那我们要不要写个Server或者某个嵌入式的Server呢?如果需要,方案就会比较复杂,毕竟RCP还是专注于桌面端的(虽然有RAP,那是后话)。但当我发现BrowserFunction后,这个问题就简单了。

假如,HTML想通过一个函数得到RGB中红、绿、蓝的值,这些值却是在SWT的Text中输入的。函数分别是r(), g(), b().

在RCP的Java代码中,

BrowserFunction构造的第一个入参是Browser Instance,第二个是函数名。这可以大大扩展JS的能力。

那SWT可以控制Brower吗?比如调用JS里的Function。答案也是可以的。首先Browser提供了很多的Listener,让SWT捕获各种事件,此外可以直接用Browse.excute()来执行JS Function。

比如JS中定义了draw()函数,Java代码就可以用如下代码来调用 。

总结

在Sample中,我集成了Two.js,jquery, jquery-ui和AlloyImage.js, 实现了一些图片选择处理的功能,Webkit都能工作良好,让我惊艳,也让我坚信这个方向探索的潜力。但也遇到了不少问题,如Resize时页面的刷新问题,如何调试HTML页面,跨平台问题等,还需要更多时间的探索。Sample的代码在GitHub上,在Ubuntu 13.04, Mac OS X 10.8上都可以工作良好。

jQuery选择器(Selector)总结

最喜欢jQuery网站上的一句话”Write Less, Do More”。除了有非常丰富的函数可以选用以外,它的选择器也是非常强大,确实大大的提高的生产效率。今天就把这些有用的选择器好好总结一下。

jQuery的选择器可以归为三类:基本CSS选择器位置选择器还有自定义选择器

  • 基本选择器又被称为“查找选择器”,用来找到DOM中的各种元素。
  • 位置和自定义选择又被称为“过滤选择器”,因为它可以过滤出一个元素的集合。

下面就分类看看这几种选择器的使用方法。

基本CSS选择器(Basic CSS Selectors)

基本选择器的很多语法很像CSS,很容易记忆。

语法描述
*匹配任意元素
E匹配名为E的元素
E F匹配名为F的元素,且是E元素的后代(可以不是直接后代)
E>F匹配名为F的元素,且是E元素的直接后代
E+F匹配名为F的元素,且F元素前一个元素名为E
E~F匹配名为F的元素,且F元素前面有名为E的元素
E:has(F)匹配名为E的元素,且E元素至少有一个元素为F
E.c匹配名为E且属于类c的元素
E#i匹配名为E且其id为i的元素
E[a]匹配名为E的元素且其有属性a
E[a=v]匹配名为E的元素且其属性a的值为v
E[a^=v]匹配名为E的元素且其属性a的值以v开始
E[a$=v]匹配名为E的元素且其属性a的值以v结尾
E[a*=v]匹配名为E的元素且其属性a的值包含v

位置选择器(Positional Selectors)

这类选择器是基于元素之间位置关系的,而且可以和任意的基础选择器一起使用。

语法描述
B:first选择selector B选出元素的第一个
B:last选择selector B选出元素的最后一个
B:first-child过滤selector B选出元素中是第一孩子的
B:last-child过滤selector B选出元素中是最后一孩子的
B:only-child过滤selector B选出元素中是唯一孩子的
B:nth-child(n)过滤selector B选出元素中是第n个孩子的
B:nth-child(odd|even)过滤selector B选出元素中是奇位或偶位孩子
B:nth-child(Xn+Y)过滤selector B选出元素的序号满足Xn+Y的。
B:even过滤selector B选出元素序号是偶数的
B:odd过滤selector B选出元素序号是奇数的
B:eq(n)过滤selector B选出元素序号是n的
B:gt(n)过滤selector B选出元素序号大于n的
B:lt(n)过滤selector B选出元素序号小于n的

自定义选择器(Custom Selectors)

语法描述
B:animated过滤出B选出元素中在jQuery动画函数控制的
B:button过滤出B选中元素中所有的button
B:checkbox过滤出B选中元素中所有的checkbox
B:enabled过滤出B选中元素中所有处于enabled状态的
B:file过滤出B选中元素中属于input[type=file]
B:header过滤出B选中元素是header type的h1~h6
B:hidden过滤出B选中元素的状态是隐藏的
B:image过滤出B选中元素是input[type=image]
B:input过滤出B选中元素是input, select, textarea和button
B:not(f)过滤出B选中元素不满足selector f的。
B:parent过滤出B选中元素有不为空的孩子
B:password过滤出B选中元素是input[type=password]
B:radio过滤出B选中元素是input[type=radio]
B:reset过滤出B选中元素是input[type=reset]或button[type=reset]
B:selected过滤出B选中元素是处于selected状态的
B:submit过滤出B选中元素是input[type=submit]或button[type=submit]
B:text过滤出B选中元素是input[type=text]
B:visible过滤出B选中元素是处于可见状态的

使用jQuery获得Input的值

jQuery可以非常方便的取到网页里标准input的值。我们主要使用val()方法,用几个例子说明一下。

Text Input

HTML

JavaScript

Select Input

HTML

JavaScript

selectedVal可能是option_one/option_two/option_three.

当多选的情况时,我们可以得到所有selected items的value的数组,如:

HTML

JavaScript

CheckBox Input

HTML

JavaScript

如果没有Box selected, checkValue是一个空串。

Radio Input

HTML

JavaScript

 

JavaScript里的变量作用域

JavaScript的确有很多和C-like编程语言不一样的地方,就比如简章的变量作用域。让写惯了C++/Java的我很不习惯。

C/C++/Java里的变量作用域被称为block scope, 也就是块作用域。但JavaScript里可不一样,它的作用域称为function scope-函数域。简单点说,就是变量不管在哪声明,在整个函数范围内是可见的。

举个例子先:

怎么样,是不是有点别扭?j, k在for block之外,在function block之内就可以被访问。

那如果是下面这个函数呢,

这个也是正确的,它等价于:

简单的说,就是变量像是被提到函数开始的地方声明,这被称为hoisting(informally).

所以JavaScript不能像C/C++/Java那样,在使用变量时才就近声明该变量,反而应该为了避免这种默认提前声明所产生的误解,自己手动把变量声明写到函数开始的地方。唉,不爽! :cry: