2009年4月3日 星期五

JavaScript shell

2009年4月3日 星期五 0
寻找一个类似于ruby irb的工具来验证自己的js语法是否输出正确的结果,除了firebug之外,还有一款很酷的小工具,http://www.billyreisinger.com/jash/

用法:
1. 下载jash.js 和jash.css
2. 在页面加载jash.js 和 jash.css
3. 在页面上加这个链接:
Jash bookmarklet

然后点这个链接就可以调出shell窗口了。

2009年4月1日 星期三

为TextMate扩展全屏功能

2009年4月1日 星期三 0
今天看代码,感觉TextMate那个窗口太小了点,越看越不爽,就想把它弄成全屏的。于是搜索啊搜索啊搜索,终于让我找到一款很yd的小软件,叫megazoomer, 下载地址是:
http://ianhenderson.org/megazoomer.html
安装它之前还需要另一款小软件,叫SIMBL (SM?)
http://culater.net/software/SIMBL/SIMBL.php

下面来小讲一下安装步骤(非Mac用户就靠边吧,没你什么事):
1. 安装SIMBL
2. 安装megazoomer, 把.bundle文件放在/Library/Application Support/SIMBL/Plugins/目录下,如果没用这个目录就自己动手建。
3. 重启TextMate
4. command + 回车 激活这个软件,退出全屏也是一样的快捷键。 注意的是,TextMate只有在没用打开任何文件的时候才能使用这个功能。这可能是因为快捷键冲突的原因造成的,那么我们来修改其快捷键:

  1. 打开系统首选项,寻找 Keyboard + Mouse
  2. 然后选keyboard shortcut,点击左下角的 + (plus)按钮
  3. 然后下拉列表里选TextMate
  4. 在Menu Item里输入“Mega Zoom”
  5. 输入你的快捷键,比如: command(苹果键)+ F.
  6. 退出并且重启TextMate,则可以自由使用了。

Google Gears离线应用之实时判断系统是否离线

离线应用有不同的架构,我采用的架构需要在后台实时判断用户是否在线,也就是说,判断用户的网络是否通畅。 基本思路是:
1. 使用一个WorkerPool实时的向服务端发出请求
2. 把是否在线状态保存到浏览器数据库里供其他WorkerPool使用。

之下是代码:
1. 父WorkerPool, 负责在页面显示是否在线的图标:
/**
* The ParentWorkerPool of Monitor whether the system is online or offline
*
* Alex(blackanger.z@gmail.com)
* 2009.3
*/
isOnlie: function(){
workerPool = google.gears.factory.create('beta.workerpool');

workerPool.onmessage = function(a, b, message) {
if (message.sender == monitorchildWorkerId) {
if(message.text == 'online'){
$('#is-connected').show();
$('#is-disconnected').hide();
}else if(message.text == 'offline'){
$('#is-disconnected').show();
$('#is-connected').hide();
}
}
};

var monitorchildWorkerId = workerPool.createWorkerFromUrl('/javascripts/js_app/models/monitor.js');
workerPool.sendMessage(window.location + '?monitor', monitorchildWorkerId);

}

2. 子WorkerPool,负责实时发出请求并且保存状态到浏览器的数据库里(这里用gears的数据库):
/**
* The ChinldWorkerPool of Monitor whether the system is online or offline
*
* Alex(blackanger.z@gmail.com)
* 2009.3
*/

var POLLING_INTERVAL = 2000;

var wp = google.gears.workerPool;
var url;
var parentId;

var first = true;
var online;

var request = google.gears.factory.create('beta.httprequest', '1.0');
var timer = google.gears.factory.create('beta.timer');

var wp = google.gears.workerPool;

monitor = function (message) {
var count = 0;
var db = google.gears.factory.create('beta.database');
db.open('red-CustomersManagement');
request.open('HEAD', url + String(Math.floor(Math.random()*10000)));
request.onreadystatechange = function() {
if (request.readyState == 4) {
try {
if (request.status == 200) {
rs = db.execute("select * from isonline",[]);
if(rs.isValidRow()){count = rs.field(0)};
if (!online) {
online = true;
if (count == 0){
db.execute("insert into isonline (state) values (?)",['online']);
}else{
db.execute('update isonline set state=? where state=?;', ['online',"offline"]);
}

rs.close();
wp.sendMessage("online", parentId);
}
}
}
catch(e) {
if (online || first) {
online = false;
first = false;
db.execute('update isonline set state=? where state=?;', ['offline',"online"]);
wp.sendMessage("offline", parentId);

}
}
db.close();
// wp.sendMessage('ddd', parentId);
timer.setTimeout(monitor, POLLING_INTERVAL);
}
}
try {
request.send();
}
catch(e) {
if (online) {
online = false;
var db = google.gears.factory.create('beta.database');
db.open('red-CustomersManagement');
db.execute('update isonline set state=? where state=?;', ['offline',"online"]);
db.close();
wp.sendMessage("offline", parentId);
}
}
}

