├── source ├── video.md ├── code.md ├── people.md ├── science.md ├── article.md ├── hardware.md ├── preface.md ├── software.md ├── pdffooter.htm ├── focus.md ├── md0.js ├── Makefile ├── convert.exe ├── mimetex.exe ├── tex2img.bat ├── title.md ├── metadata.xml ├── header.htm ├── tex2img.sh ├── footer.htm ├── editor.md ├── reflink.md9 ├── license.md ├── focus4.md ├── focus2.md ├── home.md ├── article2.md ├── info.md ├── focus1.md ├── focus3.md └── article1.md ├── book ├── A4.pdf ├── A4.epub ├── ipad.epub └── ipad.pdf ├── img ├── mt.jpg ├── cover.jpg ├── coverA4.png └── mt_back.jpg ├── code ├── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── js │ ├── npm.js │ ├── bootstrap-filestyle.min.js │ └── bootstrap.min.js ├── home.html ├── help.html ├── navmenu.js ├── dict.js ├── spa.js ├── dict.html ├── account.html ├── elearn.css ├── elearn.html ├── mt.html ├── login.html └── css │ ├── bootstrap-theme.min.css │ └── bootstrap-theme.css ├── submit └── 利用 SQL Compact Edition 免費建立擁有 DataBase 的 Azure Websites.doc ├── README.md ├── htm ├── preface.html ├── code.html ├── people.html ├── science.html ├── video.html ├── article.html ├── hardware.html ├── software.html ├── focus.html ├── title.html ├── editor.html ├── license.html ├── focus4.html ├── focus2.html ├── article2.html ├── home.html ├── focus1.html ├── info.html ├── focus3.html └── article1.html └── css └── pmag.css /source/video.md: -------------------------------------------------------------------------------- 1 | # 影音頻道 2 | -------------------------------------------------------------------------------- /source/code.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/people.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/science.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/article.md: -------------------------------------------------------------------------------- 1 | # 程式人文集 2 | 3 | -------------------------------------------------------------------------------- /source/hardware.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/preface.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 3 | 4 | -------------------------------------------------------------------------------- /source/software.md: -------------------------------------------------------------------------------- 1 | 2 | # 影音頻道 3 | -------------------------------------------------------------------------------- /source/pdffooter.htm: -------------------------------------------------------------------------------- 1 |
_PAGENUM_
2 | -------------------------------------------------------------------------------- /source/focus.md: -------------------------------------------------------------------------------- 1 | # 本期焦點:令人眼花撩亂的 javascript -- 前端技術篇 2 | -------------------------------------------------------------------------------- /book/A4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/book/A4.pdf -------------------------------------------------------------------------------- /img/mt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/img/mt.jpg -------------------------------------------------------------------------------- /book/A4.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/book/A4.epub -------------------------------------------------------------------------------- /book/ipad.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/book/ipad.epub -------------------------------------------------------------------------------- /book/ipad.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/book/ipad.pdf -------------------------------------------------------------------------------- /img/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/img/cover.jpg -------------------------------------------------------------------------------- /source/md0.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/source/md0.js -------------------------------------------------------------------------------- /code/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/code/favicon.ico -------------------------------------------------------------------------------- /img/coverA4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/img/coverA4.png -------------------------------------------------------------------------------- /img/mt_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/img/mt_back.jpg -------------------------------------------------------------------------------- /source/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/source/Makefile -------------------------------------------------------------------------------- /source/convert.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/source/convert.exe -------------------------------------------------------------------------------- /source/mimetex.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/source/mimetex.exe -------------------------------------------------------------------------------- /source/tex2img.bat: -------------------------------------------------------------------------------- 1 | if not exist {%2.jpg} ( 2 | mimetex -d %1 -e %2.gif 3 | convert %2.gif %2.jpg 4 | rm %2.gif 5 | ) 6 | -------------------------------------------------------------------------------- /source/title.md: -------------------------------------------------------------------------------- 1 | % [程式人雜誌](http://programmermagazine.github.com/home/) 2 | % 2015 年 1 月 3 | % 本期焦點:令人眼花撩亂的 javascript -- 前端技術篇 4 | -------------------------------------------------------------------------------- /source/metadata.xml: -------------------------------------------------------------------------------- 1 | Creative Commons Non-Commercial Share Alike 3.0 2 | en-US 3 | -------------------------------------------------------------------------------- /code/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/code/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /code/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/code/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /code/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/code/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /submit/利用 SQL Compact Edition 免費建立擁有 DataBase 的 Azure Websites.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programmermagazine/201501/gh-pages/submit/利用 SQL Compact Edition 免費建立擁有 DataBase 的 Azure Websites.doc -------------------------------------------------------------------------------- /source/header.htm: -------------------------------------------------------------------------------- 1 |
2 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

3 |
4 |
5 | -------------------------------------------------------------------------------- /source/tex2img.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 3 | export PATH 4 | if [ -f "$2" ] 5 | then 6 | echo $2, ' not exist' 7 | else 8 | mimetex -d "$1" -e $2.gif 9 | convert $2.gif $2.jpg 10 | rm $2.gif 11 | fi 12 | exit 0 13 | -------------------------------------------------------------------------------- /source/footer.htm: -------------------------------------------------------------------------------- 1 |
2 | 5 | -------------------------------------------------------------------------------- /source/editor.md: -------------------------------------------------------------------------------- 1 | ## 編輯小語 2 | 3 | HTML5 技術將網頁帶入了更豐富的應用開發領域,而 node.js 的出現則讓 javascript 統一了前後端的技術,這兩個技術的出現,讓 javascript 得以橫跨「前端與後端」,於是 javascript 就成了雲端技術當中最耀眼的一種語言。 4 | 5 | 本期的「程式人雜誌」探討的焦點是「javascript 前端技術」,企圖為讀者介紹「javascript 與前端技術的發展現況」,以便讓大家可以在這些令人眼花撩亂的技術框架中,整理出一些頭緒,希望透過這樣的介紹,可以讓大家對 javascript 技術的現況能有更清楚的認識。 6 | 7 | 8 | ---- (「程式人雜誌」編輯 - 陳鍾誠) 9 | -------------------------------------------------------------------------------- /source/reflink.md9: -------------------------------------------------------------------------------- 1 | [程式人雜誌社團]: https://www.facebook.com/groups/programmerMagazine/ 2 | [少年科技人社團]: https://www.facebook.com/groups/youngmaker.magazine/ 3 | [少年科技人雜誌]: http://programmermagazine.github.io/youngmaker/ 4 | [程式人雜誌]: http://programmermagazine.github.com/home/ 5 | [姓名標示、相同方式分享]: http://creativecommons.org/licenses/by-sa/3.0/tw/ 6 | [陳鍾誠]: http://ccckmit.wikidot.com/ 7 | [維基百科]:http://zh.wikipedia.org/ 8 | -------------------------------------------------------------------------------- /source/license.md: -------------------------------------------------------------------------------- 1 | ## 授權聲明 2 | 3 | 本雜誌許多資料修改自維基百科,採用 創作共用:[姓名標示、相同方式分享] 授權,若您想要修改本書產生衍生著作時,至少應該遵守下列授權條件: 4 | 5 | 1. 標示原作者姓名 (包含該文章作者,若有來自維基百科的部份也請一併標示)。 6 | 3. 採用 創作共用:[姓名標示、相同方式分享] 的方式公開衍生著作。 7 | 8 | 另外、當本雜誌中有文章或素材並非採用 [姓名標示、相同方式分享] 時,將會在該文章或素材後面標示其授權,此時該文章將以該標示的方式授權釋出,請修改者注意這些授權標示,以避免產生侵權糾紛。 9 | 10 | 例如有些文章可能不希望被作為「商業性使用」,此時就可能會採用創作共用:[姓名標示、非商業性、相同方式分享] 的授權,此時您就不應當將該文章用於商業用途上。 11 | 12 | 最後、懇請勿移除公益捐贈的相關描述,以便讓愛心得以持續散播! 13 | 14 | -------------------------------------------------------------------------------- /code/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /code/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 陳鍾誠 9 | 11 |
12 | 13 |

14 |

15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 關於程式人雜誌 2 | 3 | [程式人雜誌] 是一個結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎程式人認養專欄、或者捐出您的網誌。 4 | 5 | ## 授權聲明 6 | 7 | 本雜誌許多資料修改自維基百科,採用 創作共用:[姓名標示、相同方式分享] 授權,若您想要修改本書產生衍生著作時,至少應該遵守下列授權條件: 8 | 9 | 1. 標示原作者姓名 (包含該文章作者,若有來自維基百科的部份也請一併標示)。 10 | 3. 採用 創作共用:[姓名標示、相同方式分享] 的方式公開衍生著作。 11 | 12 | 另外、當本雜誌中有文章或素材並非採用 [姓名標示、相同方式分享] 時,將會在該文章或素材後面標示其授權,此時該文章將以該標示的方式授權釋出,請修改者注意這些授權標示,以避免產生侵權糾紛。 13 | 14 | 例如有些文章可能不希望被作為「商業性使用」,此時就可能會採用創作共用:[姓名標示、非商業性、相同方式分享] 的授權,此時您就不應當將該文章用於商業用途上。 15 | 16 | 最後、懇請勿移除公益捐贈的相關描述,以便讓愛心得以持續散播! 17 | 18 | 19 | [程式人雜誌]: https://www.facebook.com/groups/programmerMagazine/ 20 | [姓名標示、相同方式分享]: http://creativecommons.org/licenses/by-sa/3.0/tw/ 21 | [姓名標示、非商業性、相同方式分享]: http://creativecommons.org/licenses/by-nc-sa/3.0/tw/ 22 | -------------------------------------------------------------------------------- /code/help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 |
11 | 12 |

13 | : Chung-Chen Chen (陳鍾誠)
14 | : ccckmit@gmail.com
15 | : Mozilla Public License 16 |

17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /source/focus4.md: -------------------------------------------------------------------------------- 1 | ## 網站設計的一種新模式 - 基於 localstorage 與 websocket 的可離線設計方法 2 | 3 | 雖然最近的 Backbone.js , Angular.js, React.js 等框架似乎都提供了單頁式應用 (Single Page Application) 更好的發展工具,但是網頁做成單頁式的畢竟還是會喪失原本的優勢之一,也就是每頁分開的獨立性較高,分工較容易的的特點。 4 | 5 | 舉例而言、假如我想作一個翻譯系統,那麼除了『翻譯功能』之外,還會有字典管理、帳號管理、登入模組等功能,如果做成單頁應用,那麼這些功能就必須整合在一頁當中,雖然可以分開放在不同的javascript模組,但是會納入到一個系統當中,而不能個別獨立的運作了。 6 | 7 | 於是我開始思考,有沒有可能做成很多個獨立的頁面,但是這些頁面合起來還是可以形成一個完整的系統呢? 8 | 9 | 在看到了localstorage與 websocket 這些HTML5的新技術之後,我開始覺得這樣的設計應該是可行的。 10 | 11 | 舉例而言,當我們設計了一個網頁專門作『翻譯功能』的時候,我們可能會需要用到字典,於是我們可以用一個預設的字典放在程式裡,但是讓使用者可以透過 localstorage 取得『字典管理』頁面所記錄下來的『其他字典』,這樣就可以讓『翻譯功能』與『字典管理』共用字典了。 12 | 13 | 然後、當網頁偵測到可以連上伺服器時,就可以利用websocket的模組將資料傳回伺服器儲存,但是在連不上伺服器時就採取離線的方式運作,這樣就可以讓一個網頁再沒有伺服器時也能運作,但是在有伺服器時就可以取得伺服端的資料並於修改後存回伺服器。 14 | 15 | 在本期雜誌的後半部與下期的雜誌中,我們將會用實際的範例,說明這種『多網頁可離線的合作模式』是如何進行的,讓大家能透過程式碼來理解這種模式的實際運作方式。 16 | 17 | 我們將展示一個包含『逐字翻譯、英文單字測驗、字典管理、帳號登入、多國語言』等幾個單獨網頁的系統,而這些系統透過上述模式進行資料分享與溝通,並與伺服端結合的範例,展示這種『多網頁可離線的合作模式』的設計原理。 18 | -------------------------------------------------------------------------------- /htm/preface.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

前言

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/code.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

影音頻道

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/people.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

影音頻道

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/science.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

影音頻道

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

影音頻道

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/article.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

程式人文集

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/hardware.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

影音頻道

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/software.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

影音頻道

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /htm/focus.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

本期焦點:令人眼花撩亂的 javascript -- 前端技術篇

22 |
23 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /source/focus2.md: -------------------------------------------------------------------------------- 1 | ## HTML5 與前端技術的新進展 2 | 3 | HTML5 是網頁技術上的一個重要里程碑,雖然其 W3C 的標準直到2014年才進入正式版的recommandation模式,但是在各家的瀏覽器當中,卻幾乎都已經相當完整的支援了HTML5的大部分功能。 4 | 5 | HTML5 裡面有很多受到注目的功能,這些功能很可能改變整個web的設計與使用型態,其中較為人所知的部份如下: 6 | 7 | * 2D 繪圖的 canvas 功能 8 | * 3D 繪圖的 WebGL 功能 9 | * GPS 定位的 geo location 功能 10 | * 更多的語意標記 (article, ....) 11 | * 搭配 CSS3 的動畫與更多排版功能 12 | * 區域儲存 (localstorage, indexedDB)與離線應用的功能 13 | * 雙向網路通訊的 websocket 功能 14 | * 可以不阻礙畫面顯示的 webworker 功能 15 | 16 | 其中有關 2D、3D、GPS等功能比較一目了然,可以想見會造成哪些影響。這些功能讓遊戲動畫與地理資訊類的程式可以搬到HTML5/CSS3/Javascript 的平台上呈現使用,不需要再依賴flash或其他外掛了。 17 | 18 | 至於語意標記則是W3C在XML無法普及後企圖讓網路稍微具有點語意功能的方法,而CSS3則讓網頁排版可以更加動態與活潑,但是直到最近我才發現,其實最後三項 (區域儲存、websocket、webworker) 的影響力或許會比前面那些更大也說不定。 19 | 20 | 關注web與行動技術的朋友一定都會注意到,1993年網路大爆發之後,web技術大致在javascript提出之後就底定了,中間經過flash動畫的銜接,但web整體的技術並沒有很明顯的改變。反而是2007年開始智慧型手機上網後導致APP興起,於是技術又回到各家廠商主導的平台導向世界。 21 | 22 | 但是、HTML5 提出了區域儲存的功能之後,就為離線應用鋪好了一條路,這條路有可能直達APP的地盤,讓網頁也能做出類似APP的應用,於我們就有可能用HTML5做出跨平台的APP,而且不需要依靠像Titanium或PhoneGap 這樣的平台。 23 | 24 | 當然、基於安全性的顧慮,有些系統功能還是無法用HTML5做出來的,例如存取硬碟、呼叫系統函數等等,但是對於那些不需要存取系統函數的程式而言,可以將資料存在localstorage或indexedDB當中,然後用websocket的方式回傳到伺服端,這種方法可以部份的彌補原本網頁程式難以 APP化的問題。 25 | 26 | 最近、像是 Backbone.js , Angular.js, React.js 等著重在『單頁應用』的框架開始受到大量的關注,我想也是與 HTML5 技術有關的。但是、即使不做成單頁應用,而是做成多頁應用,然後再利用『區域儲存』的localstorage或indexedDB技術達成跨網頁間的資料共用,其實也可以做出類似 APP的效果,我們將在這兩期的『程式人雜誌』當中探討此一議題。 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /htm/title.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 程式人雜誌 9 | 10 | 11 | 12 | 13 |
14 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

