2009年7月31日 星期五

extjs - EditorGridPanel編輯後欄位錯亂的問題


Ext JS的Ext.grid.EditorGridPanel中有個bug,就是當使用者修改某欄位後,內容就會位移。不過這個bug只會發生在IE,FireFox不會有問題(看圖就知道我想說啥啦)。

其實問題就出在viewConfig: {forceFit: true},這是要讓grid自動設定欄寬,不用自動調整的話,自己去設定ColumnMode中每個欄位大小,bug自然就解啦。
在https://yui-ext.com/forum/showthread.php?t=69637 中有較為詳盡的說明。

2009年7月30日 星期四

javascript(5) - function


在java script中,函數必須以關鍵字(key word) function開頭,function name可寫可不寫(named/anonymous function)。可以有0個以上的參數,參數會被存放於arguments中。
function f1() { alert('f1'); } f2 = function (x) { alert('f2'); }; /* 注意; */ (function() { alert('f3'); })(); /* defined anonymous function and invoke. 注意後面的(); */ f1(); f2();
arguments
當pass的參數少於function定義的參數時,少的這些參數會被視為undefined。
function pass(x) { alert(x); } pass(); pass(123); 其實,function的參數會被儲存在arguments(Arguments類別)中。
function max() { var max = arguments[0]; for (var i = 1; i < arguments.length; i++) { if (max < arguments[i]) max = arguments[i]; } return max; } alert(max(9, 7, 1, 3)); arguments並不是一個真的array,而是一個Arguments,當改變function的參數時,也會同步改變arguments。
function print(x) { alert(x); arguments[0] = null; alert(x); } print('123');
callee
另外arguments還有另外一個常用的properties - 'callee',用於傳回正在執行的Function物件,常用於匿名的function的遞迴(recursive)。
function factorial(n) { if (n <= 0) return 1; else return n * arguments.callee(n - 1) } alert(factorial(3));
function's properties
function在JavaScript中算是個object,所以自然就有properties,這邊介紹幾個properties,length取得function參數數量。
var f1 = function(x) {return x * x}; var f2 = function(x, y) {return x + y}; alert(f1(3)); alert(f1.length); alert(f2.length);
apply()/call()
call()/apply()讓使用者暫時的將function當成某個object的method.
如f.call(obj, 1, 2) 等同於
obj.m = f;
obj.m(1,2);
delete obj.m;
apply()和call()很像, 只是apply的參數必須是array
f.apply(obj, [1,2]);



開箱文 - 麥當勞之Hello Kitty


熱騰騰的kitty終於到手啦,前幾天在新聞上看到麥當勞又要推出kitty的系列商品,本來不以為意,但是越看越可愛,害我忍不住衝啦..趁著中午要去銀行辦事,就"順道"繞去麥當勞買了個經濟餐在加20元。
呼..我的Hello Kitty就到手啦!!
比想像中的大..大約十公分左右喔..
合體囉...Kitty回家啦!!!

ext.gird的右鍵功能簡介


Grid提供了四個與右鍵功能有關的event,包含contextmenu、cellcontextmenu、以及headercontextmenu,說明分別如下:
由於Browser本身就具有右鍵功能,所以在自訂右鍵功能時,必須使用preventDefault防止發生Browser的預設事件動作。
contextmenu(Ext.ExentObject e)
The raw contextmenu event for the entire grid.

cellcontextmenu(Grid this, Number rowIndex, Number cellIndex, Ext.EventObject e)
Fires when a cell is right clicked。
範例為顯示使用者對哪個cell按下右鍵。
var headerMenu = new Ext.menu.Menu({
    items: [{
        text: 'show index(row, col)',
        handler: function(item, event) {
            alert(headerMenu.cellSelected.row + 
                  ' ' + headerMenu.cellSelected.column);
        }
    }]
});
grid.on('cellcontextmenu', function(grid, rowIndex, columnIndex, e) {
    e.preventDefault();
    // 將點選的cell資訊存放於此
    headerMenu.cellSelected = {'row': rowIndex, 'column': columnIndex}; 
    headerMenu.showAt(e.getXY());
});

rowcontextmenu(Grid this, Number rowIndex, Ext.EventObject e)
Fires when a row is right clicked。
我將舉刪除某列為範例說明。由於menu的handler並不能直接得知目前選到的row index,所以必須在rowcontextmenu event中,先將row index存起來,在menu的handler中讀取,才能得知目前選到的row。
var rowMenu = new Ext.menu.Menu(
  items: [{
    text: 'delete',
    handler: function(item, event) {
      var rec = store.getAt(grid.rowContextIndex);
      store.remove(rec);
    }
  }]
});
grid.on('rowcontextmenu', function(grid, rowIndex, e) {
    e.preventDefault();
    grid.getSelectionModel().selectRow(rowIndex);
    grid.rowContextIndex = rowIndex; // 將點選的row資訊存放於此
    rowMenu.showAt(e.getXY());
});

