Chen Yangjian's Blog

Carpe diem - Seize the day

MySQL 使用一二

| Comments

errno: 150

有个表用到外键,创建的时候老是报这个错误。 Google 后得知是外键声明与该外键所在的表中的声明不一致的缘故,改掉之后就好了。

小项目的好处是数据库迁移太方便了…… 更完美的是以前的用户们的数据我根本不必在意。 于是上个月底最后一天的下午鼓捣了一下 Worklog,现在可以支持 MySQL 和 Oracle 了。 代码有重用,前台不用改,学了三年的所谓 interface,终于派上点严肃的用场而非用来忽悠老师。

以上。

XHTML 2 介绍

| Comments

今天是五四青年节,左右无事,翻译 W3C 文章一篇。

via

====翻译的分割线====

本文是介绍性质的,不属于文档定义的范畴。

1.1 什么是 XHTML 2

XHTML 2 是个为互联网文档展示所设计的通用标记语言。因此,它并不尝试大而全, 满足每一个可能的标记习语,而是提供一个广为使用的元素集合, 以及可以通过在spandiv元素上使用classrole属性结合样式表单的可扩展性,和自带的初始属性集和。

1.1.1. 设计目标

在设计 XHTML 2 的过程中,奉行了一些设计主导思想来指引设计。包括:

  • 尽量通用的 XML:如果 XML 已有,就不再复制,而是使用已有的。
  • 更少的形式,更多的结构:页面形式交给样式表单去打理。
  • 更好的可用性:在 XML 的规范下,试着让 XHTML 易于书写,写就的文档易于使用。
  • 更好的可接入性:有人称之为 “为未来的自己设计” —— 文档设计尽量包容。
  • 更好的国际化:因为是互联网诶。
  • 更好的设备独立性:越来越多的新设备能上网了,比如电话、个人数字助理(PDA)、 桌面电脑、电视等等,意味着有必要存在一个允许你书写一次并在不同设备上分别以不同方式展现的设计, 而非为每个设备都弄个新的文档版本。
  • 更少的脚本:通过脚本实现功能对文档作者来说是一大困难,同时限制了可用以阅读该文档的客户端。 我们试着研究了目前的典型用例,并将它们包括在了标记语言中。
  • 与语义化网络整合:让 XHTML 2 能被语义化网络工具所处理。

1.1.2 向后兼容

因为早期的 HTML 版本都是专项语言,所以有必要保证新版本的向后兼容性,使得新的文档依然能够在老浏览器中可用。 但是,多亏了 XML 和样式表单,如此元素级别的向后兼容已经没有必要了,因为基于 XML 的浏览器 (在笔者写著此文时,已经意味着95%的在使用的浏览器)都能不更新即可解析新的标记语言。 许多 XHTML 2 的成果已经在现有的浏览器中存在了;许多,但不是全部:就像当初 formtable添加到 HTML 里头, 人们得等到新版本的浏览器出来才能使用这些功能一样,XHTML 的某些部分,主要是 XForms 和 XML 事件, 依然需要能够处理该功能项的客户端(出现)。

1.1.3 XHTML 2 与形式表现

最初的 HTML 是为了展现文档的结构而设计的,而非它的形式表现。 虽然以形式表现为目的的标签元素后来被浏览器产商加入到该语言中,HTML 依然又一颗结构化文档标记语言的心。 XHTML 2 将 HTML 带回到它的根本。将所有形式展现的标签去除,归入到样式表单中。 这带来了更好的弹性、可接入性,更好的设备独立性,以及因为样式表单比元素标签更强而带来的更强大的表现性。

1.1.4 XHTML 2 与链接

HTML 的早期版本依赖于客户端和其他文档解析器的自身的认知能力。虽然许多都与文档表现有关(见上文), 但大部分与处理文档间的关系有关 —— 即所谓的“链接”。

种种 W3C 和其他努力,比如最令人瞩目的 [XLINK], 试着建立一种定义链接文字的语法规范。悲剧的是,这些语法都未能满足 XHTML 的要求。 大家都还在上下而求索一个综合性的描述链接文意的语法。