15 |
16 |
17 | 22 | 23 |
24 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /source/home.md: -------------------------------------------------------------------------------- 1 | ### 關於程式人雜誌 2 | 3 | [少年科技人雜誌] 與 [程式人雜誌] 都是結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎大家認養專欄、或者捐出您的網誌。 4 | 5 | ### 雜誌下載 6 | 7 | 出刊年月 epub PDF mobi 單頁 HTM 全部下載 8 | ------------ ---------- ----------- ----------- ----------- ------------- 9 | 2015年1月 [epub] [ipad.pdf] [mobi] [pmag.html] [github] 10 | 11 | ### 本期內容 12 | * 前言 13 | * [編輯小語](editor.html) 14 | * [授權聲明](license.html) 15 | * 本期焦點:令人眼花撩亂的 javascript -- 前端技術篇 16 | * [令人眼花撩亂的 javascript 新世界](focus1.html) 17 | * [HTML5 與前端技術的新進展](focus2.html) 18 | * [前端框架套件 -- jQuery, backbone.js, angular.js 與 react.js](focus3.html) 19 | * [網站設計的一種新模式 - 基於 localstorage 與 websocket 的可離線設計](focus4.html) 20 | * 程式人文集 21 | * [Web 可離線應用 1 -- 逐字英翻中系統](article1.html) 22 | * [演算法統治世界 (AUTOMATE THIS) (作者:研發養成所 Bridan)](article2.html) 23 | * [雜誌訊息](info.html) 24 | 25 | 26 | ### 雜誌取得 27 | 28 | 程式人雜誌預定於每個月 1 日出刊,您可以從下列網址取得程式人雜誌的所有內容 (包含當月最新出刊的雜誌)。 29 | 30 | * 31 | 32 | ### 連絡我們 33 | 34 | 竭誠歡迎程式人投稿,或者成為本雜誌的專欄作家,現在就可以加入 [程式人雜誌社團] 一同共襄盛舉。 35 | 36 | 本雜誌編輯為「陳鍾誠 (@ccckmit)」,若要聯絡編輯,請寄信到 。 37 | 38 | [epub]: ../book/A4.epub 39 | [mobi]: ../book/pmag.mobi 40 | [ipad.pdf]: ../book/ipad.pdf 41 | [A4.pdf]: ../book/A4.pdf 42 | [code.zip]: ../code.zip 43 | [pmag.html]: ../book/pmag.html 44 | [github]: https://github.com/programmermagazine/201501 45 | 46 | -------------------------------------------------------------------------------- /htm/editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

編輯小語

22 |

HTML5 技術將網頁帶入了更豐富的應用開發領域,而 node.js 的出現則讓 javascript 統一了前後端的技術,這兩個技術的出現,讓 javascript 得以橫跨「前端與後端」,於是 javascript 就成了雲端技術當中最耀眼的一種語言。

23 |

本期的「程式人雜誌」探討的焦點是「javascript 前端技術」,企圖為讀者介紹「javascript 與前端技術的發展現況」,以便讓大家可以在這些令人眼花撩亂的技術框架中,整理出一些頭緒,希望透過這樣的介紹,可以讓大家對 javascript 技術的現況能有更清楚的認識。

24 |

---- (「程式人雜誌」編輯 - 陳鍾誠)

25 |
26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /source/article2.md: -------------------------------------------------------------------------------- 1 | ## 演算法統治世界 (AUTOMATE THIS) (作者:研發養成所 Bridan) 2 | 3 | > 演算法統治世界 4 | > Automate This: How algorithms came to rule the world 5 | > 行人文化實驗室發行,ISBN 978-986-9028790 6 | > 克里斯多夫‧史坦能(Christopher Steiner)著,陳正芬譯 7 | 8 | 我把這本書當作小說來看,內容是真實的並且正在進行中,只是有些事還沒那麼顯著,過些年當你發現一些工作被電腦或機器人取代時,不要太訝異,因為這些都是遲早會發生的事。 9 | 10 | 故事從 1960 年代華爾街開始,一位匈牙利裔的美國人以駭客手法切入股市交易,這就是電腦程式交易的始主,台灣的股市散戶要小心,如果你還是以直覺或聽信消息以手動交易,那你很容易小贏大輸,因為越來越多人採用電腦自動交易,平時研究好某種交易策略,然後就讓程式機器人自動跑,隨時抓取線上交易資料,程式判定狀況後,立即送單交易,就像百米賽跑一樣,別人一聽到槍聲就全力衝刺,而你是看到別人開跑後才起步,已經輸人一截。 11 | 12 | 演算法就是教電腦如何執行命令的方法,電腦語言就像每個國家的語言,每個物件動作有自己的名詞與動詞,雖然說法不同,但同指相同的事物,因此演算法才是精隨所在。通常精通數學的人在這方面比較吃香,想自動化工作,需要知道事物之間的關係,數學的學習就是這方面訓練的基礎,例如計算矩形面積,就是長方形長寬相乘與面積的關係。書中也簡述演算法與數學的歷史,值得探尋。 13 | 14 | 在二十一世紀初,已經有一些演算法被實質應用於特殊場合,例如 15 | 電影公司掃描未上映電影腳本預測票房結果,音樂公司掃描歌曲預測是否會流行,利用隨機演算法創作動人音樂,想要巴哈風格的古典樂也可以。未來如果有文辭優美的詩詞創作來自電腦產生不要太驚訝。 16 | 17 | 現在一些眼光先進的投資者,想利用速度取勝,因此投資電腦硬體或相關設備以取得或保持優勢,像美國東西部之間的光纖電纜就是這樣建出來的。 18 | 19 | 許多人應該知道 1997 IBM 深藍 (Deep Blue) 打敗世界西洋棋王卡斯帕洛夫 (Garry Kasparov),2011 IBM 另一新作華生 (Watson) 在猜謎電視節目「危機重重!」(Jeopardy!) 擊敗所有人類對手,現在不同的演算法分別侵入撲克牌賽、體育賽事、挑選潛力選手、當中情局分析師、交友配對等。 20 | 21 | 美國器官捐贈配對、電腦斷層掃描分析也漸漸轉成電腦處理,未來如果遇到電腦取代醫生問診,不要太訝異,因為電腦的誤診率比人類醫生還低。美國 NASA 在登月計畫能後來居上贏過蘇聯,其中一樣就是精準分類人格特質 (有六類:感情驅動、思考基礎、行動導向、反思導向、意見導向、反應型),讓個性相合的人在一起工作,避免因成員衝突導致任務失敗,現在已經有公司依據客戶性格將客服電話轉接到適合的人員處理。 22 | 23 | 在 2008 年前,許多一流的演算法人才被華爾街企業蒐羅,但在 2008 秋天雷曼兄弟因次級房貸崩潰後,人才開始往矽谷移動,其中臉書就內藏許多演算法,隨時記錄你使用臉書的習慣,從中擷取精華提供合適的廣告以獲取利益。想想看全球超過十億人口隨時使用臉書,大家隨便 PO 個文貼個圖點個讚,那資料要怎麼存怎麼用,這沒有厲害的數學高手寫程式是沒辦法處理海量資料的。 24 | 25 | 未來是屬於演算法創作者的世界,只要願意花點時間思考訓練自己,想想可以利用電腦程式幫你做些事情,這樣你才能控制程式,而不是被機器人取代。 26 | 27 | (本文來自「研發養成所」 Bridan 的網誌,原文網址為 ,由陳鍾誠編輯後納入程式人雜誌) 28 | 29 | 30 | -------------------------------------------------------------------------------- /htm/license.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

授權聲明

22 |

本雜誌許多資料修改自維基百科,採用 創作共用:姓名標示、相同方式分享 授權,若您想要修改本書產生衍生著作時,至少應該遵守下列授權條件:

23 |
    24 |
  1. 標示原作者姓名 (包含該文章作者,若有來自維基百科的部份也請一併標示)。
  2. 25 |
  3. 採用 創作共用:姓名標示、相同方式分享 的方式公開衍生著作。
  4. 26 |
27 |

另外、當本雜誌中有文章或素材並非採用 姓名標示、相同方式分享 時,將會在該文章或素材後面標示其授權,此時該文章將以該標示的方式授權釋出,請修改者注意這些授權標示,以避免產生侵權糾紛。

28 |

例如有些文章可能不希望被作為「商業性使用」,此時就可能會採用創作共用:[姓名標示、非商業性、相同方式分享] 的授權,此時您就不應當將該文章用於商業用途上。

29 |

最後、懇請勿移除公益捐贈的相關描述,以便讓愛心得以持續散播!

30 |
31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /code/navmenu.js: -------------------------------------------------------------------------------- 1 | var navMenuHtml = '\ 2 |
\ 3 | \ 6 | \ 33 |
\ 34 | \ 35 | '; 36 | 37 | $(function() { 38 | $('#navbar').html(navMenuHtml); 39 | Mt.show(); 40 | }); -------------------------------------------------------------------------------- /htm/focus4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 | 21 |

網站設計的一種新模式 - 基於 localstorage 與 websocket 的可離線設計方法

22 |

雖然最近的 Backbone.js , Angular.js, React.js 等框架似乎都提供了單頁式應用 (Single Page Application) 更好的發展工具,但是網頁做成單頁式的畢竟還是會喪失原本的優勢之一,也就是每頁分開的獨立性較高,分工較容易的的特點。

23 |

舉例而言、假如我想作一個翻譯系統,那麼除了『翻譯功能』之外,還會有字典管理、帳號管理、登入模組等功能,如果做成單頁應用,那麼這些功能就必須整合在一頁當中,雖然可以分開放在不同的javascript模組,但是會納入到一個系統當中,而不能個別獨立的運作了。

24 |

於是我開始思考,有沒有可能做成很多個獨立的頁面,但是這些頁面合起來還是可以形成一個完整的系統呢?

25 |

在看到了localstorage與 websocket 這些HTML5的新技術之後,我開始覺得這樣的設計應該是可行的。

26 |

舉例而言,當我們設計了一個網頁專門作『翻譯功能』的時候,我們可能會需要用到字典,於是我們可以用一個預設的字典放在程式裡,但是讓使用者可以透過 localstorage 取得『字典管理』頁面所記錄下來的『其他字典』,這樣就可以讓『翻譯功能』與『字典管理』共用字典了。

27 |

然後、當網頁偵測到可以連上伺服器時,就可以利用websocket的模組將資料傳回伺服器儲存,但是在連不上伺服器時就採取離線的方式運作,這樣就可以讓一個網頁再沒有伺服器時也能運作,但是在有伺服器時就可以取得伺服端的資料並於修改後存回伺服器。

28 |

在本期雜誌的後半部與下期的雜誌中,我們將會用實際的範例,說明這種『多網頁可離線的合作模式』是如何進行的,讓大家能透過程式碼來理解這種模式的實際運作方式。

29 |

我們將展示一個包含『逐字翻譯、英文單字測驗、字典管理、帳號登入、多國語言』等幾個單獨網頁的系統,而這些系統透過上述模式進行資料分享與溝通,並與伺服端結合的範例,展示這種『多網頁可離線的合作模式』的設計原理。