headercontextmenu(Grid this, Number columnIndex, Ext.EventObject e)
Fires when a header is right clicked。
例子為顯示使用者對哪個header按下右鍵。
var headerMenu = new Ext.menu.Menu({
    items: [{
        text: 'show column index',
        handler: function(item, event) {
            alert(grid.headerContextId);
        }
    }]
});
grid.on('headercontextmenu', function(grid, columnIndex, e) {
    e.preventDefault();
    var cm = grid.getColumnModel();
    // 將點選的column資訊存放於此
    grid.headerContextId = cm.getDataIndex(columnIndex); 
    headerMenu.showAt(e.getXY());
});


2009年7月29日 星期三

Ext.grid.rownumberer顯示錯亂的問題


小弟發現造成錯亂是因為自己沒有將view做refresh,應該在新增刪除後執行grid.view.refresh()。

-- 舊文章 --
在ext-js中的Ext.grid.rownumberer()常常會因為store的新增刪除造成數字錯亂,可以在grid中執行新增刪除的地方(如insertRows()/removeRow()),修改成每次執行後都要refresh()即可解決。
不過小弟也不知道這算不算是正解。

insertRows : function(dm, firstRow, lastRow, isUpdate){
    if(!isUpdate && firstRow === 0 && lastRow >= dm.getCount()-1){
        this.refresh();
    }else{
        if(!isUpdate){
            this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
        }
        var html = this.renderRows(firstRow, lastRow);
        var before = this.getRow(firstRow);
        if(before){
            Ext.DomHelper.insertHtml('beforeBegin', before, html);
        }else{
            Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);
        }
        if(!isUpdate){
            this.fireEvent("rowsinserted", this, firstRow, lastRow);
            this.processRows(firstRow);
        }
    }
    this.syncFocusEl(firstRow);
},
改成
insertRows : function(dm, firstRow, lastRow, isUpdate){
    if(!(!isUpdate && firstRow === 0 && lastRow >= dm.getCount()-1)) {
        if(!isUpdate){
            this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
        }
        var html = this.renderRows(firstRow, lastRow);
        var before = this.getRow(firstRow);
        if(before){
            Ext.DomHelper.insertHtml('beforeBegin', before, html);
        }else{
            Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);
        }
        if(!isUpdate){
            this.fireEvent("rowsinserted", this, firstRow, lastRow);
            this.processRows(firstRow);
        }
    }
    this.refresh();
    this.syncFocusEl(firstRow);
},


2009年7月28日 星期二

關於美食


小弟我沒啥嗜好,就是愛吃台灣美食,所以決定將台灣的美食記錄下來,並且分類,分等主要以路邊攤,與一般店面為主(至於連鎖餐廳大家隨時隨地都可以找到,在寫也沒意義了),文章命名以 '縣市 - 食物類別 - 店名'為主,路邊攤的評等只評好吃的程度與價格(裝潢和服務路邊攤好像不適合),店面的評等除了包含好吃的程度與價格,還有裝潢也會描述一下,如果有加收服務費,這項肯定要加以評等的。 標題上的☆就是小弟我個人的感覺, 每個人口味都可能不同,所以也許我覺得好吃,別人不覺得,不過應該還是不至於差太多啦,☆的多寡描述如下:

☆:路過可以吃吃看 ☆☆:在附近可以吃吃看 ☆☆☆:有機會要去吃吃看 ☆☆☆☆:一定要去吃吃看 ☆☆☆☆☆:今生一定要吃過 至於分類,目前只想到日式料理、簡餐、火鍋、小吃、糕點飲料、海鮮快炒、麵食、牛排館等,剩下的往後再補充嚕。


新竹 - 日式料理 - 壽司店 ☆


這家店位於新竹縣竹北市三民路上,接近博愛路口,沒有店名,走進店裡的看來多是熟客,東西都是物美價廉(俗擱大碗),裡面大概只有四張桌子,不過還好很多人都外帶,今天小弟點了鮭魚炒飯、握壽司、綜合小菜以及味增湯($20,裡面有不少魚肉唷)。 不過老闆娘表示過幾天要搬到三民路250號,派出所的對面。
鮭魚炒飯
握壽司,個人覺得飯有點硬,生魚片感覺很新鮮。
綜合小菜,菜色可以自己搭配。
味增湯,味道有些SOSO,不過有大大的魚肉。

類別:日式料理
店名:無
地點:新竹縣竹北市三民路250號
評論:☆ 便宜大碗型

2009年7月27日 星期一

在cgic中印出form中所有的data


在cgic中印出form中所有的data是我覺得是非常重要的功能之一,因為這可以幫助你debug,印出cgi到底收到哪些from,以及其內容(value)為何。
首先利用cgiFormEntries()抓取form中所有欄位名稱(field name),接著在利用cgiFormStringNoNewlines()抓取內容(value)。
#include <stdio.h>
#include <string.h>
#include "cgic.h"