HTML 标准指定小组认为如此语法,虽然很有用,但对定义 XHTML 2 来说并非必要。以下不晓得怎么翻译好:

Instead, this document is explicit in the characteristics of the elements and attributes that are used to connect to other resources. The Working Group has taken this course because 1) the problem with XHTML 2 is well bounded, 2) the general solution is slow in coming, and 3) it will be easier for implementors to support and users to rely upon.

与 XHTML 1 的主要区别

XHTML 2 希望被 HTML 和 XHTML 1 的著者们认同,同时更正 HTML 家族中早期版本的错误和不足,并为伺机改进。

最显著的改变有以下:

  • 更多的结构可能性
  • section 与 heading 不得不说的故事:先前的 HTML 文档结构需要从文档中的 heading 推测出来; 如果作者为了取得某些视觉效果错用了 heading 标签,那问题就大了。XHTML 2 允许你显式地用 section 和与它相对应的 h 来标明文档的结构,
  • 我想做条分割线:在 HTML 的前期版本中,hr 标签被用来分隔文档。回想一下,标签名 hr(Horizontal rule,水平直线) 非常误导人,因为一个 hr 一并不一定是水平的(在竖版文档中它是纵向的), 二并不一定是条直线(书籍经常使用其他印刷符例如三个直线排布的星号来作为分隔符,而样式表单也能让你做到这一点)。 为了突出该标签的结构化的本性,让它更广为使用,并使它不再误导人, hr 改名 separator
  • 换行符:先前 HTML 版本中,br标签用来让文本换行。在 XHTML 2 里头它将被 l 标签代替。该标签将需要换行的文本括起来。 除了一些为人熟知的好处之外,该标签还给予了更多的形式表现能力,例如自动显示行号,每行文字交替着色之类。
  • 段落结构:以前的 HTML 中,p 只能包含简单的文本。新版本中它有所增强,允许包含列表和表单,使得它更像人们所数值的“段落”。
  • 导航列表:XHTML 2 的制定有部分是基于对现有 HTML 的观察而做的拾遗补缺,例如目前通过脚本语言来实现的 HTML 没有的功能。 一个显著的组件是“导航列表”,由连接到网站其他部分的链接组成,横向、纵向,或者下拉。为了支持这种使用方式, XHTML 2 引入了导航列表标签 nl, 用来标记文档中相应的部分,并提供各种可能的表现风格。一个额外的优点是,辅助技术能够避过这些标签。
  • 图片:HTML img 标签有许多让人不爽的地方:只允许你指定一张图片资源,而不是提供后备; 唯一的后备选项就是 alt 文本,而它只是个属性,只能是文本,而不能标记扩展;而 longdesc 属性很麻烦并且很少有浏览器支持。

XHTML 2 采用了完全不同的方式。by taking the premise that all images have a long description and treating the image and the text as equivalents.