30 |
31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/info.md: -------------------------------------------------------------------------------- 1 | # 雜誌訊息 2 | 3 | ## 讀者訂閱 4 | 程式人雜誌是一個結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎程式人認養專欄、或者捐出您的網誌,如果您願意成為本雜誌的專欄作家,請加入 [程式人雜誌社團] 一同共襄盛舉。 5 | 6 | 我們透過發行這本雜誌,希望讓大家可以讀到想讀的書,學到想學的技術,同時也讓寫作的朋友的作品能產生良好價值 – 那就是讓讀者根據雜誌的價值捐款給慈善團體。 7 | 讀雜誌做公益也不需要有壓力,您不需要每讀一本就急著去捐款,您可以讀了十本再捐,或者使用固定的月捐款方式,當成是雜誌訂閱費,或者是季捐款、一年捐一次等都 OK ! 甚至是單純當個讀者我們也都很歡迎! 8 | 9 | 本雜誌每期參考價:NT 50 元,如果您喜歡本雜誌,請將書款捐贈公益團體。例如可捐贈給「羅慧夫顱顏基金會 彰化銀行(009) 帳號:5234-01-41778-800」。(若匯款要加註可用「程式人雜誌」五個字) 10 | 11 | ## 投稿須知 12 | 13 | *給專欄寫作者:* 做公益不需要有壓力。如果您願意撰寫專欄,您可以輕鬆的寫,如果當月的稿件出不來,我們會安排其他稿件上場。 14 | 15 | *給網誌捐贈者:* 如果您沒時間寫專欄或投稿,沒關係,只要將您的網誌以 [創作共用的「姓名標示、非商業性、相同方式分享」授權] 並通知我們,我們會自動從中選取需要的文章進行編輯,放入適當的雜誌當中出刊。 16 | 17 | *給文章投稿者:* 程式人雜誌非常歡迎您加入作者的行列,如果您想撰寫任何文章或投稿,請用 markdown 或 LibreOffice 編輯好您的稿件,並於每個月 25 日前投稿到[程式人雜誌社團] 的檔案區,我們會盡可能將稿件編入隔月1號出版程式人雜誌當中,也歡迎您到社團中與我們一同討論。 18 | 19 | 如果您要投稿給程式人雜誌,我們最希望的格式是採用 markdown 的格式撰寫,然後將所有檔按壓縮為 zip 上傳到社團檔案區給我們, 如您想學習 markdown 的撰寫出版方式,可以參考 [看影片學 markdown 編輯出版流程] 一文。 20 | 21 | 如果您無法採用 markdown 的方式撰寫,也可以直接給我們您的稿件,像是 MS. Word 的 doc 檔或 LibreOffice 的 odt 檔都可以,我們 22 | 會將這些稿件改寫為 markdown 之後編入雜誌當中。 23 | 24 | ## 參與編輯 25 | 您也可以擔任程式人雜誌的編輯,甚至創造一個全新的公益雜誌,我們誠摯的邀請您加入「開放公益出版」的行列,如果您想擔任編輯或創造新雜誌,也歡迎到 [程式人雜誌社團] 來與我們討論相關事宜。 26 | 27 | ## 公益資訊 28 | 29 | ------------------------------------------------------------------------------------------------------------------------------------------------------------ 30 | 公益團體 聯絡資訊 服務對象 捐款帳號 31 | ------------------------------- ----------------------------- ----------------------------------------- ------------------------------------------- 32 | 財團法人羅慧夫顱顏基金會
顱顏患者 銀行:009彰化銀行民生分行
33 |
(如唇顎裂、小耳症或其他罕見顱顏缺陷) 帳號:5234-01-41778-800 34 | 02-27190408分機 232 35 | 36 | 社團法人台灣省兒童少年成長協會
單親、隔代教養.弱勢及一般家庭之兒童青少年 銀行:新光銀行
37 |
戶名:台灣省兒童少年成長協會
38 | 04-23058005 帳號:103-0912-10-000212-0 39 | ------------------------------- ----------------------------- ----------------------------------------- ------------------------------------------- 40 | 41 | [看影片學 markdown 編輯出版流程]:https://dl.dropboxusercontent.com/u/101584453/pmag/201304/htm/video1.html 42 | -------------------------------------------------------------------------------- /source/focus1.md: -------------------------------------------------------------------------------- 1 | ## 令人眼花撩亂的 javascript 新世界 2 | 3 | 如果您尚未學過 HTML/CSS/javascript 等語法的話,建議您可以先看看 [『少年程式人雜誌』](http://programmermagazine.github.io/youngmaker/) 2014年12月號的下列文章,再來看本期的內容,應該會比較順利。 4 | 5 | * [少年科技人雜誌 -- 2014 年 12 月號](http://programmermagazine.github.io/y201412/htm/home.html) 6 | * [基於 HTTP/HTML/CSS/JavaScript 的 Web 技術](http://programmermagazine.github.io/y201412/htm/focus2.html) 7 | * [HTML 網頁設計](http://programmermagazine.github.io/y201412/htm/focus3.html) 8 | * [CSS 版面設計](http://programmermagazine.github.io/y201412/htm/focus4.html) 9 | * [JavaScript -- 讓網頁動起來](http://programmermagazine.github.io/y201412/htm/focus5.html) 10 | 11 | 在我所學過的語言當中,javascript 大概是被誤解最多的一個語言。像是 JavaScript 是 Java 語言的簡化版、JavaScript 語言很難用、JavaScript 語言設計很差勁、javascript 只能用來寫寫小程式等等。 12 | 13 | 然而,這些誤解其實是我們不瞭解 JavaScript 所造成的。如果您用心的理解 JavaScript,您會發現這是一個「簡單、輕巧又優美」的語言,其原型導向的設計方式,用很簡單的概念達成了物件導向語言的功能,真的很適合做為瀏覽器上的共通語言。 14 | 15 | javascript 的歷史還算蠻悠久的,在1995年時就由瀏覽器始祖網景公司 (Netscape) 的布蘭登·艾克 (Brendan Eich) 所設計出來,企圖在瀏覽器中引入程式語言,讓網頁可以擁有更多的互動性。 16 | 17 | 原本 javascript 稱為 livescript,但網景公司為了和昇陽公司合作推動 java,結果將此以語言改名為 javascript,於是javascript常被誤解為java版本的script,但其實兩者的設計上並沒有太大關係。 18 | 19 | 不過瀏覽器確實需要一個程式語言,可惜當初昇陽公司主推java語言的applet技術在瀏覽器上表現不佳,瀏覽器內的動畫等領域反而被Macromedia 公司的flash 佔領,而java卻陰錯陽差的成了桌上應用與伺服端的重要語言,這段歷史讓javascript沈寂了一段時間。 20 | 21 | 但是自從 2009 年 node.js 推出以來,javascript 就開始進入一個『大爆發』時期,各式各樣的『框架、函式庫、套件、平台、應用』層出不窮,而 HTML5 的成熟化更進一步讓 javascript 進入了一個嶄新的時代,為 javascript 創造出了全新的可能性。 22 | 23 | 現在的javascript技術演進可以說是令人眼花撩亂,從前端的 jQuery、backbone.js、angular.js、react.js 等技術,到後端的 node.js、express.js 、connect.js、mongoose.js,以及橫跨兩端用來通訊的 websocket, ajax 技術與 socket.io 等套件,還有經常搭配 javascript 使用的 HTML5, CSS3 技術,以及 bootstrap 等顯示框架,這些技術的蓬勃發展讓 javascript 再度回春,成為具有強大生命力的一種語言。 24 | 25 | 除了瀏覽器前後端之外,javascript也開始入侵到一些本地應用與手機APP等領域,像是 Titanium, PhoneGap 可以讓您用javascript/html/css 等技術撰寫橫跨iOS、android、window phone 等平台的APP,而 [微軟新一代的 windows App](http://msdn.microsoft.com/en-us/library/windows/apps/dn631758.aspx) 也是依靠 HTML/CSS/javascript 這樣的技術體系所建立的,另外像 [Intel 的王文睿也釋出了 Node-webkit](http://www.codedata.com.tw/javascript/node-webkit-great-tool-for-gui) 這種可以用 HTML/CSS/javascript 創建以瀏覽器為何心的視窗程式環境,而 Unity 這個跨平台的遊戲引擎也主要支援 javascript /c# 這兩種語言,這讓 javascript 成為可以用來創建「從命令列程式、網路程式、web程式、視窗程式到遊戲程式」這樣涵蓋度極為廣泛的一種語言,大大的增加了javascript這個語言的吸引力。 26 | 27 | 未來、javascript 還會被用在什麼領域呢?我們很難預測,因為也有人開始試圖將 javascript 用到嵌入式系統與設計作業系統上了,而 javascript 的語法標準 ECMAScript 6 又為 javascript 添加了包含正規物件導向、 mixin 模組、預設值參數、yield語法等等,讓那些抱怨javascript物件語法不正統、語法不夠強大的人們,也有機會用正規的物件導向方式與強大的語法來撰寫javascript了。 28 | 29 | 這些 javascript 的新發展,可是讓身為『程式控』的我,感到非常的激動與興奮呢! 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /code/dict.js: -------------------------------------------------------------------------------- 1 | var dictMap = { 2 | "小四上": "bed=床,chair=椅子,desk=書桌,sofa=沙發,table=桌子,on=在...上面,under=在...下面,where=在...哪裡?, book bag=書包, key=鑰匙, pencil box=鉛筆盒, watch=手錶, bottle=水壺,It is=Yes,___ __, It's not=No,___ ____, under=A mouse is _____ the chair", 3 | "程式人常唸錯的字": "null=空無, access=存取, administrator=管理員, architecture=架構, cache=快取, cancel=取消, confirm=確認, distributed=分散式, feature=特徵, format=格式, illustrator=插畫, infrastructure=基礎設施, maintenance=維修, modem=調製解調器, parameter=參數, power=電源, processor=處理器, programmer=程序員, standard=標準, suite=套件, variable=變數, word=詞彙, walk=走, exit=離開;出口, error=錯誤", 4 | "小學三百字": "zero=零,one=一,two=二,three=三,four=四,five=五,six=六,seven=七,eight=八,nine=九,ten=十,eleven=十一,twelve=十二,thirteen=十三,fourteen=十四,fifteen=十五,sixteen=十六,seventeen=十七,eighteen=十八,nineteen=十九,twenty=二十,thirty=三十,forty=四十,fifty=五十,sixty=六十,seventy=七十,eighty=八十,ninety=九十,number=號碼,money=錢,dollar=美元,family=家庭,father=爸爸,mother=媽媽,brother=哥哥/弟弟,sister=姊姊/妹妹,boy=男孩,girl=女孩,baby=嬰兒,grandfather=祖父,grandmother=祖母,man=男人,woman=女人,Mr.=先生,Mrs.=太太,Ms.=小姐,teacher=老師,student=學生,doctor=醫生,driver=司機,friend=朋友,eye=眼睛,ear=耳朵,nose=鼻子,mouth=嘴巴,hair=頭髮,face=臉,body=身體,head=頭,hand=手掌,foot=腳掌,leg=腿,food=食物,breakfast=早餐,lunch=午餐,dinner=晚餐,juice=果汁,milk=牛奶,tea=茶,apple=蘋果,banana=香蕉,lemon=檸檬,orange=柳丁;橘色,egg=蛋,rice=米飯,chicken=雞肉;小雞,pizza=披薩,ice cream=冰淇淋,cake=蛋糕,hot dog=熱狗,hamburger=漢堡,fish=魚,pet=寵物,bear=熊,bird=鳥,cat=貓,dog=狗,lion=獅子,monkey=猴子,pig=豬,color=顏色,black=黑色,blue=藍色,green=綠色,red=紅色,pink=粉紅色,white=白色,yellow=黃色,draw=畫畫,hat=帽子,jacket=夾克,shirt=襯衫,T-shirt=圓領襯衫,pants=褲子,skirt=裙子,shoes=鞋子,watch=手錶,clock=時鐘,o'clock=點鐘,pen=原子筆,pencil=鉛筆,book=書,eraser=橡皮擦,homework=功課,ruler=尺,bag=包包,box=盒子,school=學校,class=班級;課程,door=門,window=窗戶,bed=床,house=房子,computer=電腦,telephone=電話,television=電視,room=房間,chair=椅子,desk=書桌,ball=球,baseball=棒球,basketball=籃球,doll=洋娃娃,card=卡片,e-mail=電子郵件,spring=春天,summer=夏天,fall=秋天,winter=冬天,time=時間,morning=早上,afternoon=下午,evening=傍晚,night=晚上,day=日子;天,birthday=生日,today=今天,week=星期,year=年", 5 | "TOEIC":"appointment=約會,約定,attendance=出席人數;出席,cabinet=櫥,calendar=日曆;月曆;行事曆,clerk=辦事員,書記,directory=人名住址薄,duplicate=複製;副本,filing=歸檔,in-tray=待處理文件盒,monitor=檢測;監視;追蹤,out-tray=已處理文件盒,partition=分隔;分隔物(如牆壁等),postage=郵費,punctuality=準時;守時,schedule=時間表;計畫表,shift=換班;輪班;值班,staff=全體職員,strike=罷工,task=工作,任務,work force=工作人員", 6 | "e2c": "null=空無, access=存取, administrator=管理員, architecture=架構, cache=快取, cancel=取消, confirm=確認, distributed=分散式, feature=特徵, format=格式, illustrator=插畫, infrastructure=基礎設施, maintenance=維修, modem=調製解調器, parameter=參數, power=電源, processor=處理器, programmer=程序員, standard=標準, suite=套件, variable=變數, word=詞彙, walk=走, exit=離開;出口, error=錯誤" 7 | }; 8 | -------------------------------------------------------------------------------- /code/spa.js: -------------------------------------------------------------------------------- 1 | var c = console; 2 | 3 | var Mt = { 4 | dictMap : { 5 | tw: { "Login":"登入", "Logout":"登出", "Sign up":"申請帳號", "Help":"說明", "Language":"語言", "Home":"首頁", 6 | "English":"英文", "English test":"單字測驗", "Translation":"翻譯", "Dictionary Editing":"字典編輯", 7 | "Query":"查詢", "Save":"儲存", "Forget":"忘記", "queryResult":"查詢結果", 8 | "correct":"正確", "wrong":"錯誤", 9 | "Audio":"發音", "Submit":"送出", "Hint ! Press enter to submit, slash / to play audio!":"提示:按 Enter 送出答案, 按斜線 / 發音!", "The correct answer is: ":"正確的答案是:", "Start Testing":"開始測驗", 10 | "Author":"作者", "License":"授權", "Email":"電子郵件", "Password":"密碼", "Remember me":"記住我", "User":"使用者", "Account":"帳號" 11 | }, 12 | us: {} 13 | }, 14 | lang:'tw', 15 | } 16 | 17 | Mt.dict=Mt.dictMap['tw']; 18 | 19 | Mt.mt = function mt(e) { 20 | var v = Mt.dict[e]; 21 | return (v===undefined)?e:v; 22 | } 23 | 24 | Mt.show = function show() { 25 | Mt.lang = window.localStorage["Mt_lang"]; 26 | Mt.dict = Mt.dictMap[Mt.lang]; 27 | $( "[data-mt]" ).each(function() { 28 | var e = $(this).data("mt"); 29 | if ($(this).attr("placeholder") === undefined) { 30 | $(this).text(Mt.mt(e)); 31 | } else { 32 | $(this).attr("placeholder", Mt.mt(e)); 33 | } 34 | }); 35 | } 36 | 37 | Mt.switchLang = function switchLang(pLang) { 38 | Mt.lang = pLang; 39 | Mt.dict = Mt.dictMap[Mt.lang]; 40 | window.localStorage["Mt_lang"]=pLang; 41 | Mt.show(); 42 | } 43 | 44 | var Account = {}; 45 | 46 | Account.init = function init() { 47 | c.log(window.localStorage); 48 | Mt.lang = window.localStorage['Mt_lang']; 49 | if (Mt.lang === undefined) Mt.lang='tw'; 50 | Mt.switchLang(Mt.lang); 51 | } 52 | 53 | Account.login = function login(user, password) { 54 | window.localStorage["user"]=user; 55 | location.reload(); 56 | } 57 | 58 | Account.logout = function logout() { 59 | delete window.localStorage["user"]; 60 | location.reload(); 61 | } 62 | 63 | var DB = {}; 64 | 65 | DB.forget = function DB_forget(name) { 66 | window.localStorage.removeItem(name); 67 | } 68 | 69 | DB.load = function DB_load(name) { 70 | if (window.localStorage[name] !== undefined) 71 | return JSON.parse(window.localStorage[name]); 72 | else 73 | return undefined; 74 | } 75 | 76 | DB.save = function DB_save(name, obj) { 77 | window.localStorage[name] = JSON.stringify(obj); 78 | } 79 | 80 | var Spa = {}; 81 | 82 | Spa.switchPanel = function switchPanel(name) { 83 | $(".panel" ).css( "display", "none" ); 84 | $("#panel"+name).css("display", "block"); 85 | $(".tab" ).removeClass("active"); 86 | $("#tab"+name).addClass("active"); 87 | } 88 | -------------------------------------------------------------------------------- /htm/focus2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 20 |
21 |

HTML5 與前端技術的新進展

22 |

