2014-11-10 11:45

[轉載] Javascript Char Codes (Key Codes)

轉載自:Javascript Char Codes (Key Codes)

KeyCode
backspace8
tab9
enter13
shift16
ctrl17
alt18
pause/break19
caps lock20
escape27
page up33
page down34
end35
home36
left arrow37
up arrow38
right arrow39
down arrow40
insert45
delete46
048
149
250
351
452
553
654
755
856
957
a65
b66
c67
d68
KeyCode
e69
f70
g71
h72
i73
j74
k75
l76
m77
n78
o79
p80
q81
r82
s83
t84
u85
v86
w87
x88
y89
z90
left window key91
right window key92
select key93
numpad 096
numpad 197
numpad 298
numpad 399
numpad 4100
numpad 5101
numpad 6102
numpad 7103
KeyCode
numpad 8104
numpad 9105
multiply106
add107
subtract109
decimal point110
divide111
f1112
f2113
f3114
f4115
f5116
f6117
f7118
f8119
f9120
f10121
f11122
f12123
num lock144
scroll lock145
semi-colon186
equal sign187
comma188
dash189
period190
forward slash191
grave accent192
open bracket219
back slash220
close braket221
single quote222
  
2014-10-02 09:48

[轉載] Superpower your JavaScript with 10 quick tips - For Beginners

轉載自:Superpower your JavaScript with 10 quick tips - For Beginners

Who doesn't love to write better code? In this article I will list 10 simple and quick JavaScript tips that will help beginners improve their code quality. You might know some of these already. In case you didn't feel free to buy me a beer later.


#1 - Use && and || Operators Like a Boss


Well, JavaScript gives you two awesome logical operators : && and ||. In other languages like Java or C++ they always return a boolean value. But things get a bit interesting when it comes to JavaScript. The && and || operators return the last evaluated operand. Have a look at the following

function getMeBeers(count){
    if(count){
        return count;
    } 
    else{
        return 1;
    }
}

Well, our function is simple and returns the required number of beers. If you specify no argument, it simply gives you a single beer. Here, you can use || to refactor the code as following:

function getMeBeers(count){
    return count || 1;
}

In case of || if the first operand is falsy, JavaScript will evaluate the next operand. So, if no count is specified while calling the function, 1 will be returned. On the other hand, if count is specified then it will be returned (as the first operand is truthy in this case).

Note: null, false,0 (the number), undefined, NaN, and '' (empty string) are falsy values. Any other value is considered truthy.

Now if you want to allow adults only, you can use && as following:

function getMeBeers(age, count){
    return (age>=18) && (count || 1);
}

Instead of :

function getMeBeers(age, count){
    if(age>=18){
        return count || 1;
    }
}

In the above case if age < 18, JavaScript won't even bother evaluating the next operand. So, our function will return. But if the age is actually >= 18, the first operand will evaluate to true and then the next operand will be evaluated.

By the way you should be a careful here. If you pass count as 0, the function will return 1 (as 0 is falsy). So, in a real world app you should be careful while handling numeric values.



#2 - Use === and !== Instead of == and !=


The operators == and != do automatic type conversion, if needed. But === and !== will consider both value and type while comparing and won't do any automatic type conversion. So, to reliably compare two values for equality/non-equality always use === and !==.

10 == '10' //true

10 === '10' //false

10 === 10 //true



#3 - Use Strict mode while writing JS


Strict mode was introduced in ECMA 5. It allows you to put a function or an entire script into strict operating context. The benefits are:

  1. It eliminates some of the silent JavaScript errors by throwing the errors explicitly.
  2. It throws exceptions when relatively unsafe actions take place.
  3. Sometimes strict mode code can run faster than non strict mode code.

<script type="text/javascript">
      'use strict'
      //Strict mode code goes here
</script>

Or,

function strictCode(){
    'use strict'
    //This is a strict mode function
}

As currently all the major browsers support this feature you should start using strict mode.



#4 - Use splice() to remove an array element


If you want to remove an element from an array use splice() instead of delete. delete sets the particular array item to undefined while splice() actually removes the item.

var array=[1,2,3];
delete array[1]; // now array= [1,undefined,3]

array.splice(1,1); //now array=[1,3]



#5 - Use [] to create new array


Use [] to create a new array. Writing var a=[1,2,3] will create a 3-element array whereas new Array(N) will create a physically empty array of N logical length.

Similarly, use var a={} to create an object rather than new Object(). The former one is compact, readable and takes less space. You can also instantly populate the object like:

var a = {
    name: 'John Doe',
    email: 'john@doe.com'
}



#6 - Use String.link() to create Hyperlinks


Many times in JavaScript you will need to generate HTML anchors on the fly. For that you will need some concatenation which may look ugly and messy.