在 XTHML 2 里头任一标签都有个 src 属性,用以指定一个让浏览器载入的资源(例如图片)。如果该资源不可用(因为网络挂了,因为浏览器不知道怎么搞定该类型的资源,或者因为图片被浏览器关掉了),那么该标签就作为后备而采用。 Essentially the longdesc has been moved into the document, though this behavior also mimicks the fallback behavior of the object element. (To achieve the tooltip effect that some browsers gave with the alt attribute, as in HTML 4 you use the title attribute). - 类型:在 HTML 4 里头,srctype 属性用来提示客户端该资源的类型。在 XHTML 2 里头它不再是提示,而是强制。 - 表格:清理了,简化了,功能上还是一样的。 - Bi-directional text: rather than use an explicit element to describe bi-directional override, new values have been added to the dir attribute that allow bi-directional override on any element. (这个不懂) - 编辑:与其使用 insdel 来标记文档的更改历史, edit 属性能够用来标记文档中的任一标签来实现同样的事情。 - 链接们:HTML 3 里头,只有 a 标签能够作为超链接的源和目标。在 HTML 4 和 XHTML 1 里头, 任何元素可以作为超链接的目标,但是只有 a 可以作为源。 在 XHTML 2 里头任何标签都可以作为超链接的源,因为 href 现在可以作为任一元素的属性。所以举个例子,不用再 <li><a href=”home.html”>Home</a></li>, 现在可以写 <li href=”home.html”>Home</li>。虽然如此以来 a 显得很多余,但它还是被保留了下来。 - Metadata: the meta and link elements have been generalized, and their relationship to RDF [RDF] described. Furthermore, the attributes on these two elements can be more generally applied across the language. - Role: in order to aid adding semantics to documents, the role attribute has been added, along with an initial set of useful values, in order to classify the use of a particular element. For instance a paragraph may play the role of a note, and so may be marked up <p role=”note”>. - Events: event handling in HTML was restricted in several ways: since the event names were hard-wired in the language (such as onclick), the only way to add new events was to change the language; many of the events (such as click) were device-specific, rather than referring to the intent of the event (such as activating a link); you could only handle an event in one scripting language — it was not possible to supply event handlers in the same document for several different scripting languages.

XHTML 2 uses XML Events [XMLEVENTS] to specify event handling, giving greater freedom in the ability to handle events. Along with this, the script element has been renamed handler to indicate its different semantics.

  • Forms: HTML Forms were introduced in 1993, before the advent of the e-commerce revolution. Now with more than a decade of experience with their use, they have been thoroughly overhauled and updated to meet the needs of modern forms, in the shape of XForms [XFORMS], which are an integral part of XHTML 2.
  • Ownership where due: since HTML 4 was a standalone application, it defined many things which no longer need to be defined now that it is an XML application. For instance the definitions of whitespace are given by XML for input, and CSS for output; similarly, the definition of values of the media attribute are relegated to the relevant style sheet language.
  • Frames and Framesets: In HTML 4 multi-panel “pages” could be described using the frameset and frame elements. The Frames model is no longer defined in XHTML. Instead, if is defined through the separate [XFRAMES] specification.

====翻译了一半累了,总结一下====

我果然当不了翻译……

单从标记语言来说最显著的可能是 srchref 属性,从今后的 JavaScript 民工生涯来说最显著的可能是 XFormsXMLEvents。以上只是对该文的字面理解…… 具体背后标准如何我其实没有深究。

XHTML 2 离我们还很远,有多远?至少比 HTML 5 远。

学长们的书——《程序员的自我修养》

| Comments

我的博客估计看的人也没几个,但是鉴于新文章会被推送到 yo2.cn 的用户童鞋们那里,我就恬不知耻地广告一下。

《程序员的自我修养》前一阵在萝卜(俞甲子)的博客上就打过预告,书名估计出自周星驰《喜剧之王》中那本某斯基的《演员的自我修养》,但从定价¥65来看,似乎也会是一本镇宅砖头。

必须拜读一下。

又及,标题有装嫩之意。

最近二三事

| Comments

许久未更新,讲点近况

五一哪儿也没去,呆在杭州,去了下太子湾。时节不对其一,时候不对其二,于是改爬山。顺便去河坊街、延安南路南端那儿的百滋百特甜甜圈吃了一哈,当点心可以,很腻。次日下雨,宅家里看电影,Twilight、暮光之城。晚间重装系统,电脑待机回来老是没时间,于是装了 Windows 7,没想到还是一样。今天大扫除,抹了两回地板,进房间要拖鞋,晚上去看了 Wolverine。

大家都来玩 Tag Cloud

| Comments

Tag Cloud 即将标签按照其各自“重量”的大小个性化,给人以视觉上的冲击,有个传说中的大局观。我以为还是比较一目了然的。

要开始玩的话很简单,这里隆重推荐 Wordle

worklog.js.teen