HTML5 是網頁技術上的一個重要里程碑,雖然其 W3C 的標準直到2014年才進入正式版的recommandation模式,但是在各家的瀏覽器當中,卻幾乎都已經相當完整的支援了HTML5的大部分功能。

23 |

HTML5 裡面有很多受到注目的功能,這些功能很可能改變整個web的設計與使用型態,其中較為人所知的部份如下:

24 |
    25 |
  • 2D 繪圖的 canvas 功能
  • 26 |
  • 3D 繪圖的 WebGL 功能
  • 27 |
  • GPS 定位的 geo location 功能
  • 28 |
  • 更多的語意標記 (article, ....)
  • 29 |
  • 搭配 CSS3 的動畫與更多排版功能
  • 30 |
  • 區域儲存 (localstorage, indexedDB)與離線應用的功能
  • 31 |
  • 雙向網路通訊的 websocket 功能
  • 32 |
  • 可以不阻礙畫面顯示的 webworker 功能
  • 33 |
34 |

其中有關 2D、3D、GPS等功能比較一目了然,可以想見會造成哪些影響。這些功能讓遊戲動畫與地理資訊類的程式可以搬到HTML5/CSS3/Javascript 的平台上呈現使用,不需要再依賴flash或其他外掛了。

35 |

至於語意標記則是W3C在XML無法普及後企圖讓網路稍微具有點語意功能的方法,而CSS3則讓網頁排版可以更加動態與活潑,但是直到最近我才發現,其實最後三項 (區域儲存、websocket、webworker) 的影響力或許會比前面那些更大也說不定。

36 |

關注web與行動技術的朋友一定都會注意到,1993年網路大爆發之後,web技術大致在javascript提出之後就底定了,中間經過flash動畫的銜接,但web整體的技術並沒有很明顯的改變。反而是2007年開始智慧型手機上網後導致APP興起,於是技術又回到各家廠商主導的平台導向世界。

37 |

但是、HTML5 提出了區域儲存的功能之後,就為離線應用鋪好了一條路,這條路有可能直達APP的地盤,讓網頁也能做出類似APP的應用,於我們就有可能用HTML5做出跨平台的APP,而且不需要依靠像Titanium或PhoneGap 這樣的平台。

38 |

當然、基於安全性的顧慮,有些系統功能還是無法用HTML5做出來的,例如存取硬碟、呼叫系統函數等等,但是對於那些不需要存取系統函數的程式而言,可以將資料存在localstorage或indexedDB當中,然後用websocket的方式回傳到伺服端,這種方法可以部份的彌補原本網頁程式難以 APP化的問題。

39 |

最近、像是 Backbone.js , Angular.js, React.js 等著重在『單頁應用』的框架開始受到大量的關注,我想也是與 HTML5 技術有關的。但是、即使不做成單頁應用,而是做成多頁應用,然後再利用『區域儲存』的localstorage或indexedDB技術達成跨網頁間的資料共用,其實也可以做出類似 APP的效果,我們將在這兩期的『程式人雜誌』當中探討此一議題。

40 |
41 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /code/dict.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 |
12 | 13 |
14 |
15 |
16 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /htm/article2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 | 21 |

演算法統治世界 (AUTOMATE THIS) (作者:研發養成所 Bridan)

22 |
23 |

演算法統治世界 Automate This: How algorithms came to rule the world 行人文化實驗室發行,ISBN 978-986-9028790 克里斯多夫‧史坦能(Christopher Steiner)著,陳正芬譯

24 |
25 |

我把這本書當作小說來看,內容是真實的並且正在進行中,只是有些事還沒那麼顯著,過些年當你發現一些工作被電腦或機器人取代時,不要太訝異,因為這些都是遲早會發生的事。

26 |

故事從 1960 年代華爾街開始,一位匈牙利裔的美國人以駭客手法切入股市交易,這就是電腦程式交易的始主,台灣的股市散戶要小心,如果你還是以直覺或聽信消息以手動交易,那你很容易小贏大輸,因為越來越多人採用電腦自動交易,平時研究好某種交易策略,然後就讓程式機器人自動跑,隨時抓取線上交易資料,程式判定狀況後,立即送單交易,就像百米賽跑一樣,別人一聽到槍聲就全力衝刺,而你是看到別人開跑後才起步,已經輸人一截。

27 |

演算法就是教電腦如何執行命令的方法,電腦語言就像每個國家的語言,每個物件動作有自己的名詞與動詞,雖然說法不同,但同指相同的事物,因此演算法才是精隨所在。通常精通數學的人在這方面比較吃香,想自動化工作,需要知道事物之間的關係,數學的學習就是這方面訓練的基礎,例如計算矩形面積,就是長方形長寬相乘與面積的關係。書中也簡述演算法與數學的歷史,值得探尋。

28 |

在二十一世紀初,已經有一些演算法被實質應用於特殊場合,例如 電影公司掃描未上映電影腳本預測票房結果,音樂公司掃描歌曲預測是否會流行,利用隨機演算法創作動人音樂,想要巴哈風格的古典樂也可以。未來如果有文辭優美的詩詞創作來自電腦產生不要太驚訝。

29 |

現在一些眼光先進的投資者,想利用速度取勝,因此投資電腦硬體或相關設備以取得或保持優勢,像美國東西部之間的光纖電纜就是這樣建出來的。

30 |

許多人應該知道 1997 IBM 深藍 (Deep Blue) 打敗世界西洋棋王卡斯帕洛夫 (Garry Kasparov),2011 IBM 另一新作華生 (Watson) 在猜謎電視節目「危機重重!」(Jeopardy!) 擊敗所有人類對手,現在不同的演算法分別侵入撲克牌賽、體育賽事、挑選潛力選手、當中情局分析師、交友配對等。

31 |

美國器官捐贈配對、電腦斷層掃描分析也漸漸轉成電腦處理,未來如果遇到電腦取代醫生問診,不要太訝異,因為電腦的誤診率比人類醫生還低。美國 NASA 在登月計畫能後來居上贏過蘇聯,其中一樣就是精準分類人格特質 (有六類:感情驅動、思考基礎、行動導向、反思導向、意見導向、反應型),讓個性相合的人在一起工作,避免因成員衝突導致任務失敗,現在已經有公司依據客戶性格將客服電話轉接到適合的人員處理。

32 |

在 2008 年前,許多一流的演算法人才被華爾街企業蒐羅,但在 2008 秋天雷曼兄弟因次級房貸崩潰後,人才開始往矽谷移動,其中臉書就內藏許多演算法,隨時記錄你使用臉書的習慣,從中擷取精華提供合適的廣告以獲取利益。想想看全球超過十億人口隨時使用臉書,大家隨便 PO 個文貼個圖點個讚,那資料要怎麼存怎麼用,這沒有厲害的數學高手寫程式是沒辦法處理海量資料的。

33 |

未來是屬於演算法創作者的世界,只要願意花點時間思考訓練自己,想想可以利用電腦程式幫你做些事情,這樣你才能控制程式,而不是被機器人取代。

34 |