wp.onmessage = function(a, b, message) {
url = message.text;
parentId = message.sender;
monitor(message)
}

2009年3月18日 星期三

JavaScript MVC 之 Jamal

2009年3月18日 星期三 1
JavaScript为什么要搞MVC了 ? 有些人可能不理解, 我刚开始也不理解,但是有一些现实里的需求,让我主动去寻找一个这样的MVC框架, 我的需求很简单,因为我想有一个好的js代码组织结构, 我想让自己的思路变的更加清晰。 我终于找到了--Jamal , 一个基于jQuery的JavaScript MVC框架。

Jamal的作者Timo在Jamal刚开始的版本发布的时候,做了一个图,搞了一个什么dispatcher, 可笑的是,国内的某些人竟然把这个图转来转去的当成是宝, 呵呵,我问了Timo本人,他是这么说的:
Hey Alex,

this is a slide from a presentation at the very beginning of jamal.
This is not wrong in general, but there is no dispatcher anymore. The
configuration, what controller is called, is now handled within the
body class.

A short explanation of this structure is:
- Interactions of the user are reflected in javascript events. So
bind events to the dom within the controller.
- Data is handled in the models so all XHR should go there
- The view modifies the dom

This is all convention, Jamal doesn't force you to do it like this...

Greetings,
Timo

Timo这段话已经说的很清楚了,网上流传的那张图早就作废了。 现在的Jamal 0.4.1支持jQuery1.3。
就像Timo说的, 代码是通过config方法和load方法来寻找controller和action。MVC简单来说是这么约定的:
1. C(ontroller) - 因为和用户交互的都是javascript事件,所以应该在controller里和dom绑定事件。
2. M(odel) - 在models里面是进行data处理,所以会放一些ajax逻辑,以及对本地数据库的操作(Jamal没有实现,但是因为项目需求我会集成到里面)。
3. V(iew) - 而在view里当然是对用户dom的修改。

当你下载了Jamal 0.4.1,里面会带例子的。今天研究了Jamal的源码,有一些心得:
代码1505行:
$(function(){
$j = jamal = jamal();
$j.start();
});

这段代码在页面加载以后启动Jamal。 start方法里面会调用关键的load方法去根据页面body的class属性去识别哪个controller,哪个action,所以你的页面body标签的class属性必须这么写:

class="jamal {controller:'Foos',action:'index',debug:true}"
一个页面对应一个controller,一个controller对应一个action。 如果想像rails一样,想写多个action,那么可以这样去模拟:

$j.c({Clients: {
index: function () {
this.new();
// or
$('.new').click(function(){
$j.current.new();
});
},

new: function() {}
}});

$j.c代表controller。 这样,可以更细致的组织你的controller代码了。
如果想在Jamal里扩展自己的方法,可以这样:

jamal.fn.extend(jamal.fn.m.prototype, {

createTable: function(option){
return true;
// 你可以在你的model里通过重载此方法实现你具体的方法。
},
});


最后看看代码我的代码组织结构:



2009年3月17日 星期二

Aptana Active Record 指南(一)

2009年3月17日 星期二 0
Thanks kmandrup ! (他的blog被block了)

Aptana出了一款ActiveRecord.js的库, 用以操作本地数据库,支持html5, gears,手机等。Kmandrup是我在google maillist认识的朋友,那么我就转载了他的这个指南,他还没有更新第2部分,更新完了继续转载。

This example is an extension of Stefans example, demonstrating how to create a One-to-Many relationship of a List with multiple Entry elements.

The HEAD includes jQuery and Active Record.

<html>

<head>

<meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8″>

<meta name=“author” content=“Kristian Mandrup”>

<title>AcitveJS Tutorialtitle>

<script type=“text/javascript” src=“jquery/jquery-1.3.1.min.js”>

script>

<script type=“text/javascript” src=“aptana-activejs/latest/active_record.js”>

script>

head>

The BODY contains the main interface with a few usage instructions and buttons to execute differents parts of the tutorial functionality.

<body>

<pre>

Usage: Create Person relationship graph then Display created Person relationship graph

pre>

<button onclick=”createPersonGraph()>

Create Person relationship graph

button>

<button onclick=”displayPersonGraph()>

Display created Person relationship graph

button>

<button onclick=”initPersonGraph()>

Initialize graph

button>

<br>

<br>

<br>

<div id=‘display’>

div>

The DIV called “display”, is the container where the model description is written to when the “Display…” button is clicked. jQuery finds the DIV with a certain ID and appends HTML as the model is traversed.

The script starts with an initDB() function, that initializes the database for use with Active Record. Here an adapter for the InMemory database is used for simplicity.