WordPress 有个标签云插件,按照各自标签包含的文章数目的多少来衡量标签的重要与否,并通过设置字号,区分标签大小。我仿照这个在自己毕设里头做了一个山寨版,很不幸没能打动老师,就此按下不表。yo2.cn 自带的插件库里头可能就有,因为我在 est的博客上看到了,感兴趣的话也可以看该插件的作者的博客

让 Java 程序通过代理访问网络

| Comments

via

需要设置以下属性:

http.proxyHost (default: )
http.proxyPort (default: 80 if http.proxyHost specified)
http.nonProxyHosts (default: )

关于这些属性的详细文档

实际应用中的方式有两种,启动的时候指定,其一:

java  -Dhttp.proxyHost=myproxyserver.com  -Dhttp.proxyPort=80 MyJavaApp

在代码里头指定,其二:

demo.java
1
2
3
4
5
6
import java.util.Properties;
...
Properties systemSettings = System.getProperties();
systemSettings.put("http.proxyHost", "myProxyServer.com");
systemSettings.put("http.proxyPort", "80");
System.setProperties(systemSettings);

关于代理验证之类,请参阅原文。

Emacs 里头显示行号

| Comments

看了个 jQuery for Designers 的视频,觉得让 Emacs 也显示行号也是个不错的想法,于是开搞。 办法倒也简单,得益于 Emacs 的社区贡献的插件, 我只要选择 linum.el、lineno.el、setnul.el 等其中之一就行了, EmacsWiki 上有个关于行号的文档,可以看看。

然而选择虽多,它们都有各自的问题。lineno.el 加载很快,只更新被显示的区块的行号, 然而除此之外都很不合吾意,样式不好看,滚屏的时候刷新有延迟,等等;setnu.el 加载大文件 (比如 undergroud.txt,19226 行) 的时候很慢,Emacs 就僵在那儿了;linum.el 是我最满意的,样式也能凑合,加载速度也快。 不过就一个地方不太好,左手边行号的宽度它是计算出来的,行数较少的时候显示行号的区块很窄, 我觉得不好看,所以 linum-update-window 函数中计算显示格式的部分我加了一句:

(when (< w 6) (setq w 6))

不过根据 ChrisDone 的回复:

Putting the following in your .emacs yields almost the same result without modification of linum.el:

`(setq linum-format "%d ")`

Or you can set it as a function like the following if you’d like it right justified. The body of the function is modified from linum-0.9x.

(setq linum-format (lambda (line)

  (propertize (format (let ((w (length (number-to-string (count-lines (point-min) (point-max))))))
                      (concat "%" (number-to-string w) "d ")) line)
              'face 'linum)))

You can use ‘linum-before-numbering-hook’ to count and store the number of lines only once per update. Thus you can avoid the somewhat expensive ‘count-lines’ call for each updated line. And a more simplistic constant-width version of the above could look like: (setq linum-format "%6d ")

直接一点反而省事,反正超过 99999 行的文本文件我是不想用 Emacs 马上打开的…… 原谅我后来才注意到 linum-format 选项……

Designing for Evil

| Comments

最近在 Coding Horror 上看到的这篇文章,Designing for Evil

When you design your software, work under the assumption that some of your users will be evil: out to game the system, to defeat it at every turn, to cause interruption and denial of service, to attack and humiliate other users, to fill your site with the vilest, nastiest spam you can possibly imagine.

该文提到 Craigslist 与所谓黑客之间的无休止的争斗, 并引出上述的结论。这让我想到我前一阵做给同事们用的一个工作日志程序,姑且叫 Worklog 好了。

开发的原因很简单,组内每周需要向老大汇报一周工作进展及计划,原本的方式是 email,很是麻烦。 于是做了这个 Worklog,因为都是同事们使用,安全机制几乎没有,用户不需要登陆, 根据 IP 判断谁是谁(公司局域网固定 IP,并且有个机器编号),初次访问的时候设定名字, 之后就可以一直记录工作日志。

试运行第一天,全是叫 qwerty、asdf、1234 的,工作日志有 ................................''''''''''''\\\\\\\\\\\\\\\\---------.,,,,,,,,.||||||&&&&&&$$$$!!!@@@###^^^***、有 a'; DROP TABLE users;,有特长的有空的等等。