(本文來自「研發養成所」 Bridan 的網誌,原文網址為 http://4rdp.blogspot.tw/2014/12/automate-this.html ,由陳鍾誠編輯後納入程式人雜誌)

35 |
36 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /code/account.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Login demo 8 | 9 | 10 | 11 | 12 |
13 | 23 |
24 | 25 | 26 |
27 | 30 |
31 | 32 | 33 |
34 | 48 |
49 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /code/elearn.css: -------------------------------------------------------------------------------- 1 | ruby { 2 | ruby-align: center; 3 | ruby-overhang: auto; 4 | ruby-position: above; 5 | line-height: 300%; 6 | font-size: 20px; 7 | } 8 | 9 | rb { 10 | } 11 | 12 | rt { 13 | color: #336699; 14 | } 15 | 16 | .form-signin { 17 | max-width: 330px; 18 | padding: 15px; 19 | margin: 0 auto; 20 | } 21 | .form-signin .form-signin-heading, 22 | .form-signin .checkbox { 23 | margin-bottom: 10px; 24 | } 25 | .form-signin .checkbox { 26 | font-weight: normal; 27 | } 28 | .form-signin .form-control { 29 | position: relative; 30 | height: auto; 31 | -webkit-box-sizing: border-box; 32 | -moz-box-sizing: border-box; 33 | box-sizing: border-box; 34 | padding: 10px; 35 | font-size: 16px; 36 | } 37 | .form-signin .form-control:focus { 38 | z-index: 2; 39 | } 40 | .form-signin input[type="email"] { 41 | margin-bottom: -1px; 42 | border-bottom-right-radius: 0; 43 | border-bottom-left-radius: 0; 44 | } 45 | .form-signin input[type="password"] { 46 | margin-bottom: 10px; 47 | border-top-left-radius: 0; 48 | border-top-right-radius: 0; 49 | } 50 | 51 | .footer { 52 | position: absolute; 53 | bottom: 0; 54 | width: 100%; 55 | /* Set the fixed height of the footer here */ 56 | height: 60px; 57 | background-color: #f5f5f5; 58 | } 59 | 60 | /* 61 | * Base structure 62 | */ 63 | 64 | /* Move down content because we have a fixed navbar that is 50px tall */ 65 | body { 66 | padding-top: 50px; 67 | } 68 | 69 | 70 | /* 71 | * Global add-ons 72 | */ 73 | 74 | .sub-header { 75 | padding-bottom: 10px; 76 | border-bottom: 1px solid #eee; 77 | } 78 | 79 | /* 80 | * Top navigation 81 | * Hide default border to remove 1px line. 82 | */ 83 | .navbar-fixed-top { 84 | border: 0; 85 | } 86 | 87 | /* 88 | * Sidebar 89 | */ 90 | 91 | /* Hide for mobile, show later */ 92 | .sidebar { 93 | display: none; 94 | } 95 | @media (min-width: 768px) { 96 | .sidebar { 97 | position: fixed; 98 | top: 51px; 99 | bottom: 0; 100 | left: 0; 101 | z-index: 1000; 102 | display: block; 103 | padding: 20px; 104 | overflow-x: hidden; 105 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 106 | background-color: #f5f5f5; 107 | border-right: 1px solid #eee; 108 | } 109 | } 110 | 111 | /* Sidebar navigation */ 112 | .nav-sidebar { 113 | margin-right: -21px; /* 20px padding + 1px border */ 114 | margin-bottom: 20px; 115 | margin-left: -20px; 116 | } 117 | .nav-sidebar > li > a { 118 | padding-right: 20px; 119 | padding-left: 20px; 120 | } 121 | .nav-sidebar > .active > a, 122 | .nav-sidebar > .active > a:hover, 123 | .nav-sidebar > .active > a:focus { 124 | color: #fff; 125 | background-color: #428bca; 126 | } 127 | 128 | 129 | /* 130 | * Main content 131 | */ 132 | 133 | .main { 134 | padding: 20px; 135 | } 136 | @media (min-width: 768px) { 137 | .main { 138 | padding-right: 40px; 139 | padding-left: 40px; 140 | } 141 | } 142 | .main .page-header { 143 | margin-top: 0; 144 | } 145 | 146 | 147 | /* 148 | * Placeholder dashboard ideas 149 | */ 150 | 151 | .placeholders { 152 | margin-bottom: 30px; 153 | text-align: center; 154 | } 155 | .placeholders h4 { 156 | margin-bottom: 0; 157 | } 158 | .placeholder { 159 | margin-bottom: 20px; 160 | } 161 | .placeholder img { 162 | display: inline-block; 163 | border-radius: 50%; 164 | } 165 | -------------------------------------------------------------------------------- /htm/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |

關於程式人雜誌

17 |

少年科技人雜誌程式人雜誌 都是結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎大家認養專欄、或者捐出您的網誌。

18 |

雜誌下載

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
出刊年月epubPDFmobi單頁 HTM全部下載
2015年1月epubipad.pdfmobipmag.htmlgithub
41 |

本期內容

42 | 62 |

雜誌取得

63 |

程式人雜誌預定於每個月 1 日出刊,您可以從下列網址取得程式人雜誌的所有內容 (包含當月最新出刊的雜誌)。

64 | 67 |

連絡我們

68 |

竭誠歡迎程式人投稿,或者成為本雜誌的專欄作家,現在就可以加入 程式人雜誌社團 一同共襄盛舉。

69 |

本雜誌編輯為「陳鍾誠 (@ccckmit)」,若要聯絡編輯,請寄信到

75 |
76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /htm/focus1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 | 21 |

令人眼花撩亂的 javascript 新世界

22 |

如果您尚未學過 HTML/CSS/javascript 等語法的話,建議您可以先看看 『少年程式人雜誌』 2014年12月號的下列文章,再來看本期的內容,應該會比較順利。

23 | 32 |

在我所學過的語言當中,javascript 大概是被誤解最多的一個語言。像是 JavaScript 是 Java 語言的簡化版、JavaScript 語言很難用、JavaScript 語言設計很差勁、javascript 只能用來寫寫小程式等等。

33 |

然而,這些誤解其實是我們不瞭解 JavaScript 所造成的。如果您用心的理解 JavaScript,您會發現這是一個「簡單、輕巧又優美」的語言,其原型導向的設計方式,用很簡單的概念達成了物件導向語言的功能,真的很適合做為瀏覽器上的共通語言。

34 |

javascript 的歷史還算蠻悠久的,在1995年時就由瀏覽器始祖網景公司 (Netscape) 的布蘭登·艾克 (Brendan Eich) 所設計出來,企圖在瀏覽器中引入程式語言,讓網頁可以擁有更多的互動性。

35 |

原本 javascript 稱為 livescript,但網景公司為了和昇陽公司合作推動 java,結果將此以語言改名為 javascript,於是javascript常被誤解為java版本的script,但其實兩者的設計上並沒有太大關係。

36 |

不過瀏覽器確實需要一個程式語言,可惜當初昇陽公司主推java語言的applet技術在瀏覽器上表現不佳,瀏覽器內的動畫等領域反而被Macromedia 公司的flash 佔領,而java卻陰錯陽差的成了桌上應用與伺服端的重要語言,這段歷史讓javascript沈寂了一段時間。

37 |

但是自從 2009 年 node.js 推出以來,javascript 就開始進入一個『大爆發』時期,各式各樣的『框架、函式庫、套件、平台、應用』層出不窮,而 HTML5 的成熟化更進一步讓 javascript 進入了一個嶄新的時代,為 javascript 創造出了全新的可能性。

38 |

現在的javascript技術演進可以說是令人眼花撩亂,從前端的 jQuery、backbone.js、angular.js、react.js 等技術,到後端的 node.js、express.js 、connect.js、mongoose.js,以及橫跨兩端用來通訊的 websocket, ajax 技術與 socket.io 等套件,還有經常搭配 javascript 使用的 HTML5, CSS3 技術,以及 bootstrap 等顯示框架,這些技術的蓬勃發展讓 javascript 再度回春,成為具有強大生命力的一種語言。

39 |

除了瀏覽器前後端之外,javascript也開始入侵到一些本地應用與手機APP等領域,像是 Titanium, PhoneGap 可以讓您用javascript/html/css 等技術撰寫橫跨iOS、android、window phone 等平台的APP,而 微軟新一代的 windows App 也是依靠 HTML/CSS/javascript 這樣的技術體系所建立的,另外像 Intel 的王文睿也釋出了 Node-webkit 這種可以用 HTML/CSS/javascript 創建以瀏覽器為何心的視窗程式環境,而 Unity 這個跨平台的遊戲引擎也主要支援 javascript /c# 這兩種語言,這讓 javascript 成為可以用來創建「從命令列程式、網路程式、web程式、視窗程式到遊戲程式」這樣涵蓋度極為廣泛的一種語言,大大的增加了javascript這個語言的吸引力。

40 |

未來、javascript 還會被用在什麼領域呢?我們很難預測,因為也有人開始試圖將 javascript 用到嵌入式系統與設計作業系統上了,而 javascript 的語法標準 ECMAScript 6 又為 javascript 添加了包含正規物件導向、 mixin 模組、預設值參數、yield語法等等,讓那些抱怨javascript物件語法不正統、語法不夠強大的人們,也有機會用正規的物件導向方式與強大的語法來撰寫javascript了。

41 |

這些 javascript 的新發展,可是讓身為『程式控』的我,感到非常的激動與興奮呢!

42 |
43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /code/elearn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 |

15 |

16 | 17 | 18 | 19 | = 20 |
21 |

22 |

23 |

24 |
25 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /code/mt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 |
13 |

14 |

15 |
16 |
17 | 23 | 43 |
44 |
45 | 51 |
52 |
53 |
54 |
55 |
56 |

57 |
58 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /htm/info.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

14 |
15 |
16 |
17 | 25 |
26 |

雜誌訊息

27 |

讀者訂閱

28 |

程式人雜誌是一個結合「開放原始碼與公益捐款活動」的雜誌,簡稱「開放公益雜誌」。開放公益雜誌本著「讀書做善事、寫書做公益」的精神,我們非常歡迎程式人認養專欄、或者捐出您的網誌,如果您願意成為本雜誌的專欄作家,請加入 程式人雜誌社團 一同共襄盛舉。

29 |

我們透過發行這本雜誌,希望讓大家可以讀到想讀的書,學到想學的技術,同時也讓寫作的朋友的作品能產生良好價值 – 那就是讓讀者根據雜誌的價值捐款給慈善團體。 讀雜誌做公益也不需要有壓力,您不需要每讀一本就急著去捐款,您可以讀了十本再捐,或者使用固定的月捐款方式,當成是雜誌訂閱費,或者是季捐款、一年捐一次等都 OK ! 甚至是單純當個讀者我們也都很歡迎!

30 |

本雜誌每期參考價:NT 50 元,如果您喜歡本雜誌,請將書款捐贈公益團體。例如可捐贈給「羅慧夫顱顏基金會 彰化銀行(009) 帳號:5234-01-41778-800」。(若匯款要加註可用「程式人雜誌」五個字)

31 |

投稿須知

32 |

給專欄寫作者: 做公益不需要有壓力。如果您願意撰寫專欄,您可以輕鬆的寫,如果當月的稿件出不來,我們會安排其他稿件上場。

33 |

給網誌捐贈者: 如果您沒時間寫專欄或投稿,沒關係,只要將您的網誌以 [創作共用的「姓名標示、非商業性、相同方式分享」授權] 並通知我們,我們會自動從中選取需要的文章進行編輯,放入適當的雜誌當中出刊。

34 |

給文章投稿者: 程式人雜誌非常歡迎您加入作者的行列,如果您想撰寫任何文章或投稿,請用 markdown 或 LibreOffice 編輯好您的稿件,並於每個月 25 日前投稿到程式人雜誌社團 的檔案區,我們會盡可能將稿件編入隔月1號出版程式人雜誌當中,也歡迎您到社團中與我們一同討論。

35 |

如果您要投稿給程式人雜誌,我們最希望的格式是採用 markdown 的格式撰寫,然後將所有檔按壓縮為 zip 上傳到社團檔案區給我們, 如您想學習 markdown 的撰寫出版方式,可以參考 看影片學 markdown 編輯出版流程 一文。

36 |

如果您無法採用 markdown 的方式撰寫,也可以直接給我們您的稿件,像是 MS. Word 的 doc 檔或 LibreOffice 的 odt 檔都可以,我們 會將這些稿件改寫為 markdown 之後編入雜誌當中。

37 |

參與編輯

38 |

您也可以擔任程式人雜誌的編輯,甚至創造一個全新的公益雜誌,我們誠摯的邀請您加入「開放公益出版」的行列,如果您想擔任編輯或創造新雜誌,也歡迎到 程式人雜誌社團 來與我們討論相關事宜。

39 |

公益資訊

40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 76 | 77 | 78 | 79 |
公益團體聯絡資訊服務對象捐款帳號
財團法人羅慧夫顱顏基金會http://www.nncf.org/

02-27190408分機 232
顱顏患者 (如唇顎裂、小耳症或其他罕見顱顏缺陷)銀行:009彰化銀行民生分行
帳號:5234-01-41778-800
社團法人台灣省兒童少年成長協會http://www.cyga.org/

04-23058005
單親、隔代教養.弱勢及一般家庭之兒童青少年銀行:新光銀行
戶名:台灣省兒童少年成長協會
帳號:103-0912-10-000212-0
80 |
81 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /source/focus3.md: -------------------------------------------------------------------------------- 1 | ## 前端框架套件 -- jQuery, backbone.js, angular.js 與 react.js 2 | 3 | jQuery, backbone.js, angular.js 與 react.js 等開放原始碼專案都是屬於『前端』的顯示框架,但是初學者要清楚的理解這些框架的差別,與可以適用在哪些情況,其實並不容易,因為太多的javascript框架已經到了令人眼花撩亂的程度了。 4 | 5 | 因此、雖然筆者只用 jQuery 寫過幾個小程式,看了一本backbone.js的書,沒有寫過angular.js與react.js,但是看了幾篇相關的文章,也斗膽在此分享一下自己對這些框架的理解與看法,讓大家可以在決定要學習哪個框架的時候,能夠不至於迷失在五里霧中。 6 | 7 | ### jQuery 8 | 9 | jQuery 其實是用來處理 HTML 的樹狀結構 DOM 的一個函式庫,透過物件導向的 a.b().c.d()....... 這樣的『鏈式語法』讓您可以用簡短的呼叫去巡覽、取得並處理對應的樹狀節點(node),這種『鏈式語法』可以讓程式碼縮短,用很簡潔的語法完成節點的取得與處理動作。 10 | 11 | 舉例而言、在w3school網站當中有下列的範例,該範例示範了如何用 jQuery 用很簡潔的語法做出滑動的效果。 12 | 13 | * 14 | 15 | ```javascript 16 | $(document).ready(function() 17 | { 18 | $("button").click(function(){ 19 | $("#p1").css("color","red").slideUp(2000).slideDown(2000); 20 | }); 21 | }); 22 | ``` 23 | 24 | 這種『鏈式語法』的設計關鍵其實是在物件的成員函數中,盡可能的用 return this傳回自身。舉例而言,假如我們定義下列這樣一個物件,並在每個成員函數的最後都傳回this,那麼我們就可以用 obj.a().b().c().a().d().c().....這樣的語法進行鏈式呼叫了。 25 | 26 | ```javascript 27 | var obj = { 28 | a:function() {... return this; } 29 | b:function() {... return this; } 30 | c:function() {... return this; } 31 | d:function() {... return this; } 32 | } 33 | ``` 34 | 35 | 另外、因為jQuery是集合導向的作法,每次都是處理一大堆節點,搭配上『鏈式語法』之後,就可以用一條鏈式語法對一大堆的節點進行連續的處理動作,這比起每次都要寫迴圈的方式要有效率多了。 36 | 37 | 另外、jQuery 也支援了一些像 post(), ajax() 與伺服端溝通的函數,讓網頁設計者可以用統一的語法搞定網頁的前端處理工作。 38 | 39 | ### Backbone.js 40 | 41 | 熟悉『設計模式』的朋友們應該聽說過MVC這個著名的設計模式,也就是『Model-View-Controller』,該模式將一個系統分成背後的『模型』(Model)、『顯示』(View)與連接的『控制』(Controller)等三大部份,這樣就能將模型與顯示兩者分開,然後再用controller將兩者結合在一起。 42 | 43 | 傳統上這種方法會用在『網路程式或視窗程式』上。對於web而言,我們通常會將model放在後端的伺服器,而將view放在前端的瀏覽器當中。 44 | 45 | 但是、由於javascript+HTML5這些技術讓瀏覽器可以承受的工作越來越多,因此前端就越來越複雜了,於是前端本身有時就包含了複雜的模型與控制部份,這時候就有人想到要在前端實現完整的MVC架構,以便處理這些複雜的工作,於是像backbone.js這樣的 前端MVC框架就被實現出來了。 46 | 47 | 如果您對backbone.js想有個初步的認識,可以參考下列文章, 48 | 49 | * [Javascript 前端工具 Backbone.js Framework 初學介紹](http://blog.wu-boy.com/2012/04/backbonejs-framework-tutorial-example-1/) 50 | 51 | 在 backbone.js 當中,實現的並不是 Model-View-Controller 這樣的模式,而是Model-Collection-View 這三類物件,以及利用event進行串連的方式,除此之外,javascript語言本身就扮演了某種程度的controller角色,因此您也可以輕易的將jQuery與backbone.js 搭在一起使用,兩者可以很完美的融合運作,不會有任何違和感。 52 | 53 | backbone.js 由於使用了 Underscore.js 這個框架,可以很容易的進行集合的鏈式處理,而 Underscore.js 框架裡又有一個簡易的樣板引擎,可以用來將樣板轉換成HTML區塊輸出,只要用view物件搭配Underscore.js,就可以得到一個相當完整的 MVC 框架了。 54 | 55 | 在 model 部份,backbone 的模型資料有任何修改時,都會觸發一些資料修改事件,只要在這些事件當中加入對應的程式碼,例如更新畫面或回傳資料到伺服器,就可以成為一個完整的網頁應用程式了。 56 | 57 | ### React.js 58 | 59 | React.js 是 facebook 公司所創建的一個開源專案,扮演的角色主要是 MVC 架構中的 View 角色,在 React.js 的官網中有個非常簡單的範例如下: 60 | 61 | ```html 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 | 76 | 77 | 78 | ``` 79 | 80 | 這個範例大概可以說是 React.js 版本的 hello world! 您可以看到其中的關鍵部份是 React.render 這一段。 81 | 82 | ```javascript 83 | React.render( 84 |

Hello, world!

, 85 | document.getElementById('example') 86 | ); 87 | ``` 88 | 89 | React 的特別之處是在 javascript 裡面放入了 HTML/XML 的內容,以下是 react官網中的一段關鍵描述,說明了react為何要搭配 JSXTransformer 去將 HTML/XML 語法轉換成 javascript 的原因,這樣就可以將 HTML/XML 完全的 javascript 化了。 90 | 91 | > The XML syntax inside of JavaScript is called JSX; check out the JSX syntax to learn more about it. In order to translate it to vanilla JavaScript we use ` 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /code/js/bootstrap-filestyle.min.js: -------------------------------------------------------------------------------- 1 | (function(c){var b=function(d,e){this.options=e;this.$elementFilestyle=[];this.$element=c(d)};b.prototype={clear:function(){this.$element.val("");this.$elementFilestyle.find(":text").val("");this.$elementFilestyle.find(".badge").remove()},destroy:function(){this.$element.removeAttr("style").removeData("filestyle").val("");this.$elementFilestyle.remove()},disabled:function(d){if(d===true){if(!this.options.disabled){this.$element.attr("disabled","true");this.$elementFilestyle.find("label").attr("disabled","true");this.options.disabled=true}}else{if(d===false){if(this.options.disabled){this.$element.removeAttr("disabled");this.$elementFilestyle.find("label").removeAttr("disabled");this.options.disabled=false}}else{return this.options.disabled}}},buttonBefore:function(d){if(d===true){if(!this.options.buttonBefore){this.options.buttonBefore=true;if(this.options.input){this.$elementFilestyle.remove();this.constructor();this.pushNameFiles()}}}else{if(d===false){if(this.options.buttonBefore){this.options.buttonBefore=false;if(this.options.input){this.$elementFilestyle.remove();this.constructor();this.pushNameFiles()}}}else{return this.options.buttonBefore}}},icon:function(d){if(d===true){if(!this.options.icon){this.options.icon=true;this.$elementFilestyle.find("label").prepend(this.htmlIcon())}}else{if(d===false){if(this.options.icon){this.options.icon=false;this.$elementFilestyle.find(".glyphicon").remove()}}else{return this.options.icon}}},input:function(e){if(e===true){if(!this.options.input){this.options.input=true;if(this.options.buttonBefore){this.$elementFilestyle.append(this.htmlInput())}else{this.$elementFilestyle.prepend(this.htmlInput())}this.$elementFilestyle.find(".badge").remove();this.pushNameFiles();this.$elementFilestyle.find(".group-span-filestyle").addClass("input-group-btn")}}else{if(e===false){if(this.options.input){this.options.input=false;this.$elementFilestyle.find(":text").remove();var d=this.pushNameFiles();if(d.length>0&&this.options.badge){this.$elementFilestyle.find("label").append(' '+d.length+"")}this.$elementFilestyle.find(".group-span-filestyle").removeClass("input-group-btn")}}else{return this.options.input}}},size:function(d){if(d!==undefined){var f=this.$elementFilestyle.find("label"),e=this.$elementFilestyle.find("input");f.removeClass("btn-lg btn-sm");e.removeClass("input-lg input-sm");if(d!="nr"){f.addClass("btn-"+d);e.addClass("input-"+d)}}else{return this.options.size}},buttonText:function(d){if(d!==undefined){this.options.buttonText=d;this.$elementFilestyle.find("label span").html(this.options.buttonText)}else{return this.options.buttonText}},buttonName:function(d){if(d!==undefined){this.options.buttonName=d;this.$elementFilestyle.find("label").attr({"class":"btn "+this.options.buttonName})}else{return this.options.buttonName}},iconName:function(d){if(d!==undefined){this.$elementFilestyle.find(".glyphicon").attr({"class":".glyphicon "+this.options.iconName})}else{return this.options.iconName}},htmlIcon:function(){if(this.options.icon){return' '}else{return""}},htmlInput:function(){if(this.options.input){return' '}else{return""}},pushNameFiles:function(){var d="",f=[];if(this.$element[0].files===undefined){f[0]={name:this.$element[0]&&this.$element[0].value}}else{f=this.$element[0].files}for(var e=0;e";f=h.options.buttonBefore?i+h.htmlInput():h.htmlInput()+i;h.$elementFilestyle=c('
'+f+"
");h.$elementFilestyle.find(".group-span-filestyle").attr("tabindex","0").keypress(function(j){if(j.keyCode===13||j.charCode===32){h.$elementFilestyle.find("label").click();return false}});h.$element.css({position:"absolute",clip:"rect(0px 0px 0px 0px)"}).attr("tabindex","-1").after(h.$elementFilestyle);if(h.options.disabled){h.$element.attr("disabled","true")}h.$element.change(function(){var j=h.pushNameFiles();if(h.options.input==false&&h.options.badge){if(h.$elementFilestyle.find(".badge").length==0){h.$elementFilestyle.find("label").append(' '+j.length+"")}else{if(j.length==0){h.$elementFilestyle.find(".badge").remove()}else{h.$elementFilestyle.find(".badge").html(j.length)}}}else{h.$elementFilestyle.find(".badge").remove()}});if(window.navigator.userAgent.search(/firefox/i)>-1){h.$elementFilestyle.find("label").click(function(){h.$element.click();return false})}}};var a=c.fn.filestyle;c.fn.filestyle=function(e,d){var f="",g=this.each(function(){if(c(this).attr("type")==="file"){var j=c(this),h=j.data("filestyle"),i=c.extend({},c.fn.filestyle.defaults,e,typeof e==="object"&&e);if(!h){j.data("filestyle",(h=new b(this,i)));h.constructor()}if(typeof e==="string"){f=h[e](d)}}});if(typeof f!==undefined){return f}else{return g}};c.fn.filestyle.defaults={buttonText:"Choose file",iconName:"glyphicon-folder-open",buttonName:"btn-default",size:"nr",input:true,badge:true,icon:true,buttonBefore:false,disabled:false};c.fn.filestyle.noConflict=function(){c.fn.filestyle=a;return this};c(function(){c(".filestyle").each(function(){var e=c(this),d={input:e.attr("data-input")==="false"?false:true,icon:e.attr("data-icon")==="false"?false:true,buttonBefore:e.attr("data-buttonBefore")==="true"?true:false,disabled:e.attr("data-disabled")==="true"?true:false,size:e.attr("data-size"),buttonText:e.attr("data-buttonText"),buttonName:e.attr("data-buttonName"),iconName:e.attr("data-iconName"),badge:e.attr("data-badge")==="false"?false:true};e.filestyle(d)})})})(window.jQuery); -------------------------------------------------------------------------------- /css/pmag.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | font: inherit; 18 | vertical-align: baseline; 19 | line-height:160%; 20 | } 21 | 22 | #cover-image { 23 | width:100%; 24 | } 25 | 26 | div>ol.toc { 27 | list-style-type:disc; 28 | } 29 | 30 | ol.toc { 31 | list-style-type:circle; 32 | } 33 | 34 | blockquote { 35 | margin: 10px; 36 | padding-left: 10px; 37 | padding-right: 10px; 38 | padding-top: 1px; 39 | padding-bottom: 1px; 40 | border: 3px double #373737; 41 | color:#333333; 42 | } 43 | 44 | h1, h1 a { font-size: xx-large; color:#050505; text-align:center; margin:30px; font-weight: bold; font-family: 'DFKai-sb', 'Tahoma'; } 45 | 46 | h2, h2 a { font-size: x-large; color:#8B008B; margin-top:30px; margin-bottom:30px; font-weight: bold; font-family: 'DFKai-sb', 'Tahoma'; } 47 | 48 | h3, h3 a { font-size: large; color:#000080; font-weight: bold; font-family: 'DFKai-sb', 'Tahoma'; } 49 | 50 | h4, h4 a { font-size: medium; color:#4B0082; font-weight: bold; font-family: 'DFKai-sb', 'Tahoma'; } 51 | 52 | h5, h5 a { font-size: small ; color:#708090; font-weight: bold; font-family: 'DFKai-sb', 'Tahoma'; } 53 | 54 | h6, h6 a { font-size: x-small; color:#000080; } 55 | 56 | p { 57 | font-family: 'Pmingliu', 'Tahoma'; 58 | margin: 10px 0 15px 0; 59 | font-size:100%; 60 | color:#353535; 61 | } 62 | 63 | li { 64 | font-size:100%; 65 | } 66 | 67 | footer p { 68 | color: #f2f2f2; 69 | } 70 | 71 | a { 72 | text-decoration: none; 73 | color: #007edf; 74 | text-shadow: none; 75 | 76 | transition: color 0.5s ease; 77 | transition: text-shadow 0.5s ease; 78 | -webkit-transition: color 0.5s ease; 79 | -webkit-transition: text-shadow 0.5s ease; 80 | -moz-transition: color 0.5s ease; 81 | -moz-transition: text-shadow 0.5s ease; 82 | -o-transition: color 0.5s ease; 83 | -o-transition: text-shadow 0.5s ease; 84 | -ms-transition: color 0.5s ease; 85 | -ms-transition: text-shadow 0.5s ease; 86 | } 87 | 88 | table { 89 | border-collapse: collapse; 90 | border-spacing: 0; 91 | border: 1px solid #373737; 92 | margin-bottom: 20px; 93 | text-align: left; 94 | margin-left:auto; 95 | margin-right:auto; 96 | } 97 | 98 | th { 99 | padding: 10px; 100 | background-color:black; 101 | color:white; 102 | } 103 | 104 | td { 105 | padding: 10px; 106 | vertical-align: middle; 107 | border: 1px solid #373737; 108 | } 109 | 110 | em { 111 | color: blue; 112 | } 113 | 114 | strong { 115 | font-weight:bold; 116 | color: red; 117 | } 118 | 119 | 120 | #header_wrap { 121 | margin: 0; 122 | padding: 16px; 123 | border: 0; 124 | font: inherit; 125 | vertical-align: baseline; 126 | background-color:black; 127 | color:white; 128 | } 129 | 130 | #header_wrap h1, #header_wrap h1 sub, #header_wrap h1 a { 131 | color:white; 132 | font-family: 'DFKai-sb', 'Tahoma'; 133 | } 134 | 135 | #header_wrap sub { 136 | color:white; 137 | font-size:60%; 138 | } 139 | 140 | #bar, #bar a, #header_wrap a, #header_wrap h1 sub a { 141 | color:white; 142 | width:95%; 143 | text-align:right; 144 | font-weight:bold; 145 | } 146 | 147 | .title, .author, .date { 148 | color:#333333; 149 | text-align:center; 150 | font-family: 'DFKai-sb', 'Tahoma' ; 151 | } 152 | 153 | .title { font-size:xx-large; line-height:800%; } 154 | 155 | .author { font-size:large; line-height:300%; } 156 | 157 | .date { font-size:large; line-height:300%; } 158 | 159 | 160 | #content { 161 | margin:10px; 162 | padding:10px; 163 | } 164 | 165 | pre { 166 | border: 1px solid #373737; 167 | background-color:#efefef; 168 | color:#3f3f3f; 169 | font-size:medium; 170 | width:95%; 171 | padding:10px; 172 | /* wrap ,自動換行 */ 173 | white-space: pre-wrap; /* css-3 */ 174 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 175 | white-space: -pre-wrap; /* Opera 4-6 */ 176 | white-space: -o-pre-wrap; /* Opera 7 */ 177 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 178 | } 179 | 180 | code { 181 | // font-family: SimSun; 182 | // color:blue; 183 | font-size:100%; 184 | } 185 | 186 | pre code { 187 | font-family: SimSun; 188 | font-size:125%; 189 | } 190 | 191 | .figure { 192 | margin:10px; 193 | padding:10px; 194 | margin-left: auto; 195 | margin-right: auto; 196 | display: block; 197 | } 198 | 199 | img { vertical-align:middle; } 200 | 201 | .figure img { 202 | margin-left: auto; 203 | margin-right: auto; 204 | display: block; 205 | } 206 | 207 | .figure .caption { 208 | text-align:center; 209 | } 210 | 211 | #TOC { 212 | } 213 | 214 | #footer { 215 | text-align:center; 216 | font-size:small; 217 | color:#6f6f6f; 218 | margin: 10px; 219 | padding: 10px; 220 | } 221 | 222 | /* JavaScript Style */ 223 | table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode { 224 | margin: 0; padding: 0; vertical-align: baseline; border: none; } 225 | table.sourceCode { width: 100%; } 226 | td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #afafaf; border-right: 1px solid #aaaaaa; } 227 | td.sourceCode { padding-left: 5px; } 228 | code > span.kw { color: #007020; font-weight: bold; } 229 | code > span.dt { color: #902000; } 230 | code > span.dv { color: #40a070; } 231 | code > span.bn { color: #40a070; } 232 | code > span.fl { color: #40a070; } 233 | code > span.ch { color: #4070a0; } 234 | code > span.st { color: #4070a0; } 235 | code > span.co { color: #60a0b0; font-style: italic; } 236 | code > span.ot { color: #007020; } 237 | code > span.al { color: #ff0000; font-weight: bold; } 238 | code > span.fu { color: #06287e; } 239 | code > span.er { color: #ff0000; font-weight: bold; } 240 | 241 | -------------------------------------------------------------------------------- /source/article1.md: -------------------------------------------------------------------------------- 1 | ## Web 可離線應用 1 -- 逐字英翻中系統 2 | 3 | 本系統已經上傳到 github 上,您可以點選下列連結試用一下這個「英翻中系統」系統,然後在開始閱讀本文: 4 | 5 | * 6 | 7 | 為了要說明如何用 HTML5/CSS/JavaScript 建構出可單頁獨立運作,又可透過 localstorage 記住使用者資訊的網頁應用,我們建立了一個「逐字英翻中系統」,讓使用者可以透過 localstorage 儲存使用者紀錄的一些資訊。 8 | 9 | 首先我們在 spa.js (Single Page Application 的簡寫) 當中創建了一個稱為 DB 的物件,該物件可以用來協助「載入或儲存」資訊到 localstorage 當中,如此就可以用 load(), save() 函數記住這些資訊,必須注意的是 localstorage 當中只能儲存字串資訊,因此我們必須用 JSON.stringify() 等函數將 JSON 物件轉換成字串後才能儲存,而在取出後再用 JSON.parse() 將字串轉回 JSON 物件。 10 | 11 | 12 | 檔案: spa.js 13 | 14 | ```javascript 15 | ... 16 | var DB = {}; 17 | 18 | DB.forget = function DB_forget(name) { 19 | window.localStorage.removeItem(name); 20 | } 21 | 22 | DB.load = function DB_load(name) { 23 | if (window.localStorage[name] !== undefined) 24 | return JSON.parse(window.localStorage[name]); 25 | else 26 | return undefined; 27 | } 28 | 29 | DB.save = function DB_save(name, obj) { 30 | window.localStorage[name] = JSON.stringify(obj); 31 | } 32 | ... 33 | ``` 34 | 35 | 然後、我們撰寫了 mt.html 這個網頁程式,以下是該網頁的一個執行畫面: 36 | 37 | ![圖、逐字英翻中系統](../img/mt.jpg) 38 | 39 | 該網頁的完整原始碼如下所示: 40 | 41 | 檔案:mt.html 42 | 43 | ```html 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 55 |
56 |

57 |

58 |
59 |
60 | 66 | 86 |
87 |
88 | 94 |
95 |
96 |
97 |
98 |
99 |

100 |
101 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | ``` 166 | 167 | 在上述程式中,我們透過攔截 window.onbeforeunload 事件,在離開網頁之前儲存想記憶的物件。 168 | 169 | ```javascript 170 | window.onbeforeunload = function(){ 171 | DB.save('knowWords', knowWords); 172 | }; 173 | ``` 174 | 175 | 然後在網頁載入時,我們會檢查是否有已經記住的物件,若有則將之載入恢復,這樣就可以透過 localstorage 在網頁中記住較大量的資訊 (記憶量大小各家瀏覽器不同,但大致都在 5MB 以上),這比傳統的 cookie 大多了,而且 localstorage 不會像 cookie 那樣每次都被放在表頭裡傳回伺服器,因此很適合用來於瀏覽器當中儲存較大量的資訊。 176 | 177 | ```javascript 178 | function load() { 179 | ... 180 | var dbKnowWords = DB.load('knowWords'); 181 | if (dbKnowWords === undefined) 182 | knowWords = {}; 183 | else 184 | knowWords = dbKnowWords; 185 | } 186 | ``` 187 | 188 | 那麼、我們到底用 knowWords 物件來記住甚麼資訊呢? 關於這點,請讀者仔細觀看下列的 doMT() 程式段落,該函數是用來將 ebox 英文區塊透過 mt() 函數逐字翻譯後,用 ruby 標記顯示中英對照在 ebox 當中,於是讀者才能看到中文在上英文在下的對照翻譯。 189 | 190 | ```javascript 191 | function mt(str) { 192 | var re = /([\w']+)/gi; 193 | var toStr = ""; 194 | var si = 0; 195 | while (m = re.exec(str)) { 196 | var eword = m[1], elower=eword.toLowerCase(); 197 | var cword = dict[eword.toLowerCase()]; 198 | toStr += str.substring(si, re.lastIndex-eword.length); 199 | if (cword === undefined || knowWords[elower] !== undefined) // 已經認識的字詞就不需要再翻譯了 200 | cword = ""; 201 | toStr += ''+eword+''+cword+''; 202 | si = re.lastIndex; 203 | } 204 | return toStr; 205 | } 206 | 207 | function doMT() { 208 | var cstr = mt(ebox.value); 209 | cbox.innerHTML = cstr.replace(/\n/g, "
"); 210 | $('ruby').click(function() { 211 | var e = $(this).find('rb').text().toLowerCase(); 212 | var c = $(this).find('rt').text(); 213 | knowWords[e] = c; 214 | $('#query').val(e); 215 | $('#queryResult').val(e+'='+c); 216 | $('.'+normalize(e)).find('rt').hide(); // 將使用者點掉的字詞之翻譯隱藏起來。 217 | }); 218 | } 219 | ``` 220 | 221 | 222 | 當使用者點選某個「中英對照」字詞的時候,代表該使用者已經認識該字詞了,所以我們會將該字詞記錄在 knowWords 這個字典物件當中,並且隱藏該字詞的翻譯,如此當使用者認識的字越來越多,被翻譯的字詞也就會越來越少,於是隨著使用者的進步就可以逐漸完全讀懂整篇原文,而不需要依賴系統的翻譯功能了 (這也是本系統與一般翻譯系統最大的不同點,本系統是幫助學習英文,而不是企圖做出一個很厲害的機器翻譯系統)。 223 | 224 | ![圖、將已經學會的單字點掉後,離開網頁再回來時的情況](../img/mt_back.jpg) 225 | 226 | 上述程式裡的幾個關鍵部分,我們已經用了中文註解進行說明,讀者應該很容易可以看出這幾個關鍵程式碼的功能才對! 227 | 228 | 透過這種方式,我們可以讓網頁變成一種類似 APP 的應用,而且不需要伺服端的配合。 229 | 230 | (當然、如果加上伺服端之後,還可以將這些 localstorage 中的資訊傳回到伺服器永久記住,這樣即使換了一台電腦,也不會忘記這些資訊了)。 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /htm/focus3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 28 | 29 | 30 | 31 |
32 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

33 |
34 |
35 | 40 |

前端框架套件 -- jQuery, backbone.js, angular.js 與 react.js

41 |

jQuery, backbone.js, angular.js 與 react.js 等開放原始碼專案都是屬於『前端』的顯示框架,但是初學者要清楚的理解這些框架的差別,與可以適用在哪些情況,其實並不容易,因為太多的javascript框架已經到了令人眼花撩亂的程度了。

42 |

因此、雖然筆者只用 jQuery 寫過幾個小程式,看了一本backbone.js的書,沒有寫過angular.js與react.js,但是看了幾篇相關的文章,也斗膽在此分享一下自己對這些框架的理解與看法,讓大家可以在決定要學習哪個框架的時候,能夠不至於迷失在五里霧中。

43 |

jQuery

44 |

jQuery 其實是用來處理 HTML 的樹狀結構 DOM 的一個函式庫,透過物件導向的 a.b().c.d()....... 這樣的『鏈式語法』讓您可以用簡短的呼叫去巡覽、取得並處理對應的樹狀節點(node),這種『鏈式語法』可以讓程式碼縮短,用很簡潔的語法完成節點的取得與處理動作。

45 |

舉例而言、在w3school網站當中有下列的範例,該範例示範了如何用 jQuery 用很簡潔的語法做出滑動的效果。

46 | 49 |
 $(document).ready(function()
 50 |   {
 51 |   $("button").click(function(){
 52 |     $("#p1").css("color","red").slideUp(2000).slideDown(2000);
 53 |   });
 54 | });
55 |

這種『鏈式語法』的設計關鍵其實是在物件的成員函數中,盡可能的用 return this傳回自身。舉例而言,假如我們定義下列這樣一個物件,並在每個成員函數的最後都傳回this,那麼我們就可以用 obj.a().b().c().a().d().c().....這樣的語法進行鏈式呼叫了。

56 |
 var obj = {
 57 |    a:function() {... return this; }
 58 |    b:function() {... return this; }   
 59 |    c:function() {... return this; }   
 60 |    d:function() {... return this; }   
 61 |  }
62 |

另外、因為jQuery是集合導向的作法,每次都是處理一大堆節點,搭配上『鏈式語法』之後,就可以用一條鏈式語法對一大堆的節點進行連續的處理動作,這比起每次都要寫迴圈的方式要有效率多了。

63 |

另外、jQuery 也支援了一些像 post(), ajax() 與伺服端溝通的函數,讓網頁設計者可以用統一的語法搞定網頁的前端處理工作。

64 |

Backbone.js

65 |

熟悉『設計模式』的朋友們應該聽說過MVC這個著名的設計模式,也就是『Model-View-Controller』,該模式將一個系統分成背後的『模型』(Model)、『顯示』(View)與連接的『控制』(Controller)等三大部份,這樣就能將模型與顯示兩者分開,然後再用controller將兩者結合在一起。

66 |

傳統上這種方法會用在『網路程式或視窗程式』上。對於web而言,我們通常會將model放在後端的伺服器,而將view放在前端的瀏覽器當中。

67 |

但是、由於javascript+HTML5這些技術讓瀏覽器可以承受的工作越來越多,因此前端就越來越複雜了,於是前端本身有時就包含了複雜的模型與控制部份,這時候就有人想到要在前端實現完整的MVC架構,以便處理這些複雜的工作,於是像backbone.js這樣的 前端MVC框架就被實現出來了。

68 |

如果您對backbone.js想有個初步的認識,可以參考下列文章,

69 | 72 |

在 backbone.js 當中,實現的並不是 Model-View-Controller 這樣的模式,而是Model-Collection-View 這三類物件,以及利用event進行串連的方式,除此之外,javascript語言本身就扮演了某種程度的controller角色,因此您也可以輕易的將jQuery與backbone.js 搭在一起使用,兩者可以很完美的融合運作,不會有任何違和感。

73 |

backbone.js 由於使用了 Underscore.js 這個框架,可以很容易的進行集合的鏈式處理,而 Underscore.js 框架裡又有一個簡易的樣板引擎,可以用來將樣板轉換成HTML區塊輸出,只要用view物件搭配Underscore.js,就可以得到一個相當完整的 MVC 框架了。

74 |

在 model 部份,backbone 的模型資料有任何修改時,都會觸發一些資料修改事件,只要在這些事件當中加入對應的程式碼,例如更新畫面或回傳資料到伺服器,就可以成為一個完整的網頁應用程式了。

75 |

React.js

76 |

React.js 是 facebook 公司所創建的一個開源專案,扮演的角色主要是 MVC 架構中的 View 角色,在 React.js 的官網中有個非常簡單的範例如下:

77 |
 <!DOCTYPE html>
 78 | <html>
 79 |   <head>
 80 |     <script src="build/react.js"></script>
 81 |     <script src="build/JSXTransformer.js"></script>
 82 |   </head>
 83 |   <body>
 84 |     <div id="example"></div>
 85 |     <script type="text/jsx">
 86 |       React.render(
 87 |         <h1>Hello, world!</h1>,
 88 |         document.getElementById('example')
 89 |       );
 90 |     </script>
 91 |   </body>
 92 | </html>
93 |

這個範例大概可以說是 React.js 版本的 hello world! 您可以看到其中的關鍵部份是 React.render 這一段。

94 |
      React.render(
 95 |         <h1>Hello, world!</h1>,
 96 |         document.getElementById('example')
 97 |       );
98 |

React 的特別之處是在 javascript 裡面放入了 HTML/XML 的內容,以下是 react官網中的一段關鍵描述,說明了react為何要搭配 JSXTransformer 去將 HTML/XML 語法轉換成 javascript 的原因,這樣就可以將 HTML/XML 完全的 javascript 化了。

99 |
100 |

The XML syntax inside of JavaScript is called JSX; check out the JSX syntax to learn more about it. In order to translate it to vanilla JavaScript we use <script type="text/jsx"> and include JSXTransformer.js to actually perform the transformation in the browser.

101 |
102 |

看清楚上述範例之後,您可以試著看看 5 Practical Examples For Learning The React Framework 這篇文章,該文章用 jsFiddle 提供了五個活生生的線上範例,讓您可以直接感受到 React.js 的功能,這五個範例如下:

103 | 110 |

看完上述的範例,我對 react.js 的認知大概是,一種將 XML/HTML 包在 javascript 裡撰寫的技術,用一套物件架構將網頁呈現過程包在物件內部,將 HTML/XML 的呈現動作完全變成 javascript 的物件。

111 |

Angular.js

112 |

雖然最近 React.js 的勢頭似乎有點蓋過 Angular.js 了,但是瞭解一下 Angular.js 也是不錯的,您可以看看 Learn AngularJS With These 5 Practical Examples 這篇文章與其中的範例。

113 |

我發現 Angular.js 的想法似乎與 React.js 完全相反, Angular 感覺是以 HTML 的 ng-* 自訂屬性為主,所發展出來的一套顯示框架,像是 ng-app, ng-controller, ng-model, ng-show 等屬性,然後將 ng-* 屬性、嵌入的 {{*}} 變數以及 $ 為字首的 javascript 變數或函數關聯起來,形成一套 MVC 架構。

114 |

所以我認為 Angular.js 應該是一套完整的 MVC 架構, 不需要再和其他框架結合起來就能運作了。相反的, facebook 則建議 React.js 應該和 Flux 這個架構搭配 , 才能形成更完整的架構。(當然您也可以將 React.js 拿來和 backbone.js 搭配)

115 |

結語

116 |

對於這些前端框架的用途,筆者已經困惑好久了,寫完這篇文章,腦袋裏終於有些似懂非懂的概念了,希望我的理解沒有錯誤阿!

117 |
118 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /code/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /htm/article1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 28 | 29 | 30 | 31 |
32 |

程式人雜誌 -- 2015 年 1 月號 (開放公益出版品)

33 |
34 |
35 | 40 |

Web 可離線應用 1 -- 逐字英翻中系統

41 |

本系統已經上傳到 github 上,您可以點選下列連結試用一下這個「英翻中系統」系統,然後在開始閱讀本文:

42 | 45 |

為了要說明如何用 HTML5/CSS/JavaScript 建構出可單頁獨立運作,又可透過 localstorage 記住使用者資訊的網頁應用,我們建立了一個「逐字英翻中系統」,讓使用者可以透過 localstorage 儲存使用者紀錄的一些資訊。

46 |

首先我們在 spa.js (Single Page Application 的簡寫) 當中創建了一個稱為 DB 的物件,該物件可以用來協助「載入或儲存」資訊到 localstorage 當中,如此就可以用 load(), save() 函數記住這些資訊,必須注意的是 localstorage 當中只能儲存字串資訊,因此我們必須用 JSON.stringify() 等函數將 JSON 物件轉換成字串後才能儲存,而在取出後再用 JSON.parse() 將字串轉回 JSON 物件。

47 |

檔案: spa.js

48 |
...
 49 | var DB = {};
 50 | 
 51 | DB.forget = function DB_forget(name) {
 52 |   window.localStorage.removeItem(name);
 53 | }
 54 | 
 55 | DB.load = function DB_load(name) {
 56 |    if (window.localStorage[name] !== undefined) 
 57 |      return JSON.parse(window.localStorage[name]);
 58 |    else
 59 |      return undefined;
 60 | }
 61 | 
 62 | DB.save = function DB_save(name, obj) {
 63 |   window.localStorage[name] = JSON.stringify(obj);
 64 | }
 65 | ...
66 |

然後、我們撰寫了 mt.html 這個網頁程式,以下是該網頁的一個執行畫面:

67 |
68 | 圖、逐字英翻中系統

圖、逐字英翻中系統

69 |
70 |

該網頁的完整原始碼如下所示:

71 |

檔案:mt.html

72 |
<!-- firefox 似乎不支援 ruby tag : http://www.w3schools.com/tags/tag_ruby.asp -->
 73 | <html>
 74 | <head>
 75 | <meta charset="utf-8" />
 76 |   <link rel="icon" href="favicon.ico">
 77 |   <link href="css/bootstrap.min.css" rel="stylesheet">
 78 |   <link href="elearn.css" rel="stylesheet">
 79 | </head>
 80 | <body onload="load()">
 81 |     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation" id="navbar">
 82 |     </nav>
 83 |     <div id="panelMT" class="container panel">
 84 |       <p class="lead">
 85 |         <form name="formMT" class="lead">
 86 |           <div class="row" style="height:300px">
 87 |             <div class="col-md-6">
 88 |               <div class="page-header">
 89 |                 <span data-mt="English">原文</span>
 90 |                 <input type="text" id="query" equired autofocus data-mt="Query" placeholder="" size="12"/> 
 91 |                 <button class="btn btn-primary" type="button" data-mt="Query">查詢</button>
 92 |                 <button class="btn btn-primary" type="button" data-mt="Translation" onclick="doMT()"  style="float:right">翻譯</button>
 93 |               </div>
 94 |               <textarea id="ebox" class="form-control" style="height:100%">
 95 | The snow glows white on the mountain tonight.
 96 | Not a footprint to be seen.
 97 | A kingdom of isolation, and it looks like I'm the Queen.
 98 | The wind is howling like this swirling storm inside.
 99 | Couldn't keep it in; Heaven knows I've tried.
100 | 
101 | Don't let them in, don't let them see.
102 | Be the good girl you always have to be.
103 | Conceal, don't feel, don't let them know.
104 | Well now they know.
105 | 
106 | Let it go, let it go.
107 | Can't hold it back any more.
108 | Let it go, let it go.
109 | Turn away and slam the door.
110 | I don't care.
111 | What they're going to say.
112 | Let the storm rage on, the cold never bothered me anyway.
113 |           </textarea>
114 |             </div>
115 |             <div class="col-md-6">
116 |               <div class="page-header">
117 |                 <span data-mt="Translation"></span>
118 |                 <input type="text" id="queryResult" equired autofocus data-mt="queryResult" placeholder="" size="15"/>
119 |                 <button class="btn btn-primary" type="button" data-mt="Save">儲存</button>
120 |                 <button class="btn btn-success" type="button" data-mt="Forget" onclick="forget()" style="float:right">忘記</button>
121 |               </div>
122 |               <div id="cbox" style="width:100%; height:100%; border:1px dotted #888; overflow:auto;" class="form-control"></div>
123 |             </div>
124 |             <div></div>
125 |           </div> <!-- row -->
126 |         </form>
127 |       </p>
128 |     </div>
129 | <script>
130 | var ebox, cbox, dict;
131 | 
132 | function load() {
133 |   ebox = document.getElementById("ebox");
134 |   cbox = document.getElementById("cbox");
135 |   dict = e2cTV;
136 |   var dbKnowWords = DB.load('knowWords');
137 |   if (dbKnowWords === undefined)
138 |     knowWords = {};
139 |   else
140 |     knowWords = dbKnowWords;
141 | }
142 | 
143 | function forget() {
144 |   DB.forget('knowWords');
145 |   knowWords = {};
146 | }
147 | 
148 | function normalize(e) {
149 |   return e.replace("'", '_').toLowerCase();
150 | }
151 | 
152 | function mt(str) {
153 |   var re = /([\w']+)/gi;  
154 |   var toStr = "";
155 |   var si = 0;
156 |   while (m = re.exec(str)) {
157 |     var eword = m[1], elower=eword.toLowerCase();
158 |     var cword = dict[eword.toLowerCase()];
159 |     toStr += str.substring(si, re.lastIndex-eword.length);
160 |     if (cword === undefined || knowWords[elower] !== undefined)
161 |       cword = "";
162 |     toStr += '<ruby class="'+normalize(eword)+'"><rb>'+eword+'</rb><rt>'+cword+'</rt></ruby>';
163 |     si = re.lastIndex;
164 |   }
165 |   return toStr;
166 | }
167 | 
168 | function doMT() {
169 |   var cstr = mt(ebox.value);
170 |   cbox.innerHTML = cstr.replace(/\n/g, "<BR/>");
171 |   $('ruby').click(function() {
172 |     var e = $(this).find('rb').text().toLowerCase();
173 |     var c = $(this).find('rt').text();
174 |     knowWords[e] = c;
175 |     $('#query').val(e);
176 |     $('#queryResult').val(e+'='+c);
177 |     $('.'+normalize(e)).find('rt').hide();
178 |   });
179 | }
180 | 
181 | window.onbeforeunload = function(){
182 |   DB.save('knowWords', knowWords);
183 | };
184 | </script>
185 |     <script src="js/jquery.min.js"></script>
186 |     <script src="js/bootstrap.min.js"></script>
187 |     <script src="e2c.js"></script>
188 |     <script src="spa.js"></script>
189 |     <script src="dict.js"></script>
190 |     <script src="navmenu.js"></script>
191 | </body>
192 | </html>
193 |

在上述程式中,我們透過攔截 window.onbeforeunload 事件,在離開網頁之前儲存想記憶的物件。

194 |
window.onbeforeunload = function(){
195 |   DB.save('knowWords', knowWords);
196 | };
197 |

然後在網頁載入時,我們會檢查是否有已經記住的物件,若有則將之載入恢復,這樣就可以透過 localstorage 在網頁中記住較大量的資訊 (記憶量大小各家瀏覽器不同,但大致都在 5MB 以上),這比傳統的 cookie 大多了,而且 localstorage 不會像 cookie 那樣每次都被放在表頭裡傳回伺服器,因此很適合用來於瀏覽器當中儲存較大量的資訊。

198 |
function load() {
199 | ...
200 |   var dbKnowWords = DB.load('knowWords');
201 |   if (dbKnowWords === undefined)
202 |     knowWords = {};
203 |   else
204 |     knowWords = dbKnowWords;
205 | }
206 |

那麼、我們到底用 knowWords 物件來記住甚麼資訊呢? 關於這點,請讀者仔細觀看下列的 doMT() 程式段落,該函數是用來將 ebox 英文區塊透過 mt() 函數逐字翻譯後,用 ruby 標記顯示中英對照在 ebox 當中,於是讀者才能看到中文在上英文在下的對照翻譯。

207 |
function mt(str) {
208 |   var re = /([\w']+)/gi;  
209 |   var toStr = "";
210 |   var si = 0;
211 |   while (m = re.exec(str)) {
212 |     var eword = m[1], elower=eword.toLowerCase();
213 |     var cword = dict[eword.toLowerCase()];
214 |     toStr += str.substring(si, re.lastIndex-eword.length);
215 |     if (cword === undefined || knowWords[elower] !== undefined) // 已經認識的字詞就不需要再翻譯了
216 |       cword = "";
217 |     toStr += '<ruby class="'+normalize(eword)+'"><rb>'+eword+'</rb><rt>'+cword+'</rt></ruby>';
218 |     si = re.lastIndex;
219 |   }
220 |   return toStr;
221 | }
222 | 
223 | function doMT() {
224 |   var cstr = mt(ebox.value);
225 |   cbox.innerHTML = cstr.replace(/\n/g, "<BR/>");
226 |   $('ruby').click(function() {
227 |     var e = $(this).find('rb').text().toLowerCase();
228 |     var c = $(this).find('rt').text();
229 |     knowWords[e] = c;
230 |     $('#query').val(e);
231 |     $('#queryResult').val(e+'='+c);
232 |     $('.'+normalize(e)).find('rt').hide(); // 將使用者點掉的字詞之翻譯隱藏起來。
233 |   });
234 | }
235 |

當使用者點選某個「中英對照」字詞的時候,代表該使用者已經認識該字詞了,所以我們會將該字詞記錄在 knowWords 這個字典物件當中,並且隱藏該字詞的翻譯,如此當使用者認識的字越來越多,被翻譯的字詞也就會越來越少,於是隨著使用者的進步就可以逐漸完全讀懂整篇原文,而不需要依賴系統的翻譯功能了 (這也是本系統與一般翻譯系統最大的不同點,本系統是幫助學習英文,而不是企圖做出一個很厲害的機器翻譯系統)。

236 |
237 | 圖、將已經學會的單字點掉後,離開網頁再回來時的情況

圖、將已經學會的單字點掉後,離開網頁再回來時的情況

238 |
239 |

上述程式裡的幾個關鍵部分,我們已經用了中文註解進行說明,讀者應該很容易可以看出這幾個關鍵程式碼的功能才對!

240 |

透過這種方式,我們可以讓網頁變成一種類似 APP 的應用,而且不需要伺服端的配合。

241 |

(當然、如果加上伺服端之後,還可以將這些 localstorage 中的資訊傳回到伺服器永久記住,這樣即使換了一台電腦,也不會忘記這些資訊了)。

242 |
243 | 246 | 247 | 248 | -------------------------------------------------------------------------------- /code/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn-default .badge, 33 | .btn-primary .badge, 34 | .btn-success .badge, 35 | .btn-info .badge, 36 | .btn-warning .badge, 37 | .btn-danger .badge { 38 | text-shadow: none; 39 | } 40 | .btn:active, 41 | .btn.active { 42 | background-image: none; 43 | } 44 | .btn-default { 45 | text-shadow: 0 1px 0 #fff; 46 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 47 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 48 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 49 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 50 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 51 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 52 | background-repeat: repeat-x; 53 | border-color: #dbdbdb; 54 | border-color: #ccc; 55 | } 56 | .btn-default:hover, 57 | .btn-default:focus { 58 | background-color: #e0e0e0; 59 | background-position: 0 -15px; 60 | } 61 | .btn-default:active, 62 | .btn-default.active { 63 | background-color: #e0e0e0; 64 | border-color: #dbdbdb; 65 | } 66 | .btn-default:disabled, 67 | .btn-default[disabled] { 68 | background-color: #e0e0e0; 69 | background-image: none; 70 | } 71 | .btn-primary { 72 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 73 | background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 74 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2)); 75 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); 76 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); 77 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 78 | background-repeat: repeat-x; 79 | border-color: #2b669a; 80 | } 81 | .btn-primary:hover, 82 | .btn-primary:focus { 83 | background-color: #2d6ca2; 84 | background-position: 0 -15px; 85 | } 86 | .btn-primary:active, 87 | .btn-primary.active { 88 | background-color: #2d6ca2; 89 | border-color: #2b669a; 90 | } 91 | .btn-primary:disabled, 92 | .btn-primary[disabled] { 93 | background-color: #2d6ca2; 94 | background-image: none; 95 | } 96 | .btn-success { 97 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 98 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 99 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 100 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 101 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 102 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 103 | background-repeat: repeat-x; 104 | border-color: #3e8f3e; 105 | } 106 | .btn-success:hover, 107 | .btn-success:focus { 108 | background-color: #419641; 109 | background-position: 0 -15px; 110 | } 111 | .btn-success:active, 112 | .btn-success.active { 113 | background-color: #419641; 114 | border-color: #3e8f3e; 115 | } 116 | .btn-success:disabled, 117 | .btn-success[disabled] { 118 | background-color: #419641; 119 | background-image: none; 120 | } 121 | .btn-info { 122 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 123 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 124 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 125 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 126 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 127 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 128 | background-repeat: repeat-x; 129 | border-color: #28a4c9; 130 | } 131 | .btn-info:hover, 132 | .btn-info:focus { 133 | background-color: #2aabd2; 134 | background-position: 0 -15px; 135 | } 136 | .btn-info:active, 137 | .btn-info.active { 138 | background-color: #2aabd2; 139 | border-color: #28a4c9; 140 | } 141 | .btn-info:disabled, 142 | .btn-info[disabled] { 143 | background-color: #2aabd2; 144 | background-image: none; 145 | } 146 | .btn-warning { 147 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 148 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 149 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 150 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 151 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 152 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 153 | background-repeat: repeat-x; 154 | border-color: #e38d13; 155 | } 156 | .btn-warning:hover, 157 | .btn-warning:focus { 158 | background-color: #eb9316; 159 | background-position: 0 -15px; 160 | } 161 | .btn-warning:active, 162 | .btn-warning.active { 163 | background-color: #eb9316; 164 | border-color: #e38d13; 165 | } 166 | .btn-warning:disabled, 167 | .btn-warning[disabled] { 168 | background-color: #eb9316; 169 | background-image: none; 170 | } 171 | .btn-danger { 172 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 173 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 174 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 175 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 176 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 177 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 178 | background-repeat: repeat-x; 179 | border-color: #b92c28; 180 | } 181 | .btn-danger:hover, 182 | .btn-danger:focus { 183 | background-color: #c12e2a; 184 | background-position: 0 -15px; 185 | } 186 | .btn-danger:active, 187 | .btn-danger.active { 188 | background-color: #c12e2a; 189 | border-color: #b92c28; 190 | } 191 | .btn-danger:disabled, 192 | .btn-danger[disabled] { 193 | background-color: #c12e2a; 194 | background-image: none; 195 | } 196 | .thumbnail, 197 | .img-thumbnail { 198 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 199 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 200 | } 201 | .dropdown-menu > li > a:hover, 202 | .dropdown-menu > li > a:focus { 203 | background-color: #e8e8e8; 204 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 205 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 206 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 207 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 208 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 209 | background-repeat: repeat-x; 210 | } 211 | .dropdown-menu > .active > a, 212 | .dropdown-menu > .active > a:hover, 213 | .dropdown-menu > .active > a:focus { 214 | background-color: #357ebd; 215 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 216 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 218 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 220 | background-repeat: repeat-x; 221 | } 222 | .navbar-default { 223 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 224 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 225 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 226 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 227 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 228 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 229 | background-repeat: repeat-x; 230 | border-radius: 4px; 231 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 232 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 233 | } 234 | .navbar-default .navbar-nav > .open > a, 235 | .navbar-default .navbar-nav > .active > a { 236 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 237 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 238 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 239 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 240 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 241 | background-repeat: repeat-x; 242 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 243 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 244 | } 245 | .navbar-brand, 246 | .navbar-nav > li > a { 247 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 248 | } 249 | .navbar-inverse { 250 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 251 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 253 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 255 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 256 | background-repeat: repeat-x; 257 | } 258 | .navbar-inverse .navbar-nav > .open > a, 259 | .navbar-inverse .navbar-nav > .active > a { 260 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 261 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 262 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 263 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 264 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 265 | background-repeat: repeat-x; 266 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 267 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 268 | } 269 | .navbar-inverse .navbar-brand, 270 | .navbar-inverse .navbar-nav > li > a { 271 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 272 | } 273 | .navbar-static-top, 274 | .navbar-fixed-top, 275 | .navbar-fixed-bottom { 276 | border-radius: 0; 277 | } 278 | .alert { 279 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 280 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 281 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 282 | } 283 | .alert-success { 284 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 285 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 286 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 287 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 288 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 289 | background-repeat: repeat-x; 290 | border-color: #b2dba1; 291 | } 292 | .alert-info { 293 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 294 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 295 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 296 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 297 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 298 | background-repeat: repeat-x; 299 | border-color: #9acfea; 300 | } 301 | .alert-warning { 302 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 303 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 304 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 305 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 306 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 307 | background-repeat: repeat-x; 308 | border-color: #f5e79e; 309 | } 310 | .alert-danger { 311 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 312 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 313 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 314 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 315 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 316 | background-repeat: repeat-x; 317 | border-color: #dca7a7; 318 | } 319 | .progress { 320 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 321 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 323 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .progress-bar { 328 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 329 | background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%); 330 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9)); 331 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 332 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 333 | background-repeat: repeat-x; 334 | } 335 | .progress-bar-success { 336 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 337 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 338 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 339 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 340 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 341 | background-repeat: repeat-x; 342 | } 343 | .progress-bar-info { 344 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 345 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 346 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 347 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 348 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 349 | background-repeat: repeat-x; 350 | } 351 | .progress-bar-warning { 352 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 353 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 355 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 357 | background-repeat: repeat-x; 358 | } 359 | .progress-bar-danger { 360 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 361 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 362 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 363 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 364 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 365 | background-repeat: repeat-x; 366 | } 367 | .progress-bar-striped { 368 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 369 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 370 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 371 | } 372 | .list-group { 373 | border-radius: 4px; 374 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 375 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 376 | } 377 | .list-group-item.active, 378 | .list-group-item.active:hover, 379 | .list-group-item.active:focus { 380 | text-shadow: 0 -1px 0 #3071a9; 381 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 382 | background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%); 383 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3)); 384 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 385 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 386 | background-repeat: repeat-x; 387 | border-color: #3278b3; 388 | } 389 | .list-group-item.active .badge, 390 | .list-group-item.active:hover .badge, 391 | .list-group-item.active:focus .badge { 392 | text-shadow: none; 393 | } 394 | .panel { 395 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 396 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 397 | } 398 | .panel-default > .panel-heading { 399 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 400 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 401 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 402 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 403 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 404 | background-repeat: repeat-x; 405 | } 406 | .panel-primary > .panel-heading { 407 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 408 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 409 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 410 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 411 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 412 | background-repeat: repeat-x; 413 | } 414 | .panel-success > .panel-heading { 415 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 416 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 417 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 418 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 419 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 420 | background-repeat: repeat-x; 421 | } 422 | .panel-info > .panel-heading { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 428 | background-repeat: repeat-x; 429 | } 430 | .panel-warning > .panel-heading { 431 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 432 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 433 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 434 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 435 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 436 | background-repeat: repeat-x; 437 | } 438 | .panel-danger > .panel-heading { 439 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 440 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 441 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 442 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 443 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 444 | background-repeat: repeat-x; 445 | } 446 | .well { 447 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 448 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 449 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 450 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 451 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 452 | background-repeat: repeat-x; 453 | border-color: #dcdcdc; 454 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 455 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 456 | } 457 | /*# sourceMappingURL=bootstrap-theme.css.map */ 458 | -------------------------------------------------------------------------------- /code/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.0",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus","focus"==b.type)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.0",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c="prev"==a?-1:1,d=this.getItemIndex(b),e=(d+c)%this.$items.length;return this.$items.eq(e)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i="next"==b?"first":"last",j=this;if(!f.length){if(!this.options.wrap)return;f=this.$element.find(".item")[i]()}if(f.hasClass("active"))return this.sliding=!1;var k=f[0],l=a.Event("slide.bs.carousel",{relatedTarget:k,direction:h});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var m=a(this.$indicators.children()[this.getItemIndex(f)]);m&&m.addClass("active")}var n=a.Event("slid.bs.carousel",{relatedTarget:k,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),j.sliding=!1,setTimeout(function(){j.$element.trigger(n)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(n)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.0",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.find("> .panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('