<script type=“text/javascript”>

// make Objects for Tables globally available (for simplicity)

var Person;

var Item;

var displayDiv;

function initDB(){

//connect ActiveRecord to In-memory Database

ActiveRecord.logging = true;

ActiveRecord.connect(ActiveRecord.Adapters.InMemory);

}

Next the Schema for the model is defined in initPersonSchema().

function initPersonSchema(){

//simple model: Persons

Person = ActiveRecord.create(‘persons’, {

person_id: ,

mother_id: ,

father_id: ,

spouse_id: ,

child_id: ,

sibling_id: ,

name: {

type: ’string’,

value: ‘No name’

},

age: {

type: ‘number’,

value: 30

},

isMale: {

type: ‘boolean’,

value: 1

},

});

Item = ActiveRecord.create(‘items’, {

person_id: ,

name: ‘MyItem’

});

// when a person is deleted, his/her items are also deleted!

Item.belongsTo(Person);

Child = ActiveRecord.create(‘children’, {

person_id: ,

child_id: ,

});

Sibling = ActiveRecord.create(’siblings’, {

person_id: ,

sibing_id: ,

});

// Set up foreign key relationships

Person.hasOne(Person, {

name: ‘mother’,

foreignKey: ‘mother_id’,

dependent: false

});

Person.hasOne(Person, {

name: ‘father’,

foreignKey: ‘father_id’,

dependent: false

});

Person.hasOne(Person, {

name: ’spouse’,

foreignKey: ’spouse_id’,

dependent: false

});

Person.hasMany(Item, {

name: ‘item’,

foreignKey: ‘person_id’,

dependent: false

});

Person.hasMany(Child, {

name: ‘child’,

foreignKey: ‘person_id’,

dependent: false

});

Person.hasMany(Sibling, {

name: ’sibling’,

foreignKey: ‘person_id’,

dependent: false

});

/*

Child.hasMany(Person, {

name: ‘parent‘, foreignKey: ‘person_id’, dependent: false

});

*/

}

Then a function for creating an example instance of the person graph. Note the two add… helper functions ;)

function createPersonGraph(){

//start using the model

// sister

var jessica = Person.create({

name: ‘Jessica’,

age: 12,

isMale: 0

});

// brother

var jack = Person.create({

name: ‘Jack’,

age: 14,

isMale: 1

});

// mother

var alice = Person.create({

name: ‘Alice’,

age: 42,

isMale: 0

});

// father

var adam = Person.create({

name: ‘Adam’,

age: 46,

isMale: 1

});

//save persons first to get a valid self.id the entries refer to

jessica.save();

jack.save();

adam.save();

alice.save();

jack.createMother(alice);

jack.createFather(adam);

jessica.createMother(alice);

jessica.createFather(adam);

adam.createSpouse(alice);

alice.createSpouse(adam);

var item1 = jack.createItem();

item1.set(‘name’, ‘Ball’);

var item2 = jack.createItem();

item2.set(‘name’, ‘Pillow’);

item1.save();

item2.save();

addChild(adam, jack);

addChild(adam, jessica);

addChild(alice, jack);

addChild(alice, jessica);

addSibling(jack, jessica);

// add reverse sibling connection too!

addSibling(jessica, jack);

}

function addChild(parent, child){

var childRel = parent.createChild();

childRel.set(‘child’, child.id);

childRel.save();

}

function addSibling(source, target){

var sibRel = source.createSibling();

sibRel.set(’sibling’, target.id);

sibRel.save();

}

Then follows some display functions.

function resetdisplay(){

displayDiv.html(‘Person graph
);

}

function displayRelationship(label, name){

displayDiv.append(‘ - ‘ + label + + name +
);

}

function displayPerson(person){

var gender = (person.isMale === 0) ? ‘male’ : ‘female’;

displayDiv.append(‘Person + person.name + is a ‘ + person.age + ‘ year old ‘ + gender +
);

// display relationships!

displayMother(person);

displayFather(person);

displayItems(person);

displayChildren(person);

displaySiblings(person);

}

function displayPersonGraph(){

resetdisplay();

var persons = Person.find();

var items = Item.find();

console.log(‘Items:’ + items.length)

if (persons.length > 0) {

for (p = 0; p < persons.length; p++) {

var person = persons[p];

displayPerson(person);

}

}

else

console.log(‘No Persons created’);

}

function displayMother(person){

var mother = person.getMother();

if (mother) {

displayRelationship(‘Mother is’, mother.name);

}

}

function displayFather(person){

var father = person.getFather();

if (father) {

displayRelationship(‘Father is’, father.name);

}

}

function displaySpouse(person){

var spouse = person.getSpouse();

if (spouse) {

displayRelationship(‘Spouse of’, spouse.name);

}

}