全组总共也就10来号人,大家都是同事,同样都有如此问题。

无怪乎时代杂志的所谓百大最具影响力人物网络调查背后的形同虚设的安全工作要 被别人耻笑了。

In early stages of the poll, Time.com didn’t have any authentication or validation – the door was wide open to any client that wanted to stuff the ballot box.

开始的时候,time.com 没有任何授权或者验证机制 —— 开门揖盗

Soon afterward, it was discovered that the Time.com Poll didn’t even range check its parameters to ensure that the ratings fell within the 1 to 100 range

不久后,还被发现 time.com 连投票范围都没有检查,用户提交的评分并没有被限制在 UI 显示的 1-100 的范围之内。

Shortly afterward, Time.com changed the protocol to attempt to authenticate votes by requiring a key be appended to the poll submission URL. The key consisted of an MD5 hash of the URL + a secret word (aka ‘the salt’). [hackers eventually] discovered that the salt [..] was poorly hidden in Time.com’s voting flash application. With the salt extracted, the autovoters were back online, rocking the vote.

再不久后,time.com 改了协议,试着去使用密钥。密钥是 URL 与一个密文的 MD5 算值。 结果,所谓黑客们发现该密文只不过藏在该投票 swf 程序里头。然后,自动投票机又复活了~

还有些后来的并没有考虑透彻的 13秒 限制之类,这里就不细说了。

总之,随时想着你的网站是给撒旦用的,就行了。

题外话,关于代码也有个金科玉律。“随时想着你的代码将给一个拿着沙鹰的暴徒维护,而且他还知道你的住址。”

jQuery for Designers

| Comments

proggit 或者 web_design.reddit 上经常会有写 Top 35 jQuery to make your site more user friendly 之类的所谓榜单。而 jQuery 4 Designers 则是其中的常客。

上面的教程都非常浅显详尽,还有视频…… 安装个 firebug 研究它的诸多实例(如简单的 BBC Radio 1 的 Zoom Tab,用的插件多了点的 Apple Store Slider),保管乃功力精进。

作为为数不多的我能看的比较懂比较透彻的“技术文”,我决定以后每周翻译一篇。

Coda Popup Bubbles

| Comments

via

=============以下正文翻译的分割线===============

Coda 是个 Mac 上的 Web 开发套装 —— 在我认识的设计师与开发者们里头很流行。Panic (Coda 的开发团队)也以他们敏锐的设计闻名。并且,Jorge Mesa 提出了鼠标悬停在下载图片上的时候像吞云吐雾般弹出一个提示框的需求

简单说该效果只是多个特效的简单封装。不过有几个些微处需要注意。

Coda Popup Bubble

如何解决问题

为了得到该特效,我们需要做以下事情:

  1. 有考虑 JavaScript 被关闭的情况的 HTML 代码。不过分的说,用 CSS 把弹出框隐藏掉就是了。
  2. 隐藏的弹出框使用层叠样式表单保证出现的时候是已经设计好的。
  3. 用 jQuery 实现鼠标移至与鼠标移出时的弹出特效。

最值得注意的地方就是:当你的鼠标移到弹出框上的时候,该事件会触发原图片的鼠标移出事件。我会详述如何保证这个问题不会影响到弹出框的实现。

我弄了个示范视频来演示怎么搞出这个效果。下面是我是怎么以及用什么做的。

演示视频Flash 版本

QuikeTime 版本的大约 23 兆,Flash 的是流媒体。

demo / 演示

HTML 代码

为了保证重用性,我把“触发者”与“弹出框”放在了一个 div 里头。触发者即用户鼠标移至时显示弹出框的目标元素。

demo.html
1
2
3
4
5
6
<div class="bubbleInfo">
  <img class="trigger" src="http://mysite.com/path/to/image.png" />
  <div class="popup">
    <!-- your information content -->
  </div>
</div>

CSS