var text="Cool JS Tips";
var url="http://www.htmlxprs.com";
var block='<a href="'+url+'">'+ text +'</a>';

Instead, how about this:

var block=text.link(url); // <a href="http://www.htmlxprs.com">Cool JS Tips</a>



#7 - Cache the length while looping


While looping through a JavaScript array you can cache the length so that the overall performance is better:

for (var i=0,length=array.length; i<length; i++){
    //awesome code goes here
}

Be careful while creating an inner loop. You need to name the length variable differently in the inner one.



#8 - Put 'var' before your variable name


While creating variables don't forget to use the var keyword. If you forget then the variable gets added to the global scope which is definitely a bad thing.

var localVar=12; //this is a local variable

globalVar=12; //variable goes to 'window' global



#9 - Use Closures and Self Executing Functions


Closures, if used carefully and precisely, can take your JS code to a whole new level. There are plenty of tutorials available which can teach you about closures. I will just give an example of closures and self executing functions for creating modular code:

var car=(function(){
    var _name='Benz Velo'; 
    return {
        getName: function(){
            return _name;
        }
    }
})(); //function created and invoked

console.log(car.getName()); //Logs Benz Velo

As you see we just created a function and immediately invoked it. These are called self executing functions or Immediately Invoked Function Expression (IIFE). The function returns an object which is stored in variable car. We also used closure because the object being returned can access the variable _name defined by the parent function. This is helpful for creating modules and emulating private variables.



#10 - There is always room for Optimization


Use jsHint or jsLint to check your code quality and improve further. Also don't forget to minify and concatenate your JS files while deploying your app. Finally, use SourceMaps to make debugging a breeze.



Conclusion


Tips can be unlimited. But I hope these 10 quick tips will help you write better code and superpower your JS-Foo. If you loved this you will love our newsletter as well. Don't forget to subscribe.
2014-05-08 02:58

[AngularJS] 製作 jQuery UI Sortable directive

Html
<div jq-sortable="selectedList">
    <div ng-repeat="item in selectedList">
        <img ng-src="{{item.src}}" />
    </div>
</div>


JavaScript
app.directive('jqSortable', ['$parse', function($parse) {
    return function(scope, element, attrs) {
        /*解析並取得表達式*/
        var expr = $parse(attrs['jqSortable']);
        var $oldChildren;

        element.sortable({
            opacity: 0.7,
            scroll: false,
            tolerance: "pointer",
            start: function() {
                /*紀錄移動前的 children 順序*/
                $oldChildren = element.children('[ng-repeat]');
            },
            update: function(){
                var newList = [];
                var oldList = expr(scope);
                var $children = element.children('[ng-repeat]');

                /*產生新順序的陣列*/
                $oldChildren.each(function(i){
                    var index = $children.index(this);
                    if(index == -1){ return; }

                    newList[index] = oldList[i];
                });

                /*將新順序的陣列寫回 scope 變數*/
                expr.assign(scope, newList);

                /*通知 scope 有異動發生*/
                scope.$digest();
            }
        });

        /*在 destroy 時解除 Sortable*/
        scope.$on('$destroy', function(){
            element.sortable('destroy');
        });
    };
}]);
2014-05-08 02:56

[AngularJS] 製作 Mouse Drag Event directive

Html
<div ng-style="{'top': itemTop, 'left': itemLeft}"
    my-mousedrag="itemTop = itemTop - $deltaY; itemLeft = itemLeft - $deltaX"
></div>

JavaScript
app.directive('myMousedrag', function() {
    return function(scope, element, attrs) {
        var prevEvent;
        element.mousedown(function(event){
            prevEvent = event;

        }).mouseup(function(event){
            prevEvent = null;

        }).mousemove(function(event){
            if(!prevEvent){ return; }

            /*將 element 拖移事件傳遞到 scope 上*/
            scope.$eval(attrs['myMousedrag'], {
                $event: event,
                $deltaX: event.clientX - prevEvent.clientX,
                $deltaY: event.clientY - prevEvent.clientY
            });

            /*通知 scope 有異動發生*/
            scope.$digest();

            prevEvent = event;
        });

        /*在 destroy 時清除事件註冊*/
        scope.$on('$destroy', function(){
            element.off('mousedown mouseup mousemove');
        });
    };
});
2014-05-08 02:54

[AngularJS] 製作 jQuery MouseWheel directive

相依套件:jquery-mousewheel

Html
<div jq-mousewheel="changeSize($event, $delta, $deltaX, $deltaY)"></div>

