2010年5月19日 星期三

[iPad/iPhone] Javascript + jQuery + ePub + WebKit + HTML5 + iBooks ?


圖片來源 - http://webkit.org/


電子書用 iBooks 看,沒有什麼稀奇,但 iBooks 的閱讀器是用修修改改的 WebKit 做,那可就好玩了!因為 ePub 裡的格式幾乎就像 XHTML 一般,如果呈現它的閱讀軟體可以支援網頁上豐富的互動,那電子書就不再枯燥乏味了!況且 WebKit 有支援 HTML5 與 Javascript 耶,那是不是電子書的內容就可變動了呢?


上週老闆說,iPad 裡頭的 iBooks 是用 WebKit 實作的,當下就聽到他弄出 HTML5 的特效出來,這週開始來測測上頭的 WebKit 到底有甚麼可以玩的,首先擺於上傳自己的電子書,方法很簡單,就是建立出 epub 格式,再把他拖進 iTunes ,那就會出現"書櫃"的項目,接著再切換到 device 上頭,跑去該項目按一下同步!資料就傳送到 iPad 上,並且可以用 iBooks 去瀏覽。細節可以參考這篇:[iPhone/iPad] 匯入自製的 ePub 電子書 至 iBooks


目前測試 Javascript 的結果,可以用 alert 對 document 跟 window 物件測試一下,代表有此物件可以用,所以接下來測試 document.getElementById 也是 OK 的,當然,去改某個物件的 innerHTML 也是可以成功啦!接著,野心更大就是丟個 jQuery 進去吃吃,發現也 ok 啦!


之前是先寫一個簡單的 HTML 檔案,然後用 Calibre 把他轉成 ePub 來用,後來測試幾次後,發現 script 會被它轉爛,當時還一直以為是 WebKit 的功能被縮減掉(但真的有其他的功能被拿掉了,如 js 的 document.write),浪費不少時間測試,最後,就變成自己手動去建 ePub 啦!建議可以先用 Calibre 建立一個範例檔,然後把它解開來,除了確認內文是否正常,也可以當作一個範本,以後修改完內文就可以快速打包囉!


指令:


$ cd epub
$ ls
META-INF        cover_image.jpg        jquery.html        stylesheet.css        toc.ncx
content.opf        jquery-1.4.2.min.js    mimetype        titlepage.xhtml

打包指令:
$ zip -0Xq ../test.epub mimetype
$ zip -Xr9Dq ../test.epub *


把所在目錄的東西, 打包成 test.epub 並擺到上一層目錄裡


以下是 jquery.html 程式碼:


<?xml version='1.0' encoding='utf-8'?>
<html xmlns="http://www.w3.org/1999/xhtml">
        <head>
                <title>jQuery on local</title>
                <script language="JavaScript" TYPE="text/javascript" src="jquery-1.4.2.min.js"></script>
                <script language="JavaScript" TYPE="text/javascript">
                function updateByjQuery()
                {
                        var curr = new Date();
                        var y = curr.getFullYear();
                        var m = curr.getMonth() + 1;
                        var d = curr.getDate();
                        var h = curr.getHours();
                        var min = curr.getMinutes();
                        var sec = curr.getSeconds();
                        $( '#1' ).html( 'By jQuery: '+y+'/'+m+'/'+d+' '+h+':'+min+':'+sec );
                }
                function updateBygetElementById()
                {
                        var curr = new Date();
                        var y = curr.getFullYear();
                        var m = curr.getMonth() + 1;
                        var d = curr.getDate();
                        var h = curr.getHours();
                        var min = curr.getMinutes();
                        var sec = curr.getSeconds();
                        document.getElementById( '1' ).innerHTML = 'By getElementById: ' +y+'/'+m+'/'+d+' '+h+':'+min+':'+sec;
                }
                function ajaxByjQuery()
                {
                        $.ajax({
                                async: false,
                                type: "GET",
                                dataType: "html",
                                url: "http://tw.yahoo.com",


                                success: function(data) {
                                        alert( data ) ;
                                }
                        });
                }
                function dumpObj(obj, name, indent, depth) {    // modified from http://geekswithblogs.net/svanvliet/archive/2006/03/23/simple-javascript-object-dump-function.aspx
                        if (depth > 1)
                                return ( indent + name + ": 'Maximum Depth Reached'\n" );
                        if(typeof obj == "function") {
                                return "func: " + name + "\n";
                        } else if (typeof obj == "object") {
                                var child = null;
                                var output = indent + name + "\n";
                                indent += "\t";
                                for (var item in obj) {
                                        try {
                                                child = obj[item];
                                        } catch (e) {
                                                child = "'UnableToEvaluate'";
                                        }
                                        if(typeof child == "function") {
                                                output += indent + " func: " + item + "\n";
                                        } else if (typeof child == "object") {
                                                //output += dumpObj(child, item, indent, depth + 1);
                                        } else {
                                                //output += indent + item + ": " + child + "\n";
                                        }
                                }
                                return output;
                        } else {
                                //return obj;
                        }
                }
                </script>
                <meta content="http://www.w3.org/1999/xhtml; charset=utf-8" http-equiv="Content-Type"/>
        </head>
        <body>
                <div id="main">
                        <p id="1">Hello World</p>
                </div>
                <hr/>
                <p>
                        <span onclick="alert(window);">alert(window)</span><br />
                        <span onclick="alert(document);">alert(document)</span><br />
                        <span onclick="alert(document.write);">alert(document.write)</span><br />
                        <span onclick="alert(jQuery);">alert(jQuery)</span><br />
                        <span onclick="alert($);">alert($)</span><br />
                        <span onclick="var curr = new Date();var y = curr.getFullYear();var m = curr.getMonth() + 1;var d = curr.getDate();var h = curr.getHours();var min = curr.getMinutes();var sec = curr.getSeconds();$( '#1' ).html( 'By inline:'+y+'/'+m+'/'+d+' '+h+':'+min+':'+sec );">update by inline (use jQuery)</span><br />
                        <span onclick="updateByjQuery();">update by func (use jQuery)</span><br />
                        <span onclick="updateBygetElementById();">update by func (use document.getElementById)</span><br />
                        <span onclick="$.ajax({async: false,type: 'GET',dataType: 'html',url: 'http://tw.yahoo.com', success: function(data) {alert( data ) ;}});">inline ajax call (use jQuery)</span><br />
                        <span onclick="ajaxByjQuery();">ajax call by func</span><br />
                        <span onclick="alert( dumpObj(document, 'document', '\t', 0) );">dump document</span><br />
                </p>
        </body>
</html>


心得:



  1. 若用 <script language="JavaScript" TYPE="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script> 這種方式, 則打開書的時候, 整個會空白, 但改用以下方式就沒問題:

    • <script language="JavaScript" TYPE="text/javascript" src="jquery-1.4.2.min.js"></script>

    • 新增 content.opf 的 manifest


      • <item href="jquery-1.4.2.min.js" id="jquery" media-type="text/javascript"/>



    • 最後,記得把 jquery-1.4.2.min.js 也擺進去打包



  2. 有些地方, 如在寫 inline 時, 若碰到 '<' 符號會被判斷成語法錯誤, 所以得要設法避開

  3. 在 head 定義 js func 時, 不要用 <!-- 與 // --> 去處理, 這樣定義出來不能使用, 即:

    <script language="JavaScript" TYPE="text/javascript"><!--
    func hehe() {}
    // -->
    </script>


一些成果:


測試 jQuery
jquery


錯誤訊息
error


列出 document 相關函數
document_func


沒有留言:

張貼留言