跟Eclipse, Aptana比起來開發前端又簡潔又快,而且有相當多的第三方套件支援。tuts+有一系列的影片介紹:Perfect Workflow in Sublime Text 2。 Ubuntu安裝方式如下:
1 2 3 | sudo add-apt-repository ppa:webupd8team/sublime-text-2 sudo apt-get update sudo apt-get install sublime-text |
另外還寫了一個「關閉除了現有檔案」的功能,將以下程式碼儲存為close_others.py放在Packages/User下:
1 2 3 4 5 6 7 | import sublime, sublime_plugin class CloseOthersCommand(sublime_plugin.TextCommand): def run(self, edit): window = self.view.window() group_index, view_index = window.get_view_index(self.view) window.run_command("close_others_by_index", { "group": group_index, "index": view_index}) |
然後在Default (OSX).sublime-keymap(Preference - key binding)中加入以下指令即可使用: { "keys": ["super+shift+w"], "command": "close_others" },
]]>not work in FF: CSS Exercise#1
]]>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function jsonpCallback(data) { // 需要public出來,不然會呼叫不到! console.log(data); } function remote() { $.ajax({ url: "http://demosite2013.herokuapp.com/exercise/crossDomain/jsonp.php", dataType: "jsonp", jsonpCallback: "jsonpCallback", success: function(data) { console.log("success: " + data); } }); } jQuery(document).ready(function(){ remote(); }); |
也可以利用<script> tag直接呼叫:
1 | <script type="text/javascript" src="http://demosite2013.herokuapp.com/exercise/crossDomain/jsonp.php?callback=jsonpCallback"></script> |
Server端的寫法:
1 2 3 4 | <?php header('content-type: application/json; charset=utf-8'); $data = "這是Server回傳資料!"; echo $_GET['callback'].'('.json_encode($data).')'; ?> |
- CORS:最近常見也是W3C推薦的做法。 Client端只要依照一般的ajax request要求即可,這裡用jQuery來實現。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | (function (window, document, undefined) { function remote() { $.ajax({ url: "http://demosite2013.herokuapp.com/exercise/crossDomain/cors.php", success: function(data) { console.log("success: " + data); } }); } jQuery(document).ready(function(){ remote(); }); })(window, document); |
Server端的寫法比較要考慮是否要接受/拒絕cross domain requests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php header('content-type: application/json; charset=utf-8'); if ($_SERVER['REQUEST_METHOD'] == "OPTIONS") { // Tell the Client we support invocations and that this preflight holds good for only 20 days header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, GET, OPTIONS'); header('Access-Control-Max-Age: 1728000'); header("Content-Length: 0"); header("Content-Type: application/json"); } elseif($_SERVER['REQUEST_METHOD'] == "GET" || "POST") { header('Access-Control-Allow-Origin: *'); header('Content-Type: application/json'); $data = "這是Server回傳資料!"; echo json_encode($data); } else { die("No Other Methods Allowed"); } ?> |
如果沒有瀏覽器相容性的要求,建議是以CORS實現,彈性比較大也可以發post request;如果使用JSONP的話只能處理get request,而且也不算是Ajax的實現。
]]>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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | (function ($, window, document, undefined) { var Gist = { init: function (options, target) { var self = this; $.extend($.fn.queryGist.options, options); self.API_URL = 'https://api.github.com/gists'; self.$target = $(target); self.username = $.fn.queryGist.options.username; self.password = $.fn.queryGist.options.password; self.search = $.fn.queryGist.options.search.trim().replace(/\s+/, ' '); self.fetch().done(function (results) { self.list(results); self.display(); }).fail(function(jqXHR, textStatus, errorThrown) { alert('Request failed: ' + errorThrown + '\r\n請檢查帳號密碼是否正確!'); }); }, fetch: function () { return $.ajax({ url: this.API_URL, headers: { Authorization: 'Basic ' + btoa(this.username + ':' + this.password) } }); }, list: function (results) { var file, regs, i; results = results.map(function (gist) { file = Object.keys(gist.files)[0]; return gist.files[file]; }); if (!!this.search) { regs = this.search.split(' '); results = results.filter(function (file) { for (i = 0; i < regs.length; i++) { if (new RegExp(regs[i], 'i').test(file.filename)) { return true; } } return false; }); } this.gists = results; }, display: function () { var self = this; self.$target.html(''); $(self.gists).each(function (idx, gist) { $('<a/>', { href: gist.raw_url, target: '_blank', text: gist.filename }).appendTo(self.$target); self.$target.append('<br>'); }); } }; $.fn.queryGist = function(options) { return this.each(function() { var gist = Object.create(Gist); gist.init(options, this); }); }; $.fn.queryGist.options = { username: null, password: null, search: null }; })(jQuery, window, document); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function Camera(img) { this.img = img; // 圖片來源 } Camera.prototype = { refresh: function() { var uniq = Math.random(); $('#cam').attr('src', this.img + '?uniq=' + uniq); }, loadImg: function () { var self = this; $('#cam').load(function() { // 註冊onload事件,當圖片載完3秒後觸發refresh事件 setTimeout(function() { self.refresh.call(self); }, 3000); }); } }; |
請參考:實作範例
]]>1 2 3 | <?php include_once("_index.html"); ?> |
部署步驟如下: 1.為網站建立一個專案:
1 2 | mkdir heroku cd heroku |
2.建立index.php,並指向靜態網站首頁。 3.推送到Heroku上:
1 2 3 4 5 | git init git add . heroku create <appName> git commit -m "initial commit" git push heroku master |
4.打開網站確認:
1 | heroku open
|
部署完成囉! -- 題外話,有試著偷渡把index.html改成index.jsp,想當然是失敗了......push時報錯:! Push rejected, no Cedar-supported app detected
]]>Ubuntu:
Mac:
另外finder沒有可以選擇顯示隱藏檔的設定,可以在appleScript寫入以下內容,儲存為應用程式,拉到finder功能列作使用(參考來源):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | set question to display dialog "Show or hide hidden files?" & return & "Don't that forget this will relaunch Finder." buttons {"Show hidden files", "Hide hidden files", "Cancel"} set theAnswer to button returned of result if theAnswer is "Show hidden files" then do shell script "defaults write com.apple.finder AppleShowAllFiles TRUE && killall Finder" end if if theAnswer is "Hide hidden files" then do shell script "defaults write com.apple.finder AppleShowAllFiles FALSE && killall Finder" end if if theAnswer is "Cancel" then return end if |
1 2 3 | (function ($, window, document, undefined) { // code here... })(jQuery, window, document); |
2. 利用$.fn._pluginName去新增jQuery的plugin方法供使用者呼叫。
3. 讓options可以更有彈性地被使用者呼叫,範例這裡是把options作為plugin的property去實現:$.fn._pluginName.options
4. plugin最後要記得返回jQuery的object作為之後chaining使用。
5. catch this,避免在之後使用時this被指為呼叫方法的物件誤用(範例是把this指給名為self的變數)
6. 利用Object.create去生成物件的instance(function的話直接使用new就可以了,範例把plugin主要的code包在Object裡),注意並不是所有瀏覽器都支援Object.create的寫法,可以加上這段code確保執行沒有問題:
1
2
3
4
5
6
7
if ( typeof Object.create !== 'function' ) {
Object.create = function( obj ) {
function F() {};
F.prototype = obj;
return new F();
};
}
$.extend
去覆寫options的預設值(盡量把可設定的變數都寫在$.fn._pluginName.options
裡,沒有預設值的就設成null無妨,主要是之後維護時可以一目瞭然有哪些變數可供設定)
8. 一個方法只做一件事可以確保程式容易被測試和維護。
再說比起Ruby,javascript對我來說方便調整多了,一整個神清氣爽。
--
Hexo專案 (是台灣人開發的)
Hexo說明文件
網誌用到的Plugins:RSS, Sitemap
主題:Persona Dark
--
網站的網頁用EJS樣板文件產生,CSS以Stylus維護,通常只要更改這些檔案就可以了。
舉例來說如果要將文章中的超連結另開視窗,又不想在md檔加上HTML的tag,可以修改head.ejs
加入以下script:
1 2 3 4 5 6 7 8 9 | <script> (function (window, document, undefined) { $(document).ready(function() { $('article a[href^="http"]').each(function () { $(this).attr('target', '_blank'); }); }); })(this, document); </script> |
and if you want to checkout the project: git clone _repositoryPath _projectname