JavaScript
app.directive('jqMousewheel', function(){
    return function(scope, element, attrs) {

        /*將 element 滾輪事件傳遞到 scope 上*/
        element.on('mousewheel', function (event) {
            scope.$eval(attrs['jqMousewheel'], {
                $event: event,
                $delta: event.delta,
                $deltaX: event.deltaX,
                $deltaY: event.deltaY
            });

            /*通知 scope 有異動發生*/
            scope.$digest();
        });

        /*在 destroy 時清除事件註冊*/
        scope.$on('$destroy', function(){
            element.off('mousewheel');
        });
    };
});
2014-05-08 02:52

[AngularJS] 製作 jQuery scrollTop scrollLeft directive

Html
<div jq-scroll-top="viewerScrollTop" 
      jq-scroll-left="viewerScrollLeft"
></div>

JavaScript
app.directive('jqScrollTop', ['$parse', function($parse){
    return function(scope, element, attrs) {
        /*解析並取得表達式*/
        var expr = $parse(attrs['jqScrollTop']);

        /*監聽變數異動,並更新到 element 上*/
        scope.$watch(attrs['jqScrollTop'], function(value) {
            element.scrollTop(value);
        });

        /*當 element 捲動時更新到變數上*/
        element.on('scroll', function() {
            expr.assign(scope, element.scrollTop());
        });

        /*在 destroy 時清除事件註冊*/
        scope.$on('$destroy', function(){
            element.off('scroll');
        });
    };
}]);

app.directive('jqScrollLeft', ['$parse', function($parse){
    return function(scope, element, attrs) {
        /*解析並取得表達式*/
        var expr = $parse(attrs['jqScrollLeft']);

        /*監聽變數異動,並更新到 element 上*/
        scope.$watch(attrs['jqScrollLeft'], function(value) {
            element.scrollLeft(value);
        });

        /*當 element 捲動時更新到變數上*/
        element.on('scroll', function() {
            expr.assign(scope, element.scrollLeft());
        });

        /*在 destroy 時清除事件註冊*/
        scope.$on('$destroy', function(){
            element.off('scroll');
        });
    };
}]);
2014-04-25 00:36

利用 Google Script 將 Blogger 備份到 Google Drive

在 Google Drive 中建立『指令碼』



然後選擇『空白專案』



貼上以下程式碼
/*
Ref:
https://developers.google.com/apps-script/reference/drive/drive-app
https://developers.google.com/apps-script/reference/drive/file
https://developers.google.com/apps-script/reference/drive/folder
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app
https://developers.google.com/apps-script/reference/url-fetch/o-auth-config
https://developers.google.com/apps-script/reference/base/blob
https://developers.google.com/apps-script/reference/utilities/utilities

*/

var _backupKeepAmount = 10;
var _backupFolderName = 'blogger_backup';
var _backupFolder;



function main(){
  var folders = DriveApp.getFoldersByName(_backupFolderName);

  if(folders.hasNext()){
    _backupFolder = folders.next();
  }else{
    _backupFolder = DriveApp.createFolder(_backupFolderName);
  }


  setAuth();

  backupBlogger('{my_blog_1}', '{blog_id}', false);
  backupBlogger('{my_blog_2}', '{blog_id}', false);

  MailApp.sendEmail(Session.getActiveUser().getEmail(), 'Backup Blogger To Google Drive', Logger.getLog());
}


/**
 * @param {String} prefixName 備份檔名的前綴
 * @param {String} blogId
 * @param {Boolean} isBigSize 如果備份的檔案超過 10M,請設為 true
 */
function backupBlogger(prefixName, blogId, isBigSize){
  logMsg('Backup Start', prefixName);


  /* 取得之前的備份清單 */
  var files = _backupFolder.getFilesByType('application/xml');
  var beforeFiles = [];
  while (files.hasNext()) {
    var file = files.next();
    if(file.getName().indexOf(prefixName) == -1){ continue; }

    beforeFiles.push(file);
  }

  beforeFiles.sort(function (a, b) {
    return b.getName().localeCompare(a.getName());
  });


  /* 下載並儲存檔案 */
  var isChange;
  if(isBigSize){
    isChange = downloadAndSaveBigSizeArchiveXml(prefixName, blogId, beforeFiles[0]);
  }else{
    isChange = downloadAndSaveArchiveXml(prefixName, blogId, beforeFiles[0]);
  }

  /*沒有異動結束處理*/
  if(!isChange){ return; }


  /* 刪除舊檔案 */
  var oleFiles = beforeFiles.slice(_backupKeepAmount);
  for(var i=0; i < oleFiles.length; i++){
    oleFiles[i].setTrashed(true);
  }


  logMsg('Backup Complete', prefixName);
}




function logMsg(status, msg){
  Logger.log('%s | %s', status, msg);
}