实际需要的 CSS 其实并不多。当然,你的 HTML 代码如何对此肯定会有影响。演示视频用的是 Coda 网站上的版本,所以需要设定的 CSS 还是相当可观的。

我推荐的标配如下:

demo.css
1
2
3
4
5
6
7
.bubbleInfo {
    position: relative;
}
.popup {
    position: absolute;
    display: none; /* keeps the popup hidden if no JS available */
}

这样,弹出框就能以绝对定位放置在触发者旁了。

jQuery

为了实现特效,我们需要为弹出框实现如下动画效果。

Mouse Over

  1. mouseover(鼠标移至)事件触发时:重置弹出框的位置(因为弹出框弹出的时候网上偏移了,所以这是必须的)
  2. 弹出框的不透明度从 0 到 1,并将它的 CSS 属性 top 减 10px(实现往上移动的效果)
  3. 如果 mouseover 时间再度触发,而弹出框正在动画中 —— 无视
  4. 如果 mouseover 时间再度触发,而弹出框已经可见 —— 无视

Mouse Out

  1. 设置个倒计时来触发弹出框的隐藏功能(这能保证用户不慎移出的时候弹出框不会立即消失)
  2. 如果用以隐藏的倒计时已经设定,则重置(如此方可保证隐藏功能只会被触发一次)
  3. 时间到时,将弹出框的不透明度从 1 降到 0 并将它的 CSS top 属性继续减 10 (往上飘走……)
  4. 标记弹出框已经隐藏

The ‘Trick’

一开始有个恼人的地方我不知道怎么解决。每次我将鼠标从触发者移到弹出框上的时候,触发者都会触发一个 mouseout(鼠标移出)事件 —— 于是弹出框隐藏了。这个臭虫真要命。

我这已经有了解决办法。不过或许有别的,而且据我所知,Coda 网站的开发者们并不是这么按我这说的来的。

当前文所述的 mouseover 触发的时候,你需要重置 mouseout倒数计时。问题解决。

Complete Source Code

以下是完整代码,包括注释。

demo.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
$(function () {
  $('.bubbleInfo').each(function () {
    // options
    var distance = 10;
    var time = 250;
    var hideDelay = 500;

    var hideDelayTimer = null;

    // tracker
    var beingShown = false;
    var shown = false;

    var trigger = $('.trigger', this);
    var popup = $('.popup', this).css('opacity', 0);

    // set the mouseover and mouseout on both element
    $([trigger.get(0), popup.get(0)]).mouseover(function () {
      // stops the hide event if we move from the trigger to the popup element
      if (hideDelayTimer) clearTimeout(hideDelayTimer);

      // don't trigger the animation again if we're being shown, or already visible
      if (beingShown || shown) {
        return;
      } else {
        beingShown = true;

        // reset position of popup box
        popup.css({
          top: -100,
          left: -33,
          display: 'block' // brings the popup back in to view
        })

        // (we're using chaining on the popup) now animate it's opacity and position
        .animate({
          top: '-=' + distance + 'px',
          opacity: 1
        }, time, 'swing', function() {
          // once the animation is complete, set the tracker variables
          beingShown = false;
          shown = true;
        });
      }
    }).mouseout(function () {
      // reset the timer if we get fired again - avoids double animations
      if (hideDelayTimer) clearTimeout(hideDelayTimer);

      // store the timer so that it can be cleared in the mouseover if required
      hideDelayTimer = setTimeout(function () {
        hideDelayTimer = null;
        popup.animate({
          top: '-=' + distance + 'px',
          opacity: 0
        }, time, 'swing', function () {
          // once the animate is complete, set the tracker variables
          shown = false;
          // hide the popup entirely after the effect (opacity alone doesn't do the job)
          popup.css('display', 'none');
        });
      }, hideDelay);
    });
  });
});

Taking it Further

This effect could be perfected by changing the initial reset (popup.css()) code to read from the trigger element and approximate it’s position. In my example, I’ve hardcoded it because I only have one on the page - but you may want to use this effect several times across your page.