function displayItems(person){

var items = person.getItemList();

for (i = 0; i < items.length; i++) {

var item = items[i];

console.log(item.name);

displayRelationship(‘Item’, item.name);

}

}

function displayChildren(person){

var children = person.getChildList();

console.log(‘Children:’ + children.length)

for (c = 0; c < children.length; c++) {

var childRel = children[c];

var child = Person.find(childRel.child);

console.log(child.name);

displayRelationship(‘Child’, child.name);

}

}

function displaySiblings(person){

var siblings = person.getSiblingList();

console.log(‘Siblings:’ + siblings.length)

for (s = 0; s < siblings.length; s++) {

var sibRel = siblings[s];

var sibling = Person.find(sibRel.sibling);

console.log(sibling.name);

displayRelationship(‘Sibling’, sibling.name);

}

}

Finally, the function that starts up the application when the document has finished loading. A reference to the display container is saved globally for reuse. The display is reset. The database is then initialized and the schema created. Population of the model and the display is all performed as a result of the user clicking the appropriate buttons.

$(document).ready(function(){

//initialy reset the display

displayDiv = $(‘div#display’);

resetdisplay();

// initialize DB and schema on load

initDB();

initPersonSchema();

});

script>

body>

html>

It took quite a lot of experimentation to get to this resulting code. I’m sure there is a better way of creating the model relationships, than using the ID properties in some cases as is done here, but the documentation is lacking in some respects.

Any comments and improvements are most welcome. I hope this is of use for newcomers to Active Record. Enjoy!

Below is another snippet from a sample I am working on. Note the getStringList() which references an AttributeString table through a reference named “string” (defined in the options object on the hasMany relationship.

function initGenericSchema(){

Attribute = ActiveRecord.create(‘attributes’, {

attribute_id: , // primary key

profile_id: , // foreign key

name: ,

type:

});

// string attribute

AttributeString = ActiveRecord.create(‘attributeStrings’, {

attributeString_id: , // primary key

attribute_id: , // foreign key

type: ’string’,

val: {

type: ’string’,

value:

}

});

Attribute.hasMany(AttributeString, {

name: ’string’,

foreignKey: ‘attributeString_id’,

dependent: false

});

Profile = ActiveRecord.create(‘profile’, {

profile_id:

});

Profile.hasMany(Attribute, {

name: ‘attribute’,

foreignKey: ‘attribute_id’,

dependent: false

});

}

function createProfileGraph(){

//start using the model

// string

var strName = AttributeString.create({

val: ‘MyName’

});

strName.save();

console.log(’string:’ + strName.val + ‘, type:’ + strName.type);

// Atribute: Name

var attribName = Attribute.create({

name: ‘Firstname’,

type: ‘name’

});

var profile = Profile.create({

});

attribName.save();

profile.save();

console.log(‘attribName: ‘ + attribName.name + ‘, ‘ + attribName.type);

addAttributeString(attribName, strName);

addAttribute(profile, attribName);

console.log(‘attribName: ‘ + attribName.name + ‘, ‘ + attribName.type);

// to get Relation use name of relation (name in options obj), not name of referenced table!

var strings = attribName.getStringList();

console.log(’strings:’ + strings.length);

var str = strings[0];

console.log(’string:’ + str.val + ‘, type:’ + str.type);

}

I have had some trouble with conflicts on some sort of reserved words within A.R. One such word is “class”. The following schema causes errors, since the reserved word “class” is used in the table name and a relationship name:

function initGenericSchema(){

GObject = ActiveRecord.create(‘objects’, {

gobject_id: , // primary key

name:

});

ObjectClass = ActiveRecord.create(‘objectClasses’, {

objectClass_id: , // primary key

gobject_id: , // foreign key

name:

});

GObject.hasMany(ObjectClass, {

name: ‘objectClass,

foreignKey: ‘gobject_id’,

dependent: false

});

}

These can be fixed to the following schema, using non-conflicting names:

function initGenericSchema(){

GObject = ActiveRecord.create(‘objects’, {

gobject_id: , // primary key

name:

});

ObjectClass = ActiveRecord.create(‘objectTypes, {

objectClass_id: , // primary key

gobject_id: , // foreign key

name:

});

GObject.hasMany(ObjectClass, {

name: ‘objectType,

foreignKey: ‘gobject_id’,

dependent: false

});

}


2009年3月11日 星期三

当你遇到挫折的时候

2009年3月11日 星期三 0

人生总是充满坎坷的。 有的人从容面对,有的人选择死亡。今天看到这幅图挺震撼的, 请记住这个笑容, 当你遇到挫折的时候,想想这个笑容。
他来自美国德克萨斯州,7岁,名叫Cody McCasland
 
City Sleeps ◄Design by Pocket, BlogBulk Blogger Templates