function setAuth(){
  var scope = "https://www.blogger.com/feeds/";
  var oAuthConfig = UrlFetchApp.addOAuthService("blogger");
  oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
  oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
  oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");

//  oAuthConfig.setConsumerKey("anonymous");
//  oAuthConfig.setConsumerSecret("anonymous");
}



function getArchiveXmlResponse(blogId){
  var options = {
      "oAuthServiceName" : "blogger",
      "oAuthUseToken" : "always"
  };

  var url = 'https://www.blogger.com/feeds/' + blogId + '/archive';
  var response = UrlFetchApp.fetch(url, options);

  /*下載失敗,錯誤記錄*/
  if(response.getResponseCode() != 200){
    logMsg('Download Failed', response.getAllHeaders().toSource());
    return null;
  }

  return response;
}


function downloadAndSaveArchiveXml(prefixName, blogId, beforeFile){
  var response = getArchiveXmlResponse(blogId);
  if(!response){ return false; }

  var downloadContent = response.getContentText();

  /* 檢查檔案異動 */
  if(beforeFile){
    var content = beforeFile.getBlob().getDataAsString();

    if(beforeFile && Math.abs(content.length -downloadContent.length) < 100){
      logMsg('Not Change', prefixName);
      return false;
    }
  }

  /* 儲存下載 */
  var fileName = Utilities.formatDate(new Date(), "+8", "yyyyMMdd_HHmmss'.xml'");
  _backupFolder.createFile(prefixName + '_' + fileName, downloadContent, 'application/xml');

  return true;
}



function downloadAndSaveBigSizeArchiveXml(prefixName, blogId, beforeFile){
  var response = getArchiveXmlResponse(blogId);
  if(!response){ return false; }


  /* 儲存下載 */
  var fileName = Utilities.formatDate(new Date(), "+8", "yyyyMMdd_HHmmss'.xml'");
  var downloadBlob = response.getBlob();
  downloadBlob.setName(prefixName + '_' + fileName);
  downloadBlob.setContentType('application/xml');
  var downloadFile = _backupFolder.createFile(downloadBlob);


  /* 檢查檔案異動 */
  if(beforeFile && Math.abs(beforeFile.getSize() - downloadFile.getSize() ) < 1000){
    downloadFile.setTrashed(true);
    logMsg('Not Change', prefixName);
    return false;
  }

  return true;
}


修改 {my_blog_1} 及 {blog_id},{my_blog_1} 是備份檔名的前綴,{blog_id} 則可以在文章管理的網址上找到



儲存檔案,並取名為『Backup Blogger To Google Drive』




先來測試一下備份是否能正常執行,請選擇執行的函數為『main』,並按下『執行』,然後先為此程式授權





如果都沒問題,接著來設定排程,選擇『啟動程序』



新增一個觸發程序



選擇執行的函數『main』,然後時間定在晚上 11 點,接著選擇『通知』



這個設定主要是發生錯誤的時候可以寄送通知

2014-03-09 17:47

理解 PredicateBuilder 實作方式

PredicateBuilder 提供了以 OR 串接 bool 的 Lambda Expression,使用上會像下面的程式:
var predicate = PredicateBuilder.False<Product>();

predicate = predicate.Or(p => p.Name == 'Shoe');
predicate = predicate.Or(p => p.Price > 100);


它的原始碼如下:
public static Expression<Func<T, bool>> Or<T> (
    this Expression<Func<T, bool>> expr1,
         Expression<Func<T, bool>> expr2
)
{
    var invokedExpr = Expression.Invoke (
        expr2, 
        expr1.Parameters.Cast<Expression>()
    );
 
    return Expression.Lambda<Func<T, bool>>(
        Expression.OrElse (expr1.Body, invokedExpr), 
        expr1.Parameters
    );
}


上面的程式雖然不長,但實在有點小難懂,搞不懂他為什麼要這麼寫??讓我們逐步解釋吧!


假設 expr1 是 x => x.Name == 'Shoe'
假設 expr2 是 y => y.Price > 100

var invokedExpr = Expression.Invoke(
    expr2, 
    expr1.Parameters.Cast<Expression>()
);
先組合出( 利用 expr1 的參數去執行 expr2 )的表示式 invokedExpr
產生出了語法會像 (y => y.Price > 100) (x)

Expression.OrElse(expr1.Body, invokedExpr)
將 expr1.Body 與 invokedExpr 以 || 運算子組合起來
產生出了語法會像 x.Name == 'Shoe' || (y => y.Price > 100) (x)

Expression.Lambda<Func<T, bool>>(
    Expression.OrElse(expr1.Body, invokedExpr), 
    expr1.Parameters
);
將剛剛組合好的 || 運算表示式再組合成 Lambda 表示式
產生出了語法會像 x => (x.Name == 'Shoe' || (y => y.Price > 100) (x))


參考來源:
Dynamically Composing Expression Predicates