Feeds:
文章
留言

Archive for 2009 年 09 月

這個編輯器其實不難,但是花了不少時間在切圖 XD

主要還是透過 Google Chart API 去繪出方程式

直接看 Demo

Read Full Post »

這週研發會議聽到同事介紹 Python+Diango,讓我在次想起 Python,一直聽說 Python 可用來開發 GUI 程式,現在終於擠出時間來瞭解一下,稍微搜尋一下你應該也會發現用來開發 GUI 的框架少說也有五種以上,常見的 gtk, wxPython, java swing, QT,我嘗試用 gtk 不過因為覺得 UI 有點醜所以改用 wxPython,外觀比較像一般 Windows 的 UI,學習門檻也不會太高,輕鬆就完成一個簡單的 Widows 程式。

我嘗試將之前用 .NET 寫得 Course Transfer 移植到 Python+wxPython,這是一個簡單的 csv 依據規則轉換成 XML 的程式,使用的 UI 也都是基本控制項 Button, Label, TextBox, ProgressBar, DirDialog 等,也嘗試透過 Thread 在背景進行運算前端顯示進度,出乎意料的簡單,沒什麼需要特別處理,不同於 .NET 還要透過特別寫法才能更新 UI

Python 移植版本沒有特別進行一些檢查(目錄、檔案),所以程式比較短,檔案清單

test.py — 主程式
compile.py — py2exe 用的腳本
+cwc
– ui.py – UI
– utils.py – 輔助
– fs.py – 檔案 i

以下是畫面截圖

image image image

image

移植過程料處理部份沒有什麼問題,算是相當的簡單容易,csv 的處理也有內建的模組可用,唯一比較麻煩的部份是手工建立 UI 的排版,我想應該會有 wxPython 的 UI 設計工具才對,不然打造複雜 UI 是一件頭痛的事情。

還有將 python 程式轉成可執行程式,我在 Vista+VS2008+Python2.6+wxPython 所產生的 exe 無法在 XP SP2+VS2008 的環境運行,但是可在 Windows7執行,問題原因還沒找到,等找到後再報告吧。另外我在使用 py2exe 時,都會出現找不到 msvcp90.dll,我只好手動複製到 Python26 安裝目錄的 DLL,不太確定這樣作是否正確。

不過這是一個相當有趣的體驗,下次嘗試移植到 Python+pyQt 試試看 ^^

下載

Read Full Post »

最後一個物件 Date 主要也是兩個擴展 format 和 parse

 
var cfg = {
name: “,
dateTimeFormat: {
"AMDesignator":"AM","Calendar":{"MinSupportedDateTime":"@-62135568000000@","MaxSupportedDateTime":"@253402300799999@","AlgorithmType":1,"CalendarType":1,"Eras":[1],"TwoDigitYearMax":2029,"IsReadOnly":true},
"DateSeparator":"/","FirstDayOfWeek":0,"CalendarWeekRule":0,"FullDateTimePattern":"dddd, dd MMMM yyyy HH:mm:ss","LongDatePattern":"dddd, dd MMMM yyyy","LongTimePattern":"HH:mm:ss","MonthDayPattern":"MMMM dd","PMDesignator":"PM","RFC1123Pattern":"ddd, dd MMM yyyy HH’:’mm’:’ss ‘GMT’","ShortDatePattern":"MM/dd/yyyy","ShortTimePattern":"HH:mm","SortableDateTimePattern":"yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss","TimeSeparator":":","UniversalSortableDateTimePattern":"yyyy’-‘MM’-‘dd HH’:’mm’:’ss’Z’","YearMonthPattern":"yyyy MMMM","AbbreviatedDayNames":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"ShortestDayNames":["Su","Mo","Tu","We","Th","Fr","Sa"],"DayNames":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"AbbreviatedMonthNames":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""],"MonthNames":["January","February","March","April","May","June","July","August","September","October","November","December",""],"IsReadOnly":true,"NativeCalendarName":"Gregorian Calendar","AbbreviatedMonthGenitiveNames":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",""],"MonthGenitiveNames":["January","February","March","April","May","June","July","August","September","October","November","December",""]
}
};

