[2008-07-24 07:49:47] 基于Picasa、PHP、AJAX的图片REST架构的简单实现 完结篇
//NOTOC
一如既往的前情提要:
*[blog:98|基于Picasa、PHP、AJAX的图片REST架构的简单实现(1)]
*[blog:99|基于Picasa、PHP、AJAX的图片REST架构的简单实现(2)]
*[blog:104|基于Picasa、PHP、AJAX的图片REST架构的简单实现(3)]
现在,服务器端的架设终于全部结束了,我们可以向服务器端同一个URL发送不同的Header请求,从而得到不同的反馈,REST简单说来也就是这么一回事。但很遗憾,URL只有一个,而且现在的浏览器并没有智能到可以通过超链接携带Header信息。我们只能通过附加手段达到目的,这个附加手段毫无疑问就是最后一位主角:Ajax。
====Step.3 客户端通过Ajax发送不同的Header请求====
准确的说我们利用的是[http://www.w3.org/TR/XMLHttpRequest/|XMLHttpRequest]对象,来对服务器发送不同的header请求。在W3C的定义中,不仅能够找到GET、POST,XMLHttpRequest支持的header类型一共包括
*GET
*POST
*HEAD
*PUT
*DELETE
*OPTIONS
这些Methods早在1999年就被定义于[http://www.ietf.org/rfc/rfc2616|RFC2616]里,到今天终于有了用武之地,真是可喜可贺。
var client = new XMLHttpRequest();
client.open("GET", "test.txt", true);
client.send();
这就是一个最简单的通过XMLHttpRequest发送请求的例子,同理可以将GET替换为其他Method。如果再加上监听状态变化的readystatechange,以及获得反馈的responseXXX,你会发现Ajax原来就是这么一回事。
这里为了使演示更加简单,使用JQuery的Ajax应用,以下是客户端代码:
$("img").each(function(){
var src = $(this).attr("src");
var aim = $(this);
$.ajax({
type: "GET",
url: src,
dataType : 'json',
success: function(json){
var title= "<p>这是一张名为「" + json.title + "」的相片<br />拍摄于:" + json.date + "<br />你可以访问:" + json.full + "来获得这张照片的全图。</p>";
aim.after(title);
aim.attr("alt",json.title);
}
});
return false;
});
这段代码遍历页面的所有图片,然后对这张图片的URL发送Get请求。发送的请求被我们编写的服务器端接收并取得对应的Json数据并返回,最终在客户端显示出来。
至此,这个最简单的图片REST架构便完成了,或许花这么大功夫最终只显示出一张图片来,还称之为构架,实在是小题大作。但最终能剔除所有冗余信息并实现HTML代码的最简化,我自己是玩的不亦乐乎的。
最后附上[http://cid-01e48df64f8bd957.skydrive.live.com/embedrowdetail.aspx/Source/photorest.7z|全部代码下载],也可以[lab:/photo_rest/|在线查看]。
=====付录:HTTP-Header最高绝技之翻墙术=====
其实在国内有很多AV国的网站上不了,并不是GFW的功劳,而网站为了避免拦截正常的访问,也很少会去封IP段。那么究竟为什么很多XX站不能访问呢,在HTTP-Header中,有一个叫Accept-Language的字段负责描述用户的系统语言,国内的Accept-Language值一般都是zh-cn,zh,AV国的很多网站都是通过识别这个值来区别用户。
那么很简单,更改Accept-Language伪装成AV国用户就可以了。
*Firefox下,地址栏访问about:config,然后搜索intl.accept_languages,将值由zh-cn,zh改为ja即可。
*IE下,工具——Internet选项——语言——将列表里的语言全部删除即可。
恩恩,这也只是一个技术问题,大家回去自行研究吧。
Read More
[2008-07-23 08:11:44] 基于Picasa、PHP、AJAX的图片REST架构的简单实现(3)
//NOTOC
前情提要:[blog:98|基于Picasa、PHP、AJAX的图片REST架构的简单实现(1)]
[blog:99|基于Picasa、PHP、AJAX的图片REST架构的简单实现(2)]
之前我们从远端获得了图片信息,但是这些和REST还是不沾边的。访问同一个URL,要想获得不同的信息,以目前的软硬件条件,最好的实现方法还是对HTTP Headers进行处理。所以这次的话题是——
====Step.2 服务器端接受不同的HTTP Headers返回不同的信息====
既然是服务器端,我们仍然采用PHP实现。
PHP对于Header信息的处理是很丰富的,常见的Header都已经存放在预定义变量$_SERVER中了。如果你对什么是Header还没有概念,可以在Firefox中安装一个[https://addons.mozilla.org/en-US/firefox/addon/3829|Live HTTP Headers]自行体验一下。
现在问题是:如此之多的Header,到底选择哪个或者哪几个来进行分析?用户的客户端语言,浏览器,IP等等,都是可以进行发挥的。这里为了简单说明问题,选择REQUEST_METHOD,HTTP_REFERER以及HTTP_X_REQUESTED_WITH来进行演示。
简单说明这三个参数:
*REQUEST_METHOD是页面的请求方法,也是目前REST实现的核心。
*HTTP_REFERER包含了用户的访问来源,一般是用户前一个访问的URL
*HTTP_X_REQUESTED_WITH则代表这是一个Xmlhttprequest请求,可以简单的看成是Ajax请求。
以下就是个人的随意发挥了,我所约定的有效服务器反馈包括:
*因为不涉及更新等操作,页面的请求方法只限于GET
*如果HTTP_REFERER存在,即说明用户在网页中或者通过链接点击访问照片,服务器返回照片的缩略图。
*如果HTTP_REFERER不存在,说明用户直接通过URL访问图片,服务器返回照片的全图。
*如果HTTP_X_REQUESTED_WITH存在,则说明用户在通过Ajax访问图片,这时返回一个Json格式的照片信息
形象一点用实例说明的话:
[http://allo.ave7.net/lab/photo_rest/photo/picasa/allovince/5213571636180988625/5213571644436936978|点击链接]会看到照片的缩略图,将这张照片的地址粘贴到浏览器地址栏直接访问的话,会看到照片的大图。而在[lab:/photo_rest/demo2.html|Demo]中,点击下面的按钮,则可以看到发送Ajax请求到同一个地址时的反馈。
最后还是附上服务器端的代码
require_once 'XML/Unserializer.php';
$Unserializer = &new XML_Unserializer();
$options = array('parseAttributes' => true);
$Unserializer->setOptions($options);
if($userid && $albumid && $photoid) {
$xml = "http://picasaweb.google.com/data/feed/api/user/".$_GET['userid']."/albumid/".$_GET['albumid']."/photoid/".$_GET['photoid'];
$status = $Unserializer->unserialize($xml,true);
//XML文件解析出错, 报错并退出
if (PEAR::isError($status)) {
die($status->getMessage());
exit;
}
//如果是一个AJAX访问,返回JSON描述
elseif($_SERVER['REQUEST_METHOD'] == 'GET' && $_SERVER['HTTP_X_REQUESTED_WITH']){
$pic = $Unserializer->getUnserializedData();
$part = explode('.',$pic['media:group']['media:content']['url']);
$json = json_encode(array(
'title' => $pic['media:group']['media:description']['_content'] ? $pic['media:group']['media:description']['_content'] : $pic['title']['_content'],
'date' => gmdate("F d Y H:i:s",strtotime($pic['updated'])),
'ext' => $part[count($part) -1],
'full' => $pic['media:group']['media:content']['url']
));
echo "($json)";
}
//HTTP_REFERER有无的区分
elseif($_SERVER['REQUEST_METHOD'] == 'GET' && $_SERVER['HTTP_REFERER']) {
$pic = $Unserializer->getUnserializedData();
header("Content-Type: image/jpeg");
curl_exec(curl_init($pic['icon']));
}
elseif($_SERVER['REQUEST_METHOD'] == 'GET' && !$_SERVER['HTTP_REFERER']) {
$pic = $Unserializer->getUnserializedData();
header("Content-Type: ".$pic['media:group']['media:content']['type']);
curl_exec(curl_init($pic['media:group']['media:content']['url']));
}
}
Read More
[2008-07-08 06:24:51] Vim配置外一篇(中文化、输入法、代码补全等)
Vim不愧是地球上最强的文本编辑器之一(不加之一恐怕Emacs用户会有意见- -),用Vim就像用Foobar一样,必须先调教一番,使之很好的符合自己的习惯才能达到最高的效率。
之前(前情提要:[blog:91|非中文系统下Gvim中文化解决方法])提到了Vim在其他语言Win32平台下的中文化实现,这里再做一些补充修订:
====多语言平台下的中文化实现====
首先是编码设置
"设置内核为UTF-8 set enc=utf-8 "设置解码顺序,这个顺序经测试可以很好的识别UTF-8,JIS,GBK set fencs=utf-8,ucs-bom,shift-jis,gb18030,gbk,gb2312,cp936然后设置界面
"设置内核为UTF-8 set enc=utf-8 "设置解码顺序,这个顺序经测试可以很好的识别UTF-8,JIS,GBK set fencs=utf-8,ucs-bom,shift-jis,gb18030,gbk,gb2312,cp936注意这里需要下载Vim的[http://vcd.gro.clinux.org|中文文档] ====IME输入法切换设置==== 在Win32环境下,Vim总是会自作聪明的自动切换到IME输入法。如果想要关闭自动切换,只需要设置
set iminsert=0 imsearch=0即可,但由于Vim提供了判断IME输入是否打开的multi_byte_ime,我们就可以更加智能的加一些处理
if has('multi_byte_ime')
"未开启IME时光标背景色
hi Cursor guifg=bg guibg=Orange gui=NONE
"开启IME时光标背景色
hi CursorIM guifg=NONE guibg=Skyblue gui=NONE
" 关闭Vim的自动切换IME输入法(插入模式和检索模式)
set iminsert=0 imsearch=0
" 插入模式输入法状态未被记录时,默认关闭IME
"inoremap <silent> <ESC> <ESC>:set iminsert=0<CR>
endif
以上设置可以记忆IME开启状态,并用不同的光标颜色提示当前输入法
====代码自动补全====
实现代码补全需要插件[http://ctags.sourceforge.net/|Ctags],将下载的Ctags解压到任意文件夹,然后将Ctags目录追加到环境变量里,之后我们进入项目所在根目录,运行Ctags -R,Ctags会解析所有项目文件并生成一个类似索引的tags文件,然后Vim运行补全时会从tags文件中取得数据。
当然如果更新了类函数定义,也要再次运行Ctags重新生成一次索引,这没有Eclipse那样华丽而且智能,但相比较那些专用IDE的体积和启动速度,Vim的表现仍然非常出色。
默认的代码补全快捷键是Ctrl+X Ctrl+O,可以使用插件[http://www.vim.org/scripts/script.php?script_id=1643|SuperTab]将快捷键与Tab键合并
====自定义快捷键====
Normal模式下可以很方便的用nmap设定自定义快捷键,不过可惜的是键盘上的键位也已经被占用的七七八八了。仅列举自己常用的两个作为例子:
nmap mm :%s/\r//g双击m键可以删除Win下生成的多余换行符CR(在Vim中可以看到蓝色的^M)
nmap tt :%s/^\([\s ]\+\)/ /g<cr>:%s/^更新时间.*\d$//g<cr>:%s/<a href.*<\/a>$//g<cr>:%s/\([\s ]*\n\)\+/\r\r/<cr>这个就比较复杂一点,双击t键实现对在起点下载的TXT文本进行排版并删除里面多余的广告等。 最终效果截图 [photo:/picasa/allovince/5220926002522558673/5220926248939178194|Vim of AlloVince] ====至懒人==== 好吧,贴出自己的配置,如果只想复制粘贴的同学可以各取所需,不过注意配置对应的插件
set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin
"设置工作目录为当前编辑文件的目录
set bsdir=buffer
set autochdir
"编码设置
set enc=utf-8
set fencs=utf-8,ucs-bom,shift-jis,gb18030,gbk,gb2312,cp936
"语言设置
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
set guifont=NSimSun:h10
set helplang=cn
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
"禁止生成临时文件
set nobackup
"搜索忽略大小写
set ignorecase
"搜索逐字符高亮
set incsearch
"行内替换
set gdefault
"始终显示行号
set nu!
"Tab键的宽度
set tabstop=4
"配色方案
colorscheme rainbow_fruit
"输入法设置
if has('multi_byte_ime')
"未开启IME时光标背景色
hi Cursor guifg=bg guibg=Orange gui=NONE
"开启IME时光标背景色
hi CursorIM guifg=NONE guibg=Skyblue gui=NONE
" 关闭Vim的自动切换IME输入法(插入模式和检索模式)
set iminsert=0 imsearch=0
" 插入模式输入法状态未被记录时,默认关闭IME
"inoremap <silent> <ESC> <ESC>:set iminsert=0<CR>
endif
"自动缩进
set ai!
"与Windows共享剪贴板
set clipboard+=unnamed
"Ctags的默认索引(需要插件Ctags)
set tags=$VIMRUNTIME/tags
"添加类型检测
filetype plugin indent on
"智能补全
set completeopt=longest,menu
"快捷键调用WinManager(需要插件WinManager)
let g:winManagerWindowLayout='FileExplorer'
nmap ff :WMToggle<cr>
nmap mm :%s/\r//g<cr>
"规范行首空格<cr>去除多余字符<cr>删除空白行<cr>规范行数
nmap tt :%s/^\([\s ]\+\)/ /g<cr>:%s/^更新时间.*\d$//g<cr>:%s/<a href.*<\/a>$//g<cr>:%s/\([\s ]*\n\)\+/\r\r/<cr>
"通过ctrl+方向键切换窗口(需要插件MiniBufExplorer)
let g:miniBufExplMapCTabSwitchBufs = 1
let g:miniBufExplMapWindowNavArrows = 1
====至更懒的人====
好吧,我放下载就是了…… [http://cid-01e48df64f8bd957.skydrive.live.com/embedrowdetail.aspx/Soft/Vim.7z|点击我]试试本Blog新增的下载功能吧,下载后解压到D:根目录,将Ctags目录(D:\Vim\vim71\plugin\ctags)加入环境变量即可
Read More
[2008-07-03 05:30:28] 官方同步插件Weave0.2 for Firefox3试用简评
[https://services.mozilla.com/|Weave]是Mozilla官方推出的浏览器同步项目,目前Firefox的同步插件[http://www.google.com/tools/firefox/browsersync/|Google Browser Sync]已经停止了开发,所以Firefox3.0中尚没有可用的同步插件,而Weave0.2的推出给FF3带来了一点希望。
安装,重启,试用……一个小时后我对Weave0.2的表现只有四个字可以形容:“惨不忍睹”。
首先是不友好,账户注册完毕到数据上传是完全没有问题的,但如果要下载同步数据,需要从邮件激活Weave服务,否则会一直提示连接服务器超时。基本的提示信息都起不到相应的向导作用,很难相信这是面向普通用户的产品。
然后是速度,Weave的同步不是像Google Browser Sync那样即时通信,而是退出FF后执行,而服务器又慢到不能忍,每次退出都要停顿30秒至数分钟,最可怕的是如果强行中断同步则会驻留一个 Firefox进程在内存中,真怀疑这不是官方插件,而是官方病毒- -|||
对于真正的同步功能也很难让人满意,用作测试的数据是1000个左右的书签,但同步过程中浏览器却严重拖慢,连正常的浏览都无法进行。不知道是服务器速度影响还是插件本身缺陷。
虽然Weave的野心很大,在预定开发的功能里还能看到插件同步等等让人浮想联翩的词汇,但在一个勉强能用的版本出现之前,需要同步功能的同学还是老老实实用FF2.0+Google Browser Sync吧
另外补充一个Firefox3 css hack之JQuery版
$.browser.mozilla && parseFloat($.browser.version) > 1.8用js获得的FF3的版本并不是软件开发版本3.0,而是Gecko内核版本1.9,很有意思 Read More
[2008-07-02 09:01:51] Django with mod_python环境搭建总结
[http://www.djangoproject.com/|Django]是经常与Rails相提并论的Python Web框架。但别的姑且不说,Django的环境搭建实在是不够亲切,简单的搭建过程中被雷到多次,特记录如下以供备忘。
====安装Django====
确保在Django安装之前已经安好了Python。
Django的最新Source可以从SVN获得:[http://code.djangoproject.com/svn/django/trunk/]
然后执行Django的setup.py
python setup.py install这里建议把python目录下的script文件夹加入环境变量 ====安装Apache的mod_python模块==== 虽然Django内置了Web服务器,但官方建议使用Apache的mod_python模块(- -|||那你还写他干什么) 安装好Apache后,从[http://www.modpython.org/]获得mod_python并安装(注意下载对应的python和Apache版本) 安装完毕后Apache目录下的modules文件夹内会有mod_python.so,在httpd.conf中写入
LoadModule python_module modules/mod_python.so将mod_python模块加载进来然后重启Apache ====创建Django项目==== 进入到在Apache的web页面目录下运行
django-admin.py startproject newtest至此我们的第一个Django项目便成功创建了,此时需要牢记项目名称『newtest』,因为真正的雷才刚刚开始- -。 ====基于Location的Mod_python访问配置==== 同样是修改httpd.conf,下面是来自Django官网的配置例子
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
PythonPath "['/path/to/project'] + sys.path"
</Location>
这里有三个参数需要注意:
#Location "/mysite/":这个参数是最终在url上反映出来的地址,也就是说目前我们访问Django项目所用的url就是http://localhost/mysite/,此参数可以自由更改,阿猫阿狗都可以。
#mysite.settings :这里的mysite必须是Django的项目名,即是刚才所创建的『newtest』,mod_python通过项目名来载入settings.py从而加载整个项目。此处设置不当会出现 ImportError: Could not import settings 'xxx.settings' (Is it on sys.path? Does it have syntax errors?): No module named xxx.settings 错误。
#['/path/to/project'] : 这个参数是最雷的,需要设置为相对于Django项目的父目录,也就是运行django-admin.py startproject时的所在目录。
因此我的Apache的htdocs目录位于D:\xampp\htdocs,最终设置结果为
<Location "/newtest/">
SetHandler python-program
PythonPath "sys.path+['D:/xampp/htdocs']"
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE newtest.settings
PythonDebug On
</Location>
然后重启Apache,访问http://localhost/newtest/,就可以看到亲切的django运行画面了。
====Hello Django====
终于可以开始第一个程序了,在Django项目下新建一个helloworld.py文件,内容为
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, Django.")
然后编辑urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^newtest/index', 'newtest.helloworld.index'),
)
最后重启Apache - -|||,注意Django的所有配置更新都是需要重启Apache的……通过http://localhost/newtest/index看看结果吧……
====吐槽====
总体来说Django的初始配置给我的印象是很不友好的,违反惯性思维的路径设置;每追加一个URL就要重启一次服务简直就是IIS的再现;而舍弃成熟的 Mod_rewrite模块不用,将所有Url统一通过PythonHandler用正则表达式解析后转发,比起强大的mod_rewrite来也未必能提高多少灵活性。或许作者有自己的考量,但作为一个快速开发的框架,Django在易用性上还需要更加琢磨吧。
PS:人生はいいことがあったり、悪いことがあったり、そのたびに喜んだり、悲しんだり、と言いうことだな
Read More
[2008-06-27 07:39:08] 基于Picasa、PHP、AJAX的图片REST架构的简单实现(2)
//NOTOC
前情提要:[blog:98|基于Picasa、PHP、AJAX的图片REST架构的简单实现(1)]
在前面展示的[lab:/photo_rest/demo3.html|DEMO]中,迫不及待的同学或许已经打开图片链接看过了,但很遗憾,这张图片并不存在于ave7.net的服务器上。我们首先要了解的是标题中的第一个主角Picasa。
来自Google的Picasa无疑是目前互联网最富有代表性的网络相册之一,而我选择Picasa而不是其他风头更劲的Flickr等等的原因有三:
#Google的服务很稳定
#API有很大发挥的余地
#强劲的客户端支持
Picasa的API文档在[http://code.google.com/apis/picasaweb/overview.html|这里],有兴趣的同学可以自行慢慢研究,关于本文所涉及的内容,我们只需要知道两点:
*Picasa的API是以RSS形式发布的
*在Picasa中准确定位一张图片需要三个参数:用户名、相册id、相片id
所以在上面的URL中,我们引入这三个参数,经由解析Picasa的API,就可以得到这张图片的所有信息:缩略图、原图、拍摄地点、标签……不一而足。而上述URL,则是我们提到的服务器端的请求分析器,用PHP来实现。
====Step.1 服务器端解析Picasa API并显示缩略图====
为了更好完成这个目标,这里涉及的知识有
#借助Apache的[http://httpd.apache.org/docs/2.2/rewrite/|URL Mod_Rewrite]模块来规整URL;
#利用PHP的[http://php.net/manual/en/book.curl.php|Curl]函数组来获取远端文件;
#用PHP的[http://pear.php.net/|PEAR]库中的[http://pear.php.net/package/XML_Serializer|XML_Serializer]来解析XML文件;
当然本文的重点不是详细讲解以上这些技术,编码上的细节问题会一笔带过,文章的核心始终是框架的搭建。
假设服务器PHP文件名为_loadpic.php,在mod_rewrite模块开启后,同目录下建立一个.htaccess文件,内容为
RewriteEngine On RewriteRule ^photo\/picasa\/(\w+)\/(\d+)\/(\d+) _loadpic.php?userid=$1&albumid=$2&photoid=$3_loadpic.php文件的内容为
//引入XML_Serializer
require_once 'XML/Unserializer.php';
$Unserializer = &new XML_Unserializer();
$Unserializer->setOptions(array('parseAttributes' => true));
if($userid && $albumid && $photoid) {
$xml = "http://picasaweb.google.com/data/feed/api/user/".$_GET['userid']."/albumid/".$_GET['albumid']."/photoid/".$_GET['photoid'];
$status = $Unserializer->unserialize($xml,true);
//XML文件解析出错, 报错并退出
if (PEAR::isError($status)) {
die($status->getMessage());
exit;
}
$pic = $Unserializer->getUnserializedData();
header("Content-Type: image/jpeg");
//Curl获得远端文件,Curl模块需要在PHP.ini的单独开启。
curl_exec(curl_init($pic['icon']));
}
}
而通过以上处理,我们达到了初步的目标:通过用户名、相册id、相片id三个参数定位一张照片,访问并解析Picasa API并获得我们需要的图片,然后显示出来。
[lab:/photo_rest/demo1.html|这里]是我们初步实现的结果。
Read More
[2008-06-26 04:16:49] 基于Picasa、PHP、AJAX的图片REST架构的简单实现(1)
HTML总是以链接地址的方式引入图片,尽管我们能在网页内嵌入以BASE64编码后的图片字符,但终究网页不是Word,传输方式决定了一个表意完善,可供用户选择性显示的HTML文本,要好过夹杂了臃肿不堪的媒体文件代码的文档。
但是传统的图片外置方式,带来了很多附加的问题
#服务器地址经常变动,容易过期
#如果采用缩略图,则必然产生一个新的与原图无关的URL,带来大量的冗余
#包含信息量不足,目前图片的所有附加信息(时间,拍摄地点,描述,分类等等)仅仅使用alt属性来对图片进行简单描述,远远不足以应对Web2.0网状的Tag关联描述
好在一切有了REST!
REST构架下的互联网是那样美好,所有的资源都有唯一的,表意良好的资源定位,无需再为页面间无意义的跳转发愁,资源检索的设计空前简单……
但这一切在现有的B/S模式基础上实现的话,代价是极为高昂的。现有的浏览器无法根据用户对单一超链接的点击判断用户的动作究竟是要访问,更新还是删除。同样的,服务器端也只能使用程序本身的入口来分析Header并判断用户究竟要干什么,而不是自动的将不同的Header请求分发到对应接口。
所以一个简单的REST构架实现,在现有的设备中,或者说在我的这个简单实现中,至少需要一个将超链接转换为客户端请求的分析器(AJAX),一个服务器端的请求分析器(PHP),一个将针对各种请求的转发器(PHP+Picasa API)。
而更重要的实现REST构架之前,我们需要做的不仅仅是考虑能不能实现,更需要权衡构架实现所需花销与实现后带来收益是否相符。
那么是否相符呢?还是用最终的结果来说话吧。
点击查看[lab:/photo_rest/demo3.html|DEMO]
Demo中实际的HTML代码只有一行
<img class="photo" src="photo/picasa/allovince/5213571636180988625/5213571644436936978"/>和普通的图片引入没有任何区别,但最终我们可以在页面上看到这张照片的标题、拍摄时间、原图等等附加信息,当然本Blog也是通过这种方法进一步扩展,搭配了华丽的Lightbox特效等等,有兴趣的同学可以自行翻看。 总之抛去最后的结果不谈,这个REST构架应用的最终结果就是,用户一切所要做的,只是提供上面这样的一行代码,而获得额外的相关信息以及丰富的扩展应用。 Read More
[2008-06-18 03:02:49] Firefox3插件推荐(Allo的Firefox专贴 part.2)
Firefox3.0正式版在经历的无数的Beta和RC之后终于发布了,比起1.5到2.0的升级来,这次的版本更新显然要受瞩目的多,大多数插件都能及时跟进让升级的花费减少了很多。
之前针对FF2.0写过[blog:83|一篇插件推荐]
本次在前文的基础上修修补补,权当放松
====浏览器内部改善====
* Mediawrap
** [http://addons.sociz.com/firefox/116/]
** [https://addons.mozilla.org/en-US/firefox/addon/1879]
** 功能:将Activex转换为FF能支持的插件
** 几乎是FF必备插件了,更新能及时跟上让人很欣慰
* XHTML Ruby Support
** [http://piro.sakura.ne.jp/xul/_rubysupport.html.en]
** [https://addons.mozilla.org/en-US/firefox/addon/1935]
** 功能:日文假名显示用Ruby标签支持
** 经常要接触日文的同学必备
* Fasterfox
** 非常遗憾,这次未能随FF3一同更新
====浏览器外观改善====
* Menu Editor
** [http://menueditor.mozdev.org/]
** [https://addons.mozilla.org/en-US/firefox/addon/710]
** 功能:自定义浏览器菜单栏显示项目
** 事实上菜单项目中日常能用上的也就那么几项而已,其他的让他随浮云去吧……
* Searchbar Autosizer
** [http://menueditor.mozdev.org/]
** [https://addons.mozilla.org/en-US/firefox/addon/1172]
** 功能:让搜索栏随输入拓宽
** 要节约空间
* Tiny menu
** [http://trac.arantius.com/wiki/Extensions/TinyMenu]
** [https://addons.mozilla.org/en-US/firefox/addon/1455]
** 功能:将长长的菜单栏折叠为一个小图标
** 还是要节约空间
====浏览器操作改善====
* Easy Dragtogo
** [http://addons.mozine.cn/firefox/700/]
** [https://addons.mozilla.org/en-US/firefox/addon/6639]
** 功能:鼠标拖拽手势浏览
** 之前一直在用Super Dragandgo,但很遗憾这次并未发布对FF3的更新,Easy DragToGo功能上相差无几,绝佳的替代品
* Tab Mix Plus
** [http://tmp.garyr.net/]
** [http://tmp.garyr.net/tab_mix_plus-dev-build.xpi]
** 功能:增强的标签页浏览
** 一直对Tab Mix Plus的资源占用感到不满,之前推荐了轻量级的Tab Mix Lite CE,但FF3发布之后标签页浏览这一块竟然全军覆没,目前这个Tab Mix Plus也是作者的开发版,但至少可解一时之急
* Flashgot
** [http://flashgot.net/]
** [https://addons.mozilla.org/en-US/firefox/addon/220]
** 功能:在FF中关联任意下载程序
** 曾被某人误认为是Flashget的陈旧版本- -|||,更新很勤快也很好用的插件,安装有下载工具的话必备
* Download Statusbar
** [http://downloadstatusbar.mozdev.org/]
** [https://addons.mozilla.org/en-US/firefox/addon/26]
** 功能:将FF的下载进程整齐的排列在底部
** 不希望每次下载弹出窗口的话,这是一个很好的解决方案
* IE View Lite
** [http://www.graysonmixon.com/extension/]
** [https://addons.mozilla.org/en-US/firefox/addon/1429]
** 功能:在图标和右键中添加一个View in IE的选项
** 最轻量级的IE View实现
====浏览内容改善====
* Adblock Plus
** [http://adblockplus.org/en/]
** [https://addons.mozilla.org/en-US/firefox/addon/1865]
** 功能:强大的广告拦截插件
** 可惜缺少符合国情的过滤规则
* Customize Google
** [http://www.customizegoogle.com/]
** [https://addons.mozilla.org/en-US/firefox/addon/743]
** 功能:玩转自己的google
** 最有用的仍然是google网页快照
* Autofill Forms
** [https://blueimp.net/mozilla/]
** [https://addons.mozilla.org/en-US/firefox/addon/4775]
** 功能:自动填写表单
** 不能从已经填写的内容自动学习稍显遗憾
====开发者用====
* Firebug
** [http://getfirebug.com/]
** [https://addons.mozilla.org/en-US/firefox/addon/1843]
** 功能:Js Debug利器
** 话说谁知道怎么让HTML在刷新时记住上次的位置
* Web Developer
** [http://chrispederick.com/work/web-developer/]
** [https://addons.mozilla.org/en-US/firefox/addon/60]
** 功能:Web开发必须
** 注意在Web Developer的主页上始终有提供多国语言版的,另外本博客做到了HTML和CSS完全通过校验无一警告-_,-
* Live HTTP Headers
** [https://addons.mozilla.org/en-US/firefox/addon/3829]
** 功能:查看header
** 还是太简单了点,只能作为Firebug console功能的辅助
* Search Status
** [http://www.quirk.biz/searchstatus/]
** [https://addons.mozilla.org/en-US/firefox/addon/321]
** 功能:在状态栏显示当前页面的PR和Alexa排名
** 作为开发工具来用的话,则方便的查看meta和robot.txt
顺便一提,IE下的对应工具也是存在的,当然质量难免要打个折扣- -
*Web Developer -> [http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d-4511-bb3e-2d5e1db91038&displaylang=en | IE Developer Toolbar]
*Firebug -> [http://www.my-debugbar.com/wiki/CompanionJS/HomePage | Companion.JS]
*Live HTTP Headers -> [http://www.blunck.se/iehttpheaders/download.html | ieHTTPHeaders]
*多版本IE并存: [http://www.my-debugbar.com/wiki/IETester/HomePage | IETester]
====离线工具====
* Sage-Too
** [http://sage.blat.co.za/]
** [https://addons.mozilla.org/en-US/firefox/addon/7263]
** 功能:Rss订阅
** Sage增强版,功能简洁实用
* Scrap Book
** [http://amb.vis.ne.jp/mozilla/scrapbook/]
** [https://addons.mozilla.org/en-US/firefox/addon/427]
** 功能:最好的网摘工具
** 如果能搭配相应网站就无敌了
* Gspace
** [http://amb.vis.ne.jp/mozilla/scrapbook/]
** [https://addons.mozilla.org/en-US/firefox/addon/427]
** 功能:将gmail作为网络硬盘使用
** 期待的功能是大文件自动拆分
* Google browser sync
** 功能:Google的浏览器同步插件
** 未能跟上,需要同步功能的可以参看[blog:101|官方同步插件Weave0.2 for Firefox3试用简评]
整体来说FF3.0是很让人满意的,虽然最关键的内存和启动没有明显区别,但细节之处的修改多不胜数,即使一个插件也不装,也足够平易近人了,所以2.0用户无需犹豫,可以立即升级。
Read More
[2008-06-04 09:05:16] Javasript Date对象的扩展、国际化、总结及其他
一个优秀的程序必须要兼顾I18n和L10N,但Javascript在Date处理这一方面做得很不友好,问题反映在以下几个方面:
#虽然Js也设置了UTC时间函数,但脚本运行时的时区是自动从系统获得的,且无法更改。而在实际应用中,往往需要接受一个非当前系统时区的时间数据进行转换,这时候Js的自作聪明就带来了许多麻烦。
#Js对日期的自动解析和格式化输出根据系统环境、浏览器环境不同,表现也不同,这主要反映在Date.parse和toLocaleString方法上,有兴趣的同学可以自行测试。
为了尽可能简便的改善Js的Date处理能力,这里只对Js的Date对象做了两个扩展
/**
* 获得当前时间的UTC时间戳
* @return {int} unix timestamp
*/
Date.prototype.getTimeUTC = function() {
return this.getTime() + this.getTimezoneOffset() * 60 * 1000;
}
/**
* 将当前操作的时间变更时区(主要用于转换一个其他时区的时间)
*
* @param {int} tzo 原时区 -12~13
* @param {int} tzo 目标时区 -12~13 默认为当前时区
*/
Date.prototype.changeTimezone = function(tzo,tzn) {
tzo = tzo * 60;
tzn = tzn ? tzn * 60 : -this.getTimezoneOffset();
this.setTime(this.getTime() - (tzo - tzn) * 60 * 1000);
}
至此,就可以基于这个扩展过的Js Date对象进行新的开发。
思路很简单,就是把任意格式任意时区的时间先通过changeTimezone方法转到和当前系统同一时区下,然后再对getTimeUTC生成的UTC Unix时间戳进行操作。
比如我要计算 +8 时区下 4 Jun 2008, 16:30时刻 与 +9 时区下的当前时刻相差的时间
//自动解析成unix时间戳
var p = Date.parse('4 Jun 2008, 16:30');
var time_parse = new Date(p);
//转换到要对比的时区
time_parse.changeTimezone(8,9);
var time_now = new Date();
//都转换为UTC进行对比
var der = time_now.getTimeUTC() - time_parse.getTimeUTC();
alert('相差' + parseInt(der / 1000 / 60) + '分钟');
当然有更简单的编码,但在复杂运用中理清思路更加不容易出错。
如果想要实现本Blog左侧栏XX天XX月前这样更人性化的提示,这里可以根据自己的需要做进一步扩展。实现的函数如下
/**
* 表示指定时间与现在的差值
*
* @param {int} t 所要比较的时间 unix timestamp (UTC)
* @param {int} n 作为标准的时间,默认为现在时刻 unix timestamp (UTC)
* @return {string} 对相差时间的表述
*/
Date.prototype.derTime = function(t,n) {
var n = n ? n : this.getTimeUTC();
function ms2min(ms) {
return parseInt(ms / 1000 / 60);
}
var der = ms2min(n - t);
var ba = der > 0 ? '前' : '后';
der = Math.abs(der);
var res = '';
if(der == 0) {
res = '刚刚';
}
else if(0 < der && der < 60) {
res = der + '分钟' + ba;
}
else if(60 <= der && der < 24 * 60) {
var min = der % 60 == 0 ? '' : String(der % 60) + '分钟';
res = String(parseInt(der / 60)) + '小时' + min + ba;
}
else if(der >= 24 * 60 && der < 24 * 60 * 31) {
res = String(parseInt(der / 60 / 24)) + '天' + ba;
}
else if(der >= 24 * 60 * 31 && der < 24* 60 * 365) {
res = String(parseInt(der / 60 / 24 / 31)) + '个月' + ba;
}
else if(der > 24 * 60 * 365) {
res = String(parseInt(der / 60 / 24 / 365)) + '年' + ba;
}
return res;
}
/**
* 解析一个时间字段与当前时间的差
* @param {string} i
* @param {int} 时区 -12~13
*/
function time_der(i,tz) {
var p = Date.parse(i);
if(!p) {
return i;
}
var time_parse = new Date(p);
if(tz != undefined) {
time_parse.changeTimezone(tz);
}
var time_now = new Date();
return time_now.derTime(time_parse.getTimeUTC());
}
Read More
[2008-05-30 08:49:56] 轻量级的Accordion With JQuery
Jquery的UI中是有Accordion的,200余行代码配合themes带来的负担,让使用前不可不慎重考虑。
仔细分析一下Accordion的动作其实很简单,顺序排列的N个元素,页面载入时只显示其中一个,点击某个元素时,展开当前元素并隐蔽其他。
那么配合JQuery强大的选择器,完全可以用几行代码打造自己的轻量级Accordion。
以本Blog的左边侧栏为例:
//页面载入时隐蔽除第一个元素外所有元素
$("#accordion > li > div + *:not(:first)").hide();
//对所有元素的标题绑定点击动作
$('#accordion > li > div').click(function(){
$(this).parent().parent().each(function(){
//隐蔽所有元素
$("> li > div + *",this).slideUp();
});
//展开当前点击的元素
$("+ *",this).slideDown();
});
总共不过7行,当然选择对象部分需要根据自己的情况灵活指定。
ASUS Eee,华硕又见华硕,难道我是ASUS控么- -|||
Read More