int cgiMain(int argc, char *argv[])
{
    int ret;
    char **array, **arrayStep, value[64];

    cgiHeaderContentType("text/html");
    if (cgiFormEntries(&array) != cgiFormSuccess) {
        return -1;
    }

    for (arrayStep = array; *arrayStep; arrayStep++) {
        snprintf(value, sizeof(value), "%s=", *arrayStep);
        if ((ret =
             cgiFormStringNoNewlines(*arrayStep, value + strlen(value),
                                     sizeof(value) - strlen(value)))
            != cgiFormSuccess) {
            fprintf(cgiOut, "<p>%s(null). failed</p>\n", value);
        } else {
            fprintf(cgiOut, "<p>%s</p>\n", value);
        }
    }
    return 0;
}


利用cgic上傳檔案


CGIC提供一些上傳檔案的API,讓您可以輕鬆的利用這些API處理上傳檔案。
注意,您的form必須將enctype設定為multipart/form-data。
<html>
    <head><title>upload test</title></head>
    <body>
        <form method="post" enctype="multipart/form-data"
                action="upload.cgi">
            <input type="file" name="fileName" />
            <input type="submit" />
        </form>
    </body>
</html>

接著就是處理CGI的部份了。
1. 首先就是利用cgiFormFileName()檢查檔案是否被提交。
2. 接著利用cgiFormFileOpen()取得cgiFilePtr的object。
3. 再利用while(cgiFormFileRead(cgiFilePtr) == cgiFormSuccess)讀取資料。
4. 利用cgiFormFileClose(cgiFilePtr)釋放不再需要的cgiFilePtr。

#include <stdio.h>
#include <cgic.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define F_FILENAME      "fileName"
#define FILENAME_LEN    1024
#define BUF_LEN         1024