cfg.StringBuilder = function(){
var data = [];
this.append = function(v){
data.push(v);
}

this.toString = function(){
return data.join(“);
}
};
Date._appendPreOrPostMatch = function(e, b) {
    var d = 0,
    a = false;
    for (var c = 0,
    g = e.length; c < g; c++) {
        var f = e.charAt(c);
        switch (f) {
        case "’":
            if (a) b.append("’");
            else d++;
            a = false;
            break;
        case "\":
            if (a) b.append("\");
            a = !a;
            break;
        default:
            b.append(f);
            a = false;
            break
        }
    }
    return d
};
Date._expandFormat = function(a, b) {
    if (!b) b = "F";
    if (b.length === 1) switch (b) {
    case "d":
        return a.ShortDatePattern;
    case "D":
        return a.LongDatePattern;
    case "t":
        return a.ShortTimePattern;
    case "T":
        return a.LongTimePattern;
    case "F":
        return a.FullDateTimePattern;
    case "M":
    case "m":
        return a.MonthDayPattern;
    case "s":
        return a.SortableDateTimePattern;
    case "Y":
    case "y":
        return a.YearMonthPattern;
    default:
        throw new Error(‘bad format’);
    }
    return b
};
Date._expandYear = function(c, a) {
    if (a < 100) {
        var b = (new Date).getFullYear();
        a += b – b % 100;
        if (a > c.Calendar.TwoDigitYearMax) return a – 100
    }
    return a
};
Date._getParseRegExp = function(b, e) {
    if (!b._parseRegExp) b._parseRegExp = {};
    else if (b._parseRegExp[e]) return b._parseRegExp[e];
    var c = Date._expandFormat(b, e);
    c = c.replace(/([^$.*+?|[](){}])/g, "\\$1");
    var a = new cfg.StringBuilder("^"),
    j = [],
    f = 0,
    i = 0,
    h = Date._getTokenRegExp(),
    d;
    while ((d = h.exec(c)) !== null) {
        var l = c.slice(f, d.index);
        f = h.lastIndex;
        i += Date._appendPreOrPostMatch(l, a);
        if (i % 2 === 1) {
            a.append(d[0]);
            continue
        }
        switch (d[0]) {
        case "dddd":
        case "ddd":
        case "MMMM":
        case "MMM":
            a.append("(\D+)");
            break;
        case "tt":
        case "t":
            a.append("(\D*)");
            break;
        case "yyyy":
            a.append("(\d{4})");
            break;
        case "fff":
            a.append("(\d{3})");
            break;
        case "ff":
            a.append("(\d{2})");
            break;
        case "f":
            a.append("(\d)");
            break;
        case "dd":
        case "d":
        case "MM":
        case "M":
        case "yy":
        case "y":
        case "HH":
        case "H":
        case "hh":
        case "h":
        case "mm":
        case "m":
        case "ss":
        case "s":
            a.append("(\d\d?)");
            break;
        case "zzz":
            a.append("([+-]?\d\d?:\d{2})");
            break;
        case "zz":
        case "z":
            a.append("([+-]?\d\d?)");
            break
        }

j[j.length] = d[0];
    }
    Date._appendPreOrPostMatch(c.slice(f), a);
    a.append("$");
    var k = a.toString().replace(/s+/g, "\s+"),
    g = {
        "regExp": k,
        "groups": j
    };
    b._parseRegExp[e] = g;
    return g
};
Date._getTokenRegExp = function() {
    return /dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z/g
};

/**
*
*
* example
var d = new Date();
alert( Date.parse(‘2009/09/21 12:06:46’, ‘yyyy/MM/dd hh:mm:ss’) ); // Mon Sep 21 00:06:46 UTC+0800 2009

*/
Date.parse = function(a) {
    return Date._parse(a, cfg, arguments)
};

Date._parse = function(g, c, h) {
    var e = false;
    for (var a = 1,
    i = h.length; a < i; a++) {
        var f = h[a];
        if (f) {
            e = true;
            var b = Date._parseExact(g, f, c);
            if (b) return b
        }
    }
    if (!e) {
        var d = c._getDateTimeFormats();
        for (var a = 0,
        i = d.length; a < i; a++) {
            var b = Date._parseExact(g, d[a], c);
            if (b) return b
        }
    }
    return null
};
Date._parseExact = function(s, y, j) {
    s = s.replace(/^s+|s+$/g, "");
    var m = j.dateTimeFormat,
    v = Date._getParseRegExp(m, y),
    x = (new RegExp(v.regExp)).exec(s);
    if (x !== null) {
        var w = v.groups,
        f = null,
        c = null,
        h = null,
        g = null,
        d = 0,
        n = 0,
        o = 0,
        e = 0,
        k = null,
        r = false;
        for (var p = 0,
        z = w.length; p < z; p++) {
            var a = x[p + 1];
            if (a) switch (w[p]) {
            case "dd":
            case "d":
                h = Date._parseInt(a);
                if (h < 1 || h > 31) return null;
                break;
            case "MMMM":
                c = j._getMonthIndex(a);
                if (c < 0 || c > 11) return null;
                break;
            case "MMM":
                c = j._getAbbrMonthIndex(a);
                if (c < 0 || c > 11) return null;
                break;
            case "M":
            case "MM":
                var c = Date._parseInt(a) – 1;
                if (c < 0 || c > 11) return null;
                break;
            case "y":
            case "yy":
                f = Date._expandYear(m, Date._parseInt(a));
                if (f < 0 || f > 9999) return null;
                break;
            case "yyyy":
                f = Date._parseInt(a);
                if (f < 0 || f > 9999) return null;
                break;
            case "h":
            case "hh":
                d = Date._parseInt(a);
                if (d === 12) d = 0;
                if (d < 0 || d > 11) return null;
                break;
            case "H":
            case "HH":
                d = Date._parseInt(a);
                if (d < 0 || d > 23) return null;
                break;
            case "m":
            case "mm":
                n = Date._parseInt(a);
                if (n < 0 || n > 59) return null;
                break;
            case "s":
            case "ss":
                o = Date._parseInt(a);
                if (o < 0 || o > 59) return null;
                break;
            case "tt":
            case "t":
                var u = a.toUpperCase();
                r = u === m.PMDesignator.toUpperCase();
                if (!r && u !== m.AMDesignator.toUpperCase()) return null;
                break;
            case "f":
                e = Date._parseInt(a) * 100;
                if (e < 0 || e > 999) return null;
                break;
            case "ff":
                e = Date._parseInt(a) * 10;
                if (e < 0 || e > 999) return null;
                break;
            case "fff":
                e = Date._parseInt(a);
                if (e < 0 || e > 999) return null;
                break;
            case "dddd":
                g = j._getDayIndex(a);
                if (g < 0 || g > 6) return null;
                break;
            case "ddd":
                g = j._getAbbrDayIndex(a);
                if (g < 0 || g > 6) return null;
                break;
            case "zzz":
                var q = a.split(/:/);
                if (q.length !== 2) return null;
                var i = Date._parseInt(q[0]);
                if (i < -12 || i > 13) return null;
                var l = Date._parseInt(q[1]);
                if (l < 0 || l > 59) return null;
                k = i * 60 + (a.startsWith("-") ? -l: l);
                break;
            case "z":
            case "zz":
                var i = Date._parseInt(a);
                if (i < -12 || i > 13) return null;
                k = i * 60;
                break
            }
        }
        var b = new Date;
        if (f === null) f = b.getFullYear();
        if (c === null) c = b.getMonth();
        if (h === null) h = b.getDate();
        b.setFullYear(f, c, h);
        if (b.getDate() !== h) return null;
        if (g !== null && b.getDay() !== g) return null;
        if (r && d < 12) d += 12;
        b.setHours(d, n, o, e);
        if (k !== null) {
            var t = b.getMinutes() – (k + b.getTimezoneOffset());
            b.setHours(b.getHours() + parseInt(t / 60), t % 60)
        }
        return b
    }
};
Date._parseInt = function(a) {
    return parseInt(a.replace(/^[s0]+(d+)$/, "$1"))
};

/**
* 日期格式化
*
* example
var d = new Date();
alert(d.format(‘yyyy/MM/dd hh:mm:ss’)); //

* @return {String}
*/
Date.prototype.format = function(a) {
    return this._toFormattedString(a, cfg)
};

Date.prototype._toFormattedString = function(e, h) {
    if (!e || e.length === 0 || e === "i") if (h && h.name.length > 0) return this.toLocaleString();
    else return this.toString();
    var d = h.dateTimeFormat;
    e = Date._expandFormat(d, e);
    var a = new cfg.StringBuilder,
    b;
    function c(a) {
        if (a < 10) return "0" + a;
        return a.toString()
    }
    function g(a) {
        if (a < 10) return "00" + a;
        if (a < 100) return "0" + a;
        return a.toString()
    }
    var j = 0,
    i = Date._getTokenRegExp();
    for (; true;) {
        var l = i.lastIndex,
        f = i.exec(e),
        k = e.slice(l, f ? f.index: e.length);
        j += Date._appendPreOrPostMatch(k, a);
        if (!f) break;
        if (j % 2 === 1) {
            a.append(f[0]);
            continue
        }
        switch (f[0]) {
        case "dddd":
            a.append(d.DayNames[this.getDay()]);
            break;
        case "ddd":
            a.append(d.AbbreviatedDayNames[this.getDay()]);
            break;
        case "dd":
            a.append(c(this.getDate()));
            break;
        case "d":
            a.append(this.getDate());
            break;
        case "MMMM":
            a.append(d.MonthNames[this.getMonth()]);
            break;
        case "MMM":
            a.append(d.AbbreviatedMonthNames[this.getMonth()]);
            break;
        case "MM":
            a.append(c(this.getMonth() + 1));
            break;
        case "M":
            a.append(this.getMonth() + 1);
            break;
        case "yyyy":
            a.append(this.getFullYear());
            break;
        case "yy":
            a.append(c(this.getFullYear() % 100));
            break;
        case "y":
            a.append(this.getFullYear() % 100);
            break;
        case "hh":
            b = this.getHours() % 12;
            if (b === 0) b = 12;
            a.append(c(b));
            break;
        case "h":
            b = this.getHours() % 12;
            if (b === 0) b = 12;
            a.append(b);
            break;
        case "HH":
            a.append(c(this.getHours()));
            break;
        case "H":
            a.append(this.getHours());
            break;
        case "mm":
            a.append(c(this.getMinutes()));
            break;
        case "m":
            a.append(this.getMinutes());
            break;
        case "ss":
            a.append(c(this.getSeconds()));
            break;
        case "s":
            a.append(this.getSeconds());
            break;
        case "tt":
            a.append(this.getHours() < 12 ? d.AMDesignator: d.PMDesignator);
            break;
        case "t":
            a.append((this.getHours() < 12 ? d.AMDesignator: d.PMDesignator).charAt(0));
            break;
        case "f":
            a.append(g(this.getMilliseconds()).charAt(0));
            break;
        case "ff":
            a.append(g(this.getMilliseconds()).substr(0, 2));
            break;
        case "fff":
            a.append(g(this.getMilliseconds()));
            break;
        case "z":
            b = this.getTimezoneOffset() / 60;
            a.append((b >= 0 ? "+": "-") + Math.floor(Math.abs(b)));
            break;
        case "zz":
            b = this.getTimezoneOffset() / 60;
            a.append((b >= 0 ? "+": "-") + c(Math.floor(Math.abs(b))));
            break;
        case "zzz":
            b = this.getTimezoneOffset() / 60;
            a.append((b >= 0 ? "+": "-") + c(Math.floor(Math.abs(b))) + d.TimeSeparator + c(Math.abs(this.getTimezoneOffset() % 60)));
            break
        }
    }
    return a.toString()
};

Read Full Post »

主要就是解析與格式化兩個功能

/**
* 字串解析數值
*
* example:
alert(Number.parse("-1.234")*2);  // -2.468
alert(Number.parse("0xf"));  // 15
alert(Number.parse("1,234,567.89"));  // 1234567.89
alert(Number.parse("1,234,567.89E4"));  // 12345678900
* @param {String} g
* @return
*/

Number.parse = function(g) {
    var a = g.replace(/^s+|s+$/g, "");
    if (a.match(/infinity/i) !== null) return parseFloat(a);
    if (a.match(/^0x[a-f0-9]+$/i) !== null) return parseInt(a);

    var d = {
NumberDecimalSeparator: ‘.’,
NumberGroupSeparator: ","
};
    b = d.NumberDecimalSeparator,
    c = d.NumberGroupSeparator,
    e = new RegExp("^[+-]?[\d\" + c + "]*\" + b + "?\d*([eE][+-]?\d+)?$");
    if (!a.match(e)) return Number.NaN;
    a = a.split(c).join("");
    a = a.replace(b, ".");
    return parseFloat(a)
};

/**
* 數值格式化
*
* exmaple:
var x = 123456789;
alert( x.format("d") ); // 123456789
alert( x.format("n") ); // 123,456,789.00
alert( x.format("c") ); // $123,456,789.00
alert( x.format("p") ); // 123,456,789.00 %
*
* @param {String} 格式化參數
* @return {String}
*/

Number.prototype.format = function(a) {
    return this._toFormattedString(a, {
name: “,
numberFormat: {
"CurrencyDecimalDigits":2,
"CurrencyDecimalSeparator":".",
"IsReadOnly":true,
"CurrencyGroupSizes":[3],
"NumberGroupSizes":[3],
"PercentGroupSizes":[3],
"CurrencyGroupSeparator":",",
"CurrencySymbol": ‘$’,
"NaNSymbol":"NaN",
"CurrencyNegativePattern":0,
"NumberNegativePattern":1,
"PercentPositivePattern":0,
"PercentNegativePattern":0,
"NegativeInfinitySymbol":"-Infinity",
"NegativeSign":"-",
"NumberDecimalDigits":2,
"NumberDecimalSeparator":".",
"NumberGroupSeparator":",",
"CurrencyPositivePattern":0,
"PositiveInfinitySymbol":"Infinity",
"PositiveSign":"+",
"PercentDecimalDigits":2,
"PercentDecimalSeparator":".",
"PercentGroupSeparator":",",
"PercentSymbol":"%",
"PerMilleSymbol":"u2030",
"NativeDigits":["0","1","2","3","4","5","6","7","8","9"],
"DigitSubstitution":1
}
});
};

Number.prototype._toFormattedString = function(d, j) {
    if (!d || d.length === 0 || d === "i") if (j && j.name.length > 0) return this.toLocaleString();
    else return this.toString();
    var q = ["n %", "n%", "%n"],
    p = ["-n %", "-n%", "-%n"],
    r = ["(n)", "-n", "- n", "n-", "n -"],
    o = ["$n", "n$", "$ n", "n $"],
    n = ["($n)", "-$n", "$-n", "$n-", "(n$)", "-n$", "n-$", "n$-", "-n $", "-$ n", "n $-", "$ n-", "$ -n", "n- $", "($ n)", "(n $)"];

    function i(p, k, j, l, o) {
        var e = j[0],
        g = 1,
        c = p.toString(),
        a = "",
        m = "",
        i = c.split(".");
        if (i.length > 1) {
            c = i[0];
            a = i[1];
            var h = a.split(/e/i);
            if (h.length > 1) {
                a = h[0];
                m = "e" + h[1]
            }
        }
        if (k > 0) {
            var f = a.length – k;
            if (f > 0) a = a.slice(0, k);
            else if (f < 0) for (var n = 0; n < Math.abs(f); n++) a += "0";
            a = o + a
        } else a = "";
        a += m;
        var b = c.length – 1,
        d = "";
        while (b >= 0) {
            if (e === 0 || e > b) if (d.length > 0) return c.slice(0, b + 1) + l + d + a;
            else return c.slice(0, b + 1) + a;
            if (d.length > 0) d = c.slice(b – e + 1, b + 1) + l + d;
            else d = c.slice(b – e + 1, b + 1);
            b -= e;
            if (g < j.length) {
                e = j[g];
                g++
            }
        }
        return c.slice(0, b + 1) + l + d + a
    }
    var a = j.numberFormat,
    e = Math.abs(this);
    if (!d) d = "D";
    var b = -1;
    if (d.length > 1) b = parseInt(d.slice(1));
    var c;
    switch (d.charAt(0)) {
    case "d":
    case "D":
        c = "n";
        if (b !== -1) {
            var g = "" + e,
            k = b – g.length;
            if (k > 0) for (var m = 0; m < k; m++) g = "0" + g;
            e = g
        }
        if (this < 0) e = -e;
        break;
    case "c":
    case "C":
        if (this < 0) c = n[a.CurrencyNegativePattern];
        else c = o[a.CurrencyPositivePattern];
        if (b === -1) b = a.CurrencyDecimalDigits;
        e = i(Math.abs(this), b, a.CurrencyGroupSizes, a.CurrencyGroupSeparator, a.CurrencyDecimalSeparator);
        break;
    case "n":
    case "N":
        if (this < 0) c = r[a.NumberNegativePattern];
        else c = "n";
        if (b === -1) b = a.NumberDecimalDigits;
        e = i(Math.abs(this), b, a.NumberGroupSizes, a.NumberGroupSeparator, a.NumberDecimalSeparator);
        break;
    case "p":
    case "P":
        if (this < 0) c = p[a.PercentNegativePattern];
        else c = q[a.PercentPositivePattern];
        if (b === -1) b = a.PercentDecimalDigits;
        e = i(Math.abs(this), b, a.PercentGroupSizes, a.PercentGroupSeparator, a.PercentDecimalSeparator);
        break;
    default:
        throw new Error(‘bad format’);
    }
    var l = /n|$|-|%/g,
    f = "";
    for (; true;) {
        var s = l.lastIndex,
        h = l.exec(c);
        f += c.slice(s, h ? h.index: c.length);
        if (!h) break;
        switch (h[0]) {
        case "n":
            f += e;
            break;
        case "$":
            f += a.CurrencySymbol;
            break;
        case "-":
            f += a.NegativeSign;
            break;
        case "%":
            f += a.PercentSymbol;
            break
        }
    }
    return f
};

Read Full Post »

幾個好用的字串擴展,其中 String.format 真是超級好用,ExtJs 也有提供一個類似的函數
/** 
 * 檢查後面字串是否與指定字串匹配
 *
 * example:
	var a = 'Chui-Wen Chiu';
	alert( a.endsWith('Chiu') ); // true

 * @param {String} a 要匹配的字串
 * @return {Boolean}
 */
String.prototype.endsWith = function(a) {
    return this.substr(this.length - a.length) === a
};

/** 
 * 檢查開頭字串是否與指定字串匹配
 *
 * example:
	var a = 'Chui-Wen Chiu';
	alert( a.startsWith('Chui') ); // true

 * @param {String} a 要匹配的字串
 * @return {Boolean}
 */
String.prototype.startsWith = function(a) {
    return this.substr(0, a.length) === a
};


/**
 * trim:去除兩邊空格
 *
 * example:
	var x = ' abc ';
	alert( '-->' + x.trim() + '<--'); // -->abc<--
 *
 * Ver2
 this.replace(/(^[s]*)|([s]*$)/g, "")
 *
 * @return {String}
 */
String.prototype.trim = function() {
    return this.replace(/^s+|s+$/g, "")
};

/**
 * 去除右側空格
 *
 * example:
	var x = ' abc ';
	alert( '-->' + x.trimEnd() + '<--'); // --> abc<--
 *
 * Version
return this.replace(/([s]*$)/g, "");
 * @return {String}
 */
String.prototype.trimEnd = function() {
    return this.replace(/s+$/, "")
};

/**
 * 去除左側空格
 *
 * example:
	var x = ' abc ';
	alert( '-->' + x.trimStart() + '<--'); // -->abc <--
 *
 * 另一個版本
this.replace(/([s]*$)/g, "")

 * @return {String}
 */
String.prototype.trimStart = function() {
    return this.replace(/^s+/, "")
};

/**
 * 字串格式化
 *
 * example:
	alert( String.format("a={0}, b={1}, c={0}", 10, 100) ); // a=10, b=100, c=10

 * @param {Mixed}
 * @return {String}
 */
String.format = function() {
    return String._toFormattedString(false, arguments)
};

/**
 *
 *
 * @param {Boolean}	l
 * @param {Mixed}	j
 * @return {String}
 */
String._toFormattedString = function(l, j) {
    var c = "",
    e = j[0];
    for (var a = 0; true;) {
        var f = e.indexOf("{", a),
        d = e.indexOf("}", a);
        if (f < 0 && d < 0) {
            c += e.slice(a);
            break
        }
        if (d > 0 && (d < f || f < 0)) {
            c += e.slice(a, d + 1);
            a = d + 2;
            continue
        }
        c += e.slice(a, f);
        a = f + 1;
        if (e.charAt(a) === "{") {
            c += "{";
            a++;
            continue
        }
        if (d < 0) break;
        var h = e.substring(a, d),
        g = h.indexOf(":"),
        k = parseInt(g < 0 ? h: h.substring(0, g)) + 1,
        i = g < 0 ? "": h.substring(g + 1),
        b = j[k];
        if (typeof b === "undefined" || b === null) b = "";
        if (b.toFormattedString) c += b.toFormattedString(i);
        else if (l && b.localeFormat) c += b.localeFormat(i);
        else if (b.format) c += b.format(i);
        else c += b.toString();
        a = d + 1
    }
    return c
};

Read Full Post »

這次提煉出用於 Function 的三個擴展,雖然不多但是常用於 js 的基礎框架中,如下:

 

/**
 * 建立回呼(callback) 
 *
 * example:

function doCallback(num, callback){
	callback(num*100);
}

doCallback( 9, Function.createCallback( function(v, data ){
	if(v==data){
		alert('pass');
	}else{
		alert('fail');
	}
}, 900));

 * @param {Function} b
 * @param {Mixed} a 最後一個參數
 * @return {Function} 
 */
Function.createCallback = function(b, a) {
    return function() {
        var e = arguments.length;
        if (e > 0) {
            var d = [];
            for (var c = 0; c < e; c++) d[c] = arguments[c];
            d[e] = a;
            return b.apply(this, d)
        }
        return b.call(this, a)
    }
};

/**
 * 建立委託(delegate) 
 *
 * example:
var a = {
	name: 'Chui-Wen Chiu'
};

var delegate = Function.createDelegate(a, function(prefox, postfix){
	return prefix + this.name + postfix;
});

alert( delegate("-->", "<--") ); // -->Chui-Wen Chiu<--

 * @param {Object} a
 * @param {Function} b
 * @return {Function} 
 */
Function.createDelegate = function(a, b) {
    return function() {
        return b.apply(a, arguments)
    }
};

/** 
 * 空函數
 *
 * example:

var My = {
	changeEventHandler: Function.emptyMethod,
	v: 0,
	setValue: function(v){
		if(v!=this.v){
			this.changeEventHandler.call(this, v);
		}
	}
};

My.setValue(100); // nothing
My.changeEventHandler = function(v){
	alert(v);
};
My.setValue(100); // 
 */
Function.emptyFunction = Function.emptyMethod = function() {};

Read Full Post »

最近花了點時間瞭解 ASP.NET 提供的 Ajax 框架,使用過後發現真的非常簡單亦用,JS 寫的數量也極低,主要原因是框架提供了一個 MicrosoftAjax.js 腳本與 ASP.NET 緊密整合,呼叫 Server 端的方法就像呼叫 JS 一般函數的自然,如果你用過 PHP 的框架 xajax,其實兩者的實作差不多,都是透過 Server 產生封裝過 JS,所以用戶端才可以透過簡單的函數呼叫來取用 Server 端的功能。

除了上述的優勢之外,其實在 MicrosoftAjax.js 有一組實作擴展了 Javascript 的內建物件,我覺得在網頁開發上相當實用,接下來幾篇就是我提煉的結果,這篇主要是 Array 的擴展

// ——————- JS Code ——————-

/**
 *  將 b 元素附加到 a 陣列之後
 *
 * example:
var x = [1, 2, 3, 4, 5];
Array.add(x, 6); //[1,2,3,4,5,6]

 * @param {Array} a 
 * @param {Object} b
 */
Array.add = Array.enqueue = function(a, b) {
    a[a.length] = b
};

/**
 *  將陣列 b 全部元素附加到 a 陣列之後
 *
 * example:
	var x = [1,2,3];
	var y = [4,5];
	Array.addRange(x,y);
	alert(x,y); // x = [1,2,3,4,5]

 * @param {Array} a 
 * @param {Array} b
 */
Array.addRange = function(a, b) {
    a.push.apply(a, b)
};

/**
 * 清空陣列
 *
 * example:
	var x = [1,2,3];
	Array.clear(x);
	alert(x); // x = []

 * @param {Array} a 
 */
Array.clear = function(a) {
    a.length = 0
};

/**
 * 完整深層複製一份陣列
 *
 * example:
	var x = [1,2,3];
	var y = Array.clone(x);
	alert(y); // y = [1,2,3]

 * @param {Array} a 
 * @return {Array}
 */
Array.clone = function(a) {
    if (a.length === 1) return [a[0]];
    else return Array.apply(null, a)
};

/**
 * 找尋指定元素在陣列中的索引位置
 *
 * example:
	var x = ['a', 'b', 'c','d'];
	alert( Array.indexOf(x, 'b') ); // 1
	alert( Array.indexOf(x, 'b', -4) ); // 1
	alert( Array.indexOf(x, 'b', 0) ); // 1
	alert( Array.indexOf(x, 'b', 2) ); // -1
 * @param {Array} d
 * @param {Mixed} e 要尋找的元素
 * @param {int} a 起始索引, 非數值0從 0 開始,小於 0 從反向位置開始
 * @return {int} -1=沒有找到, 否則回傳批配的元素索引
 */
Array.indexOf = function(d, e, a) {
    if (typeof e === "undefined") return - 1;
    var c = d.length;
    if (c !== 0) {
        a = a - 0;
        if (isNaN(a)) a = 0;
        else {
            if (isFinite(a)) a = a - a % 1;
            if (a < 0) a = Math.max(0, c + a)
        }
        for (var b = a; b < c; b++) if (typeof d[b] !== "undefined" && d[b] === e) return b
    }
    return - 1
};

/**
 * 找尋指定元素是否在陣列中
 * {@link Array.indexOf}
 *
 * example:
	var x = ['a', 'b', 'c','d'];
	alert( Array.indexOf(x, 'b') ); // 1
	alert( Array.indexOf(x, 'b', -4) ); // 1
	alert( Array.indexOf(x, 'b', 0) ); // 1
	alert( Array.indexOf(x, 'b', 2) ); // -1
 * @param {Array} a
 * @param {Mixed} b 要尋找的元素
 * @return {Boolean} 
 */
Array.contains = function(a, b) {
    return Array.indexOf(a, b) >= 0
};

/**
 * 移除陣列第一個元素
 *
 * example:
	var x = ['a', 'b', 'c','d'];
	Array.dequeue(x); 
	alert(x); // x = ['b', 'c', 'd']

 * @param {Array} a
 * @return {Mixed} 被移除的元素
 */
Array.dequeue = function(a) {
    return a.shift()
};

/**
 * 移除陣列指定索引的元素
 *
 * example:
	var x = ['a', 'b', 'c','d'];
	Array.removeAt(x, 1); 
	alert(x); // x = ['a', 'c', 'd']

 * @param {Array} a
 * @param {int} b 陣列索引
 */
Array.removeAt = function(a, b) {
    a.splice(b, 1)
};

/**
 * 移除陣列中第一個符合指定條件的元素
 *
 * example:
	var x = ['a', 'b', 'c','d'];
	Array.remove(x, 'b'); 
	alert(x); // x = ['a', 'c', 'd']

 * @param {Array} b 陣列
 * @param {Mixed} c 要搜尋的元素
 * @param {Boolean} 
 */
Array.remove = function(b, c) {
    var a = Array.indexOf(b, c);
    if (a >= 0) b.splice(a, 1);
    return a >= 0
};

/**
 * 使用指定的函數迭代套用陣列的每個元素
 *
 * example:
	var x = ['a', 'b', 'c','d'];
	Array.forEach(x, function(elem, index, array_object){
		array_object[index] = '[' + elem  + ']';
	});
	alert(x); // x=['[a]', '[b]', '[c]', '[d]'];

	var y = ['a', 'b', 'c','d'];
	var My = {
		fix: function(elem, index, array_object){
			array_object[index] = '[' + elem  + ']';
		}
	};
	Array.forEach(y, My.fix, My);
	alert(y); // y=['[a]', '[b]', '[c]', '[d]'];
 * @param {Array} b
 * @param {Function} e 套用到陣列元素的方法
 * @param {Object} d 方法所屬的物件
 * @param {int} b 陣列索引
 */
Array.forEach = function(b, e, d) {
    for (var a = 0,
    f = b.length; a < f; a++) {
        var c = b[a];
        if (typeof c !== "undefined") e.call(d, c, a, b)
    }
};

/**
 * 在陣列指定的位置上插入元素
 *
 * example:
	var x = ['a', 'b', 'c'];
	Array.insert(x, 1, '**');
	alert(x); // x=['a', '**', 'b', 'c', 'd'];

 * @param {Array} a
 * @param {int} b 指定要插入的索引位置
 * @param {Mixed} c 插入的元素
 */
Array.insert = function(a, b, c) {
    a.splice(b, 0, c)
};

/**
 * 字串轉陣列
 *
 * example:
	alert(Array.parse('[1,2,3,4]')); // [1,2,3,4]

 * @param {String} value
 * @return {Mixed}
 */

Array.parse = function(value) {
    if (!value) return [];
    return eval(value)
};

Read Full Post »

將粗體紅色文字修改成你要的 PDF/PPT 網址即可

PDF 效果

<iframe src="http://docs.google.com/gview?url=http://www.cluesheets.com/SO8DrawCS.pdf&embedded=true" style="width:600px; height:500px;" frameborder="0"></iframe>

執行結果

image

PPT 效果

<iframe src="http://docs.google.com/gview?url=http://www.ym.edu.tw/pnl/960907-5.ppt&embedded=true" style="width:600px; height:500px;" frameborder="0"></iframe>

執行結果

image

Read Full Post »

數學習題產生器

微軟實驗室丟一個"數學習題產生器",可讓老師依據特定題型產生 HTML/WORD 版本的數學考試卷和答案,真是太神奇了傑克,我下載了目前版本來測試。

操作介面很簡單不需要學習就會使用

image

以下兩個連結是分別是考試卷和答案卷的連結

1. 考試卷

image

2. 答案卷

image

 

目前這個版本支援的數學題型有

  1. 四則運算
  2. 分數運算
  3. 小數運算
  4. 線性方程式
  5. 二元一次聯立方程式

已知的一些問題(針對 HTML,電腦沒裝 WORD ,不知道 Word 產生結果)

  1. 題目圖形不太清楚
  2. 產生的題型圖片放在系統的 temp 路徑而非 html 所在路徑,需要後處理才能佈署在網路上

總結,我覺得這套軟體相當不錯,要自行實做這類軟體的 2 個關鍵是

1. 如何分析使用這輸入的題型

2. 如何依據輸入的字串,產生正規的數學方程式

第一個是牽涉語法分析不是我擅長,我只能處理簡單的數值四則運算。第二個如果是用於 Web 也許可透過 jsMath 解決。

如果第一個問題能夠解決,也想寫一個來看看

Read Full Post »

ClickOnce 真的是一個很棒的技術,不過有一個討厭的問題就是對 IE6 支援不好,在 IE7, IE8 甚至裝了 Microsoft .NET Framework Assistant 的 Firefox 都運作的很好,就是 IE6 在啟動 .application 時會出現 XML 而不是安裝畫面。本來不想解決這個問題,不過礙於 IE6 無法消失的現實,還是在尋找一下解決方案。

目前找到 3 個解法

1. 使用將 .application 的超連結改為 setup.exe,因此當使用者點選 setup.exe 時會執行下載,讓使用者透過 setup.exe 進行安裝,後續透過開始功能表的程式執行即可,線上更新功能不受影響,缺點就是無法透過網頁執行。

2. ClickOnce 產生的檔案程式打包成 zip,讓使用者下載自己執行 setup.exe,基本上與解法 1 相同,只是流程與一般軟體相同。一樣具有無法直接透過網頁啟動的缺點。

3. 讓 IE6 認得 application 並執行,首先有兩個必要條件

  1. 用戶端電腦的 .application 副檔名必須設定關聯,預設動作為 rundll32.exe dfshim.dll,ShOpenVerbApplication %1
  2. 伺服端必須設定 .application 的 MIME 為 application/x-ms-application

一般 IE6 認不得 application 的原因都在條件2不滿足,可是 IE7 和 IE8 可能有經過處理,所以不會有問題。因此,我們可以修改 ClickOnce 產生的 html(如:publish.html),將

directLink = "WindowsFormsApplication1.application";

取代為

directLink = "WindowsFormsApplication1.application.php";

然後複製一份 WindowsFormsApplication1.application 成 WindowsFormsApplication1.application.php

並將

<?xml version="1.0" encoding="utf-8"?>

取代為

<?php header("Content-Type: application/x-ms-application"); ?>

即可,不過我發現 ClickOnce 產生的 .html 採用 UTF-8+BOM,這樣在執行 header 時會有問題,所以也將編碼改為 UTF-8。

如此就可以讓笨笨的 IE6 認得 ClickOnce 的程式,也可以順利在網頁上執行程式。

以下為測試網址:

http://cwchiu.chuiwenchiu.tu2.ru/test/publish.html

執行畫面

image

image

參考資料
[1] http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/bd48e757-0d49-4b94-a7d3-26363bdaeb83

Read Full Post »