int cgiMain(int argc, char *argv[])
{
    cgiFilePtr cfp;
    char rfile[FILENAME_LEN] /*remote file */ ,
        lfile[FILENAME_LEN] /* local file */ , buf[BUF_LEN];
    int ret, fd, fsize, got;

    cgiHeaderContentType("text/html");
    if ((ret = cgiFormFileName(F_FILENAME, rfile, sizeof(rfile))) !=
        cgiFormSuccess) {
        fprintf(cgiOut, "<p>No file was uploaded.(%d)</p>", ret);
        return -1;
    }
    cgiFormFileSize(F_FILENAME, &fsize);

    if ((ret = cgiFormFileOpen(F_FILENAME, &cfp)) != cgiFormSuccess) {
        fprintf(cgiOut, "<p>open cgi file failed.(%d)</p>", ret);
        return -1;
    }
    snprintf(lfile, sizeof(lfile), "/tmp/%s", rfile);
    fprintf(cgiOut, "write to %s", lfile);
    if ((fd =
         open(lfile, O_CREAT | O_WRONLY,
              S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
        fprintf(cgiOut, "<p>create file on server failed.(%s)</p>",
                strerror(errno));
        return -1;
    }
    while (cgiFormFileRead(cfp, buf, sizeof(buf), &got) == cgiFormSuccess) {
        if ((ret = write(fd, buf, got)) < 0) {
            fprintf(cgiOut, "<p> write failed(%d/%s)</p>\n", errno,
                    strerror(errno));
        }
        fprintf(cgiOut, "<p>got(%d)</p>\n", got);
    }
    close(fd);
    cgiFormFileClose(cfp);
    fprintf(cgiOut, "<p> end </p>\n");
    return 0;
}

基本上,I/O讀取上利用buffered I/O是比較有效率的,不過範例沒有用buffered I/O,留給大家去修改一下吧。
參考資料: http://www.boutell.com/cgic/


2009年7月25日 星期六

JSON


JavaScript Object Notation(JSON)是一個language-indepent的資料交換格式,他源自於ECMA-262 3rd edition中的子集合,相關資訊可以參考RFC-4627。JSON可以表示JavaScript中的資料型態,包含四種原生資料型態(string、number、boolean和null),以及兩種結構化資料型態(object和array)。JSON的主要設計理念是希望能設計出可移植,且最小化的JavaScript表示法。

JSON用name:value表示properties的name與value,在value的表示方式上,object用{}表示,array用[]表示,properities之間用","分開。
比如:
{
  "Image": {
    "Width":  800,
    "Height": 600,
    "Title":  "View from 15th Floor",
    "Thumbnail": {
      "Url":    "http://www.example.com/image/481989943",
      "Height": 125,
      "Width":  "100"
    },
    "IDs": [116, 943, 234, 38793]
  }
}


2009年7月24日 星期五

javascript(4) - Object


object的建立可以透過JSON format或者new()兩種方式:
var e = {};
var p = {x:10, y:20};
var name;
for (name in p) {
   alert('p.' + name + '=' + p[name]);
}

透過new可以建立新的object(呼叫constructor進行初始化),比如new Object(),會建立一個empty object(constructor為{})。可以透過.或者[]存取object的properties,透過delete移除object的properties。用var宣告的properity不能被delete。
var person = new Object();
person.name = "Brook";
person.age = 30;
person['weight'] = 50;
alert(person['name']);
alert(person.age);
alert(person.weight);
delete person.weight;
alert(person.weight);

檢查property是否存在
var p = {x:10, y:20};
if ('x' in p) alert('p has property "x"');
if ('y' in p) alert('p has property "y"');
if ('z' in p) alert('p has property "z"');

constructor()
類似C++/JAVA的constructor function。
function Animal() {
}
var bird = new Animal();
alert(bird.constructor == Animal);
alert(bird.constructor == Object);  

toString()
每當object要被需要被轉成string時會被呼叫。

valueOf()
每當object需要被轉成primitive type時會被呼叫。

hasOwnProperty()
用以判斷object是否有自己定義properties。

Array
Array算是一種特別的Object,可以透過.或[]存取element。要移除element必須用shift()/pop()/splice()不能用delete。
var a1 = new Array();
a1[0] = "hello";
a1.x = "xx";
alert(a1['x']);
alert(a1[0]);

var a2 = [];
for (var i = 1; i < 10; i++) {
  a2[i] = i*i;
}
a2.shift(); // remove first element
a2.pop(); // remove last element.
alert(a2);
a2.splice(5);
alert(a2);
a2['x'] = 'xx';
a2['y'] = 'yy';
alert(a2.length);
a2.length =3;
alert(a2);
a2.length = 5;
alert(a2);
Array.length回傳的是目前用的index最大值+1,index最大值為2^32-1,因此length並不保證有這麼多element,而直接改變index會造成Array的truncating和enlarging。

JavaScript並不支援multi-dimensional array,但是允許element可以是array(array本來就是object的一種)。
var t = new Array(3);
for (var i = 0; i < t.length; i++) {
  t[i] = new Array(5);
}

for (var r = 0; r < t.length; r++) {
  for( var c = 0; c < t[r].length; c++) {
    t[r][c] = r * c;
  }
}
alert(t);

Array.join()
將所有的element轉成string之後串在一起。
var a = new Array(1,2,3);
var b = new Array(3);
alert(a.join());
alert(b.join());

Array.reverse()
將所有element順序反轉(reverse the order)。
var a = new Array(1, 2, 3);
alert(a.reverse().join());

Array.sort()
將所有element做排序,可以給sort一個compare function進行排序。
var a = new Array(3, 1, 2);
alert(a.sort().join());
alert(a.sort(function(a, b) { return b - a; }).join());

Array.concat()
將回傳新的Array,包含新的element加上原本array中的element(不會改變原本的array)。
var a = new Array(1, 2, 3);
var a1 = a.concat(4,[5]); // [1, 2, 3, 4, 5]
alert(a1);
var a1 = a.concat([4, [5]]); // [1, 2, 3, 4, [5]]
alert(a1);

Array.slice()
回傳新的Array(不改變原來的array),包含指定的(satrt, end]之element。
var a = new Array(1, 2, 3, 4, 5);
alert(a.slice(1));
alert(a.slice(2,3));
alert(a.slice(-1));
alert(a.slice(-2, 3));
alert(a.slice(2, -3));
alert(a.slice(-2, -3));

Array.splice()
用於insert/remove element。
var a = new Array(1, 2, 3, 4, 5);
a.splice(4);
alert(a);
a.splice(2, 1);
alert(a);
var a = new Array(1, 2, 3, 4, 5);
a.splice(4);
alert(a);
a.splice(2, 1);
alert(a);
var a1 = a.splice(1,2, 'a', 'b'); /* a[1]開始, 取代後面2個, 為'a', 'b' */
alert(a);
alert(a1);
a1 = a.splice(1,0, 'a', 'b'); /* a[1]開始, 取代0個(insert的意思), 為'a', 'b' */
alert(a);
alert(a1);

Array.push()/Array.pop()
從Array後面新增/刪除。
var a = [];
alert(a.push('a'));
alert(a.push('b'));
alert(a.pop());
alert(a.pop());

Array.unshift()/Array.shift()
從Array前面新增/刪除。
var a = [];
alert(a.unshift('a'));
alert(a.unshift('b'));
alert(a.shift());
alert(a.shift());

global/call object
當JavaScript一啟動後,便會建立global object,而所有的全域變數/全域函數都是這個global object的屬性,當呼叫另外一個function時,就會建立call object,區域變數/內部函數也成為這個call object的屬性。

2009年7月23日 星期四

javascript(3) - statement


statment部分,大致上也和C/C++/JAVA相同,所以這邊只有提出一些不同於C/C++的部分。

switch
switch會先運算switch(x),接著再運算每一個case的內容,只要運算完的結果相符(==),就會執行該case的內容,所以case可以是任何的運算式,不過不建議使用side-effect的case,因為對於執行結果很不直覺。
var four = new Number(4);
var ten = 10;
for (x = 0; x <= 10; x++) {
  switch(x) {
    case 1*2:
      alert("the result is 1*2");
      break;
    case 3:
      alert("the result is 3");
      break;
    case four:
      alert("the result is four");
      break;
    case four+1:
      alert("the result is four+1");
      break;
    case --ten:
      alert("not recommend");
      break;
    default:
  }
}

for/in
利用for/in可以依序取得array或object的element,但沒有一定的順序,可能會因為不同的JS implementation而有所差異。
var obj = new Object();
obj.x = 100;
obj.y = function() { alert('ya') }
obj.z = new Date();
for (variable in obj) {
   alert("obj." + variable + " = " + obj[variable]);
}

label
在java script中,label等於是對statment進行命名(naming),可以使用continue重複進入該label/(naming statment),或者break跳過該statment。
test1 : for (var i = 0; i < 3; i++) {
   test2 : for (var j = 0; j < 3; j++) {
      if (i == 1 && j == 1) {
         continue test1;
      } else {
         alert("i = " + i + ", j = " + j);
      }
   }
}

var i = 0;
test2:
while(++i) {
   if (i > 10) {
      break test2;
   }
   alert(i);
}

throw/try/catch/finally
透過try進行捕捉exception,當在try這一block的code發生exception後,就會進入catch執行,而finally是不管有沒有發生exception都會被執行,而exception是透過throw丟出。
function f(x) {
  if (x == 0) throw new Error("x can't be zero");
}

for (var i =5; i > -5; ) {
  try {
    f(i);
  } catch (e) {
    alert(e);
  } finally {
    i--;
  }
}

with
with用來暫時改變scope chain,比如with(object)則會將object加到目前的scope chain中,雖然在使用上可以省略打一些字,但是java script很難對with進行最佳化,以及變數使用上可能會有問題,所以不建議使用。
with(Math) {
  alert(PI);
  alert(E);
}


2009年7月21日 星期二

javascript(2) - operators


基本上Java Script的operators和C/C++/JAVA大致相同,所以這邊只有提出一些不同於C/C++的operators。

=== (identical)
如果資料型態相同,內容相同回傳true,否則回傳false。對於primitive type只要內容相同即可。對於reference type(object/array/function)則是要refence到相同的物件。
var n1 = 123;
var n2 = 123;
var no = new Number(123);
alert("n1 == no ? " + (n1 == no));
alert("n1 === no ? " + (n1 === no));
alert("n1 == n2 ? " + (n1 == n2));
alert("n1 === n2 ? " + (n1 === n2));

var s = "123";
var so = new String("123");
alert("s == so ? " + (s == so));
alert("s === so ? " + (s === so));

in operator
當in為 left-side operator時,可以取值。當in為 right-side operator時,則判斷是否存在。
var point = { x:1, y: 1};
var has_x_coord = "x" in point;
alert("x is set ? " + has_x_coord);
alert("x is set ? " + ("z" in point));
for (p in point) {  
    alert("point." + p + "=" + eval("point." + p));
}

instanceof operator
為判斷是否為該object的instance。
var d = new Date();
alert((d instanceof Date));
alert((d instanceof Object));
alert((d instanceof Number));

>> shift right with sign, >>> Shift right with zero fill
這邊就要提到java script的number是如何儲存的,所有的number在java script中,都是以64-bit的IEEE 754表示。所以,思考一下執行完的結果吧。
alert(-1 >> 1);
alert(1 >> 1);
alert(-1 >>> 1);
alert(1 >>> 1);

typeof return a string indicating the datatype of the operand.
var s = "123";
var d = new Date();
alert("typeof s = " + (typeof s));
alert("typeof d = " + (typeof d));


2009年7月20日 星期一

xpath


xpath -- a script to query XPath statements in XML documents.
xpath算是command line的xml查詢工具。
假設有個xml檔(book.xml)內容如下:
<?xml version="1.0"?>
<root>
    <book>
        <name>b1</name>
        <auth>Brook</auth>
        <price>$10</price>
    </book>
    <book>
        <name>b2</name>
        <auth>Brook</auth>
        <price>$15</price>
    </book>
    <store location="tw" tel="0921" name="Dr.B">
</root>

使用'/A/B'尋找A底下的B。
brook@desktop:~$ xpath -e '/root/book' -q book.xml
<book>
        <name>b1</name>
        <auth>Brook</auth>
        <price>$10</price>
    </book>
<book>
        <name>b2</name>
        <auth>Brook</auth>
        <price>$15</price>
    </book>
brook@desktop:~$ xpath -e '/root/book[1]/name' -q book.xml
<name>b1</name>
brook@desktop:~$ xpath -e '/root/book[2]/name' -q book.xml
<name>b2</name>

使用//xx則會尋找xx這個tag,不管在哪個節點位置。
brook@desktop:~$ xpath -e '//name' -q book.xml
<name>b1</name>
<name>b2</name>

使用@xx取得xx的attribute。
brook@desktop:~$ xpath -e '/root/store/@name' -q book.xml
 name="Dr.B"

使用text()取得node的內容。
brook@desktop:~$ xpath -e '//book[1]/name/text()' -q book.xml
b1

其他用法請參考:
http://www.w3.org/TR/xpath
http://zh.wikipedia.org/wiki/XPath

Ext.data.Store之資料修改(add/modify/remove)


extjs中的grid負責資料的顯示,store則負責資料的處理,store.data.item[].dirty 則標示該record是否有被更改過,可以由store.getModifiedRecords()來讀取被更改過的資料(不包含被刪除的資料)。
var m = store.getModifiedRecords();
var jsonArray = [];
Ext.each(m, function(item) {
    jsonArray.push(item.data);
}); 
alert(Ext.encode(jsonArray)); 

有看到有人直接存取modified,沒有trace過,不過感覺應該透過Interface來存取比較妥當。
var m = store.modified.slice(0);
var jsonArray = [];
Ext.each(m, function(item) {
  jsonArray.push(item.data);
});
alert(Ext.encode(jsonArray)); 

至於remove/delete則必須自己處理,每次在執行delete之前就先儲存在某個地方(我都存在store.deleted)。
var records = grid.getSelectionModel().getSelections();
for (i = 0; i < records.length; i++) {
    store.deleted.push(records[i]);
    store.remove(records[i]);
}

Add則只需要將record插入store中即可。
/* Generate a constructor for a specific Record layout */
var R = Ext.data.Record.create({
    {name: 'name'},
    {name: 'tel'},
    {name: 'addr'}
});

var r = new R({
    name: 'Brook',
    tel: '0921',
    addr: 'tw'
});

grid.stopEditing();
store.insert(0, r);
grid.startEditing(0, 0);


2009年7月10日 星期五

cgic簡介


CGIC是一套用C寫成的CGI Library,主要幫您parse form data:

安裝
您可以到他的官方網站下載 wget http://www.boutell.com/cgic/cgic205.tar.gz 並且編譯
tar zxvf cgic205.tar.gz
cd cgic205 && make
編譯完會產生libcgic.a,或者您可以修改Makefile產生libcgic.so。每個cgi其實就等同於一個獨立的可執行檔,您可以在shell底下直接執行,因此每個CGI就必須要有main(),而cgic一開始就會先幫user處理一些data,您可以在cgic.c裡面可以看到,而在main()後面會呼叫cgiMain(),這也是我們cgi的進入點。
#include <stdio.h>
#include <cgic.h>

int cgiMain() {
  cgiHeaderContentType("text/html");
  fprintf(cgiOut, " <h1>hello world</h1>\n");
  return 0;
}

brook@debian:~/cgic/cgic205$ gcc -o hello.cgi hello.c libcgic.a -I.
brook@debian:~/cgic/cgic205$ ./hello.cgi
Content-type: text/html

<h1>hello world</h1>


2009年7月9日 星期四

javascript(1) - javascript introduction


statment
avascript一個statment的結束可以是換行或是分號。
alert('1')
alert('2');

如果跨行要再後面加'\'。
alert('1 \
2');

註解
javascript的註解和C++一樣,支援單行和多行。
// one-line comment
/* multiple-line
* comment */

變數
javascript的變數可以儲存任何的資料型態,沒有用var宣告的變數,會被視為global variable。
a = 1; /* global variable */
var b = 2; /* global variable */
function c() {
    var d = 3; /* local variable */
    e = 4; /* global variable */
}

變數的有效範圍為宣告的函數所涵蓋之範圍,如
var v = "global";
function fn() {
    alert(v); // 顯示'undefined', 不是'global'
    var v = "local";
    alert(v); // 顯示local
}

原生資料型
javascript中的變數可以是任何的資料型態,其原生資料型態有undefined, Null, Number, String, Boolean, Native Objects(array...).
  • undefined,所謂的undefined是指沒有初始化的變數。
  • Null通常是指已經初始化,被指向空的(empty)。
alert(null == undefined)
alert(null === undefined)

  • Number就是數值,1, 2.3, 4.5e, 07(8進制), 0x89(16進制)。
  • String就是字串,javascript並沒有所謂character的資料型態。
str = "hello"
alert(str.charAt(0))

  • Boolean不是true就是false。
alert(true == 1);
alert(true === 1);
alert(false == 0);
alert(false === 0);

  • Native Objects
剩下的應該都可以歸類為Native Objects吧(包含array)。
array = [];
array.push("str");
array.push(1)
array[2] = "i2";
array["x3"] = "si3";
alert(array[0]);
alert(array["x3"]);
alert(array.x3);


2009年7月8日 星期三

doxygen


Doxygen 是一個document generator,可以將程式中的註解轉換成為說明文件。通常我們在寫程式時,或多或少都會寫上註解,如果在寫註解的時候能依據某種格式,接著就可以透過document generator產生出漂亮的文件。Doxygen支援的程式語言包含C++、C、Java、Objective-C、Python、IDL(Corba and Microsoft flavors)、Fortran、VHDL、PHP和C#等。而且可以產生出的格式有HTML、RTF(MS-Word)、PostScript、PDF、manpage等。
安裝步驟就不多說了,直接來看doxygen的格式。
doxygen支援C-style,如:
/**
 * ... text ...
 */

Qt-style
/*!
 * ... text ...
 */

C++-style
///
/// ... text ...
///
//!
//!... text ...
//!
簡單範例doxy.c
#include 

/**
 * sum of two integer
 *
 * @param a an integer
 * @param b an integer
 * @return the sum of two integer
 */
int sum(int a, int b)
{
    return (a+b);
}

int main(int argc, char *argv[])
{
    int a = 5, b = 10;

    printf("%d\n", sum(a, b));
    return 0;
}
doxygen指令必須搭配設定檔(config),要記住的tag=value需要查閱一番,所以,我們就用gui - doxywizard來設定並且產生文件吧。
最重要的就是填入source所在的目錄(source code directory)以及檔案輸出的目錄(destination directory)。這邊還有輸入工作目錄(working directory)、專案名稱(project name)以及專案版本(Project version or id)。

這邊選擇您的程式用哪種語言寫的。

這邊選擇輸出的格式以及格式的設定。

這邊選擇要輸出的圖示有哪些。

最後切到執行(run)這個頁面,按下Run doxygen執行doxygen。





產出的文件真是讓我沒話說的好。

jsdoc-toolkit


jsdoc-toolkit算是google推薦的JavaScript document generator,您可以在 http://code.google.com/p/jsdoc-toolkit/downloads/list下載。
由於jsdoc-toolkit是用java寫的,所以請先安裝好java,Windows底下執行命令把"/"改成"\"就可以了,執行java -jar jsrun.jar app\run.js -a -t=templates\jsdoc mycode.js就可以產生mycode.js的文件檔了,這部分可以參考裡面的README.txt,預設會將document寫到out目錄中。
手邊剛好有extjs,所以直接拿ext-all-debug.js當測試,卻得到exception from uncaught JavaScript throw: java.lang.OutOfMemoryError: Java heap space的錯誤。這導因於heap不夠,可透過設定Xmx解決(請參考後面說明)。

執行java -jar jsrun.jar app/run.js --help 可以獲取更多資訊。
brook@debian:~/jsdoc_toolkit-2.3.0/$ java -Xmx1024m -Xms512m -jar jsrun.jar app/run.js -a -v -t=templates/jsdoc/ ext/adapter/ext/ext-base.js
  ... 省略  ...

brook@debian:~/jsdoc_toolkit-2.3.0/$ java -jar jsrun.jar app/run.js --help
USAGE: java -jar jsrun.jar app/run.js [OPTIONS]   ...

OPTIONS:
  -a or --allfunctions
          Include all functions, even undocumented ones.

  -c or --conf
          Load a configuration file.

  -d= or --directory=
          Output to this directory (defaults to "out").

  -D="myVar:My value" or --define="myVar:My value"
          Multiple. Define a variable, available in JsDoc as JSDOC.opt.D.myVar.

  -e= or --encoding=
          Use this encoding to read and write files.

  -E="REGEX" or --exclude="REGEX"
          Multiple. Exclude files based on the supplied regex.

  -h or --help
          Show this message and exit.

  -n or --nocode
          Ignore all code, only document comments with @name tags.

  -o= or --out=
          Print log messages to a file (defaults to stdout).

  -p or --private
          Include symbols tagged as private, underscored and inner symbols.

  -q or --quiet
          Do not output any messages, not even warnings.

  -r= or --recurse=
          Descend into src directories.

  -s or --suppress
          Suppress source code output.

  -S or --securemodules
          Use Secure Modules mode to parse source code.

  -t= or --template=
          Required. Use this template to format the output.

  -T or --test
          Run all unit tests and exit.

  -u or --unique
          Force file names to be unique, but not based on symbol names.

  -v or --verbose
          Provide verbose feedback about what is happening.

  -x=[,EXT]... or --ext=[,EXT]...
          Scan source files with the given extension/s (defaults to js).
out of memory.
看到java.lang.OutOfMemoryError就是要加大記憶體空間啦,java 程式有-Xms跟-Xmx參數可以用。
-Xms Setting minimum heap size
-Xmx Setting maximum heap size

心得:感覺jsdoc-toolkit還是很陽春,而且很耗記憶體和CPU,感覺很慢,常常讓人以為當機了。不知道哪邊有像ext-js的document一樣漂亮的工具。




2009年7月6日 星期一

indent - format your code


indent主要用來排版C code,因為coding風格差異其實不小(BSD/GNU/K&R/linux,其實最主要是很多人喜歡自創風格),但是如果大家都能使用特定的coding風格,相信熟悉此一風格的人很快的就能進入狀況。 但是,現在流行混搭風,有些地方用BSD,某些又跟隨gnu的風格,實在是有點小亂,慘的是,還有自創風格,雖說coding風格一致即可,不過要一群人跟隨你的風格可能也是不妥。
所以,我們可以利用indent,將code排成某特定風格,這樣大家都能很快的進入狀況。對於code的編排風格,建議先參考http://en.wikipedia.org/wiki/Indent_style,了解一下各大宗的原始風貌,再來研究indent(我也是混搭風的愛好者@@)
原始程式碼
brook@ctc-desktop:~$ cat xx.c
#include <stdio.h>
int main(int argc, char *argv[])
{
    int x;
    for(x=0;x<10;x++) { printf("%d\n", x); }
    switch(x) {
        case 1:
            printf("one\n");
            break;
        default:
            printf("default\n");
    }
    if(x==0) {printf("zero\n");}
    else if (x==2) {printf("two\n");}
    else {printf("no match\n");}
    return 0;
}


K&R的風格
brook@ctc-desktop:~$ indent -kr -st xx.c
#include <stdio.h>
int main(int argc, char *argv[])
{
    int x;
    for (x = 0; x < 10; x++) {
        printf("%d\n", x);
    }
    switch (x) {
    case 1:
        printf("one\n");
        break;
    default:
        printf("default\n");
    }
    if (x == 0) {
        printf("zero\n");
    } else if (x == 2) {
        printf("two\n");
    } else {
        printf("no match\n");
    }
    return 0;
}


gnu的風格
brook@ctc-desktop:~$ indent -gnu -st xx.c
#include <stdio.h>
int
main (int argc, char *argv[])
{
  int x;
  for (x = 0; x < 10; x++)
    {
      printf ("%d\n", x);
    }
  switch (x)
    {
    case 1:
      printf ("one\n");
      break;
    default:
      printf ("default\n");
    }
  if (x == 0)
    {
      printf ("zero\n");
    }
  else if (x == 2)
    {
      printf ("two\n");
    }
  else
    {
      printf ("no match\n");
    }
  return 0;
}


Linux的風格
brook@ctc-desktop:~$ indent -linux -st xx.c
#include <stdio.h>

int main(int argc, char *argv[])
{
        int x;
        for (x = 0; x < 10; x++) {
                printf("%d\n", x);
        }
        switch (x) {
        case 1:
                printf("one\n");
                break;
        default:
                printf("default\n");
        }
        if (x == 0) {
                printf("zero\n");
        } else if (x == 2) {
                printf("two\n");
        } else {
                printf("no match\n");
        }
        return 0;
}


我常用的選項 -st, --standard-output
寫到stdout去, 可以先在螢幕上確認是否是自己要的風格.
-i, --indent-level
縮排要用幾個空白.
-cli, --case-indentation
case要往內縮幾個空白
-nut, --no-tabs
使用空白取代tab


個人偏愛的風格 indent -kr -st -i4 -cli4 -nut xx.c
brook@ctc-desktop:~$ indent -kr -st -i4 -cli4 xx.c
#include <stdio.h>
int main(int argc, char *argv[])
{
    int x;
    for (x = 0; x < 10; x++) {
        printf("%d\n", x);
    }
    switch (x) {
        case 1:
            printf("one\n");
            break;
        default:
            printf("default\n");
    }
    if (x == 0) {
        printf("zero\n");
    } else if (x == 2) {
        printf("two\n");
    } else {
        printf("no match\n");
    }
    return 0;
}



7月經濟數據


  • 台灣6月消費者物價指數(CPI)年增率「-1.97%」。
  • 美國失業率來到9.5%。
  • 歐元區7月投資者信心意外惡化,7月Sentix投資者信心指數降至負31.3,6月為負27.0。
  • 歐元區6月服務業PMI修正升44.7,中國PMI指數為53.1。
  • 印度2009年1月至6月的黃金進口下跌了64%至50噸。

結論:亞洲區應該會率先復甦,歐美負債過高,可能出現M型復甦,年底前可能再度惡化,黃金則可能會成V型反轉,先往下跌,10月左右再往上拉,因為新興市場轉型成功,撐起歐美的衰退,金磚四國和東協,拉丁美洲等最看好。