CSS

Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Backbone.js - MVC framework for front-end javascript

What is Backbone.js?


Backbone is a framework for front-end JavaScript, unlike jQuery focus on easier DOM manipulation and event binding, backbone provide a structure for separating data model and DOM, just like a MVC framework separate model, view and controller. Make heavy JavaScript application easier to develop and maintain.

Why Backbone?


In jQuery, we will write a sequence of chain selector for assign data model to DOM element like:

var article = {
  author:"Joe",
  content: "testing"
};
$('#article').click(function(event){
  $(this).find('.content').text(article.content);
});
For backbone, it provide the Model class and View class, which is the main two element of backbone.
var Article = Backbone.Model;

var article = new Article({
  author:"Joe",
  content: "testing"
});

var ArticleView = Backbone.View.extend({
  el: $('#article'),
  initialize: function(){
    _.bindAll(this,'updateContent');
    this.model.bind('change',this.updateContent);
  },
  events: {
    "click .content" : "updateContent"
  },
  updateContent: function(){
    this.$('.content').text(this.model.get("content"));
  }
});

var articleView = new ArticleView({model:article});
OK, it's seen like a completely overwork, that's my first thought when I see a clientside MVC framework too, but we have to dig further to understand why people create it.

Event Binding


First, it separate the data model and view - which include event handle and DOM element, we can easily bind data model in view like:
this.model.bind('change',this.updateContent);
It means when the data model change, the view will be automatically updated to DOM element.

Also, backbone provide literal event binding:
events:{
  "click .content": "updateContent"
}
which bind the "click" event to ".content" class, trigger "updateContent" function in current view.
It's useful when binding multiple events.

Restful synchronization


Furthermore, the backbone provide a RESTful format API for synchronize data model with server.
every model class in backbone have a corresponding url for synchronize, and when the "model.save" or "model.fetch" method is called, the model will make an Ajax request to update data with server.
For example:
article.save({author:"John"});
will first find article.sync method, if undefined, call Backbone.sync.
The sync method will make an ajax request to server, and update model, trigger event and update to view.

the url of model is defined by RESTful API:

  • create -> POST /model
  • read -> GET /model[/id]
  • update -> PUT /model/id
  • delete -> DELETE /model/id

and we can also change it by overwrite url parameter

Dependency


backbone.js depend on underscore.js and jQuery/Zepto library, since it is only a 3.9k framework focus on the structure of JavaScript application.

Collection and Controller

backbone provide Collection, which is the collection of Backbone.Model,
the Controller in backbone is more like the route map in MVC framework, it provide clientside fragment url routing, eg. "/#article/12" match "article(id)". So the url can be recorded and bookmarked by browser.

Template

In Backbone, we can create template in view.
In that way we can add and remove multiple view and render with template.
The underscore.js provide template engine or we can use other engine too.

In view:
render:function(){
    var template = "
<%=content %>
"; $(this.el).html( this.template(this.model.toJSON()) ); return this; }

Conclusion


JavaScript MVC framework is good for rich client application and also can keep your javascript cleaner.
But whether to use it depend on how much script in your application, for small page, the MVC is total overhead, but it is good for large scale page like Mail or Desktop like application.

More

Backbone
Sample todo application
Annotated source

HTML5 push state

Recently I was trying to make a slide pages effect, and I realize there are some obstacle to let the browser work properly on next/back page. because you can only change the #hash value of url but the real url without redirect, the old ajax problem.

But wait a minute, is the github use the ajax page slide effect and work perfectly? After a peek on the source, I found they are using the html5 pushstate api on webkit and ff4, which can let you change the url without actually redirect the page.

sample:
$(function(){
  //check if the browser support it.
  $.get('/new_page',function(data){
    if(history.pushState){
      //push the url to the browser history, with state object and title.
      history.pushState({isAjax:true},"push the state"), 'new_page');
    }
    //update the data...
  });
  //popstate event will triggered whenever the url changed
  //but the page won't reload if url is pushed into history
  //so you have to update page yourself or reload it.
  $(window).bind("popstate",function(e){
    if (e.state.isAjax) {
      //make the ajax call for update page
    }
  });
});

try it yourself by typing
history.pushState({},"test","/test:);
in your browser console, and you'll see the effect.

reference: https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history

F2E Interview Questions

Here are some interview questions from a front-end engineering job, through I didn't get that position , these questions are pretty interesting and might help the others who want to get a Front-end job. So here are the questions:

1.Weird Width:

I create this <div/> to have my article inside. However, my nit picking product manager finds the width of this block is a little different between Internet Explorer 6 and Firefox. Can you help me to fix this weird bug?
In Internet Explorer, the width is 500px.
In Firefox 3, the width is 522px.
Can you help to correct my attached file so that the page is identical in different browsers? It would be great if you can tell me why so that I won't do that stupid thing again. And if you have spare time, please style the page for me since I am so lazy. ^^』』


Ans:

First of all, the problem of weird width is because older IE browser has different explanation in CSS box model.

The IE explained CSS width attribute as the width of content + padding + border. As the result, we get the width of 500px in IE browser that includes padding and border, in contrast of 522px in other modern browser.

Internet explorer 6+ has two mode of CSS interpretation:
Quirk mode – the interpretation of IE's own standard
standard-compliant mode – according the W3C standard (almost)
By define the <!DOCTYPE> tag we can switch the IE to standard-compliant mode. So here's the solution:
<!DOCTYPE>
By attach this before <html> tag, we can get correct width


2.Horizontal Toolbar

Product manager asks me to make a horizontal toolbar for our website.
Even if user scrolls, toolbar will always stay at the bottom of page. Another requirement is that all modern browsers are compatible with this new feature. (Internet Explorer 6 - 8, Firefox, Opera, Google Chrome, and Safari) After making a prototype I find it's really difficult. Please teach me how to do that.


Ans:

The CSS { position: fixed } attribute can build the toolbar in same position whenever scrolling. So the solution is:
#toolbar { position: fixed ; bottom:0; width:100%; }
Unfortunately, our old IE6 friend doesn't support it.
Again, search for some hack at web, we found 2 approaches:
1. JavaScript approach: which auto re-assigns position when event called.
2. CSS approach:
Using CSS expression or, Using wrapper
I use wrapper method because it's the simplest to me.



Normally, the { position:absolute } attribute will anchor the element according root element. Therefore we can set another element outside to be the root and have height equal to the screen. So the { position:absolute } attribute can place toolbar in right position. And by set the {overflow:hidden} attribute, we can hide the content outside the root element.
When assign css attribute, IE will active the element. So we can active the <html> element to be the wrapper, <body> to be the content,
CSS example:

#toolbar {position: fixed; bottom: 0; width: 100%;}
//css for ie6
* html{ overflow-y: hidden; } //hide the wrapper scroll
* html body{
  padding:0px;margin:0px; // reset
  overflow-y: auto; //set scroll
  height: 100%;
}
* html div#toolbar
{
  position: absolute;
  width:98%; //fix the problem that toolbar over scroll
}


Show me the Browser

Dear Candidate,
We front-end engineers are always busy at switching between browsers. Each engineer has three browsers installed on their notebook. They are Internet Explorer 6, Internet Explorer 7, and Firefox 3. It's really confusing to identify which browser is using. As an engineer with some repute, you want facilitate others by showing icon.

Ans:


1. we need to set CSS sprite for browser picture
I try to build CSS class with background-position attribute:
.firefox{ background-position:0 0 }
.ie7{ background-position:0 -75px }
.ie6{ background-position:0 -150px}
2. JavaScript to detect browser and parse userAgent string and replace picture for right browser.
using library from here: http://www.quirksmode.org/js/detect.html

window.onload = function(){
  // get the DOM object by ID
  var browserPic = document.getElementById("browsers");
  //detect browser and set correct class
  if(BrowserDetect.browser == "Firefox"){
    browserPic.className = "firefox";
  }
  if(BrowserDetect.browser == "Explorer"){
    if(BrowserDetect.version == "6")
      browserPic.className = "ie6";
    if(BrowserDetect.version == "7")
      browserPic.className = "ie7";
  }
};
(but it turn outs that using css hack * for ie6, _ for firefox is a far more simpler solution)

[.Note]jquery動態調整欄寬&限制checkbox選取

幾個專案上遇到的小需求,
皆用JQuery來解決,在這裡記錄一下解法

1.動態調整欄寬 :


有一個table,他的第一個欄位長度是固定的,後面的欄位要有相等的寬度,
但是後面的欄位數目是動態產生,欄位的名稱長度也不固定,如果欄位過長則必須要換行

一開始是用%數的方法來指定欄寬長度,但是這個方法並不能夠有效的在所有瀏覽器上運行
後來使用jquery來動態調整欄寬 : 先等table產生,再計算出後面欄位的平均寬度,並將儲存格寬度調整為平均寬度:

$('.sort').each(function() {
    var sum = 0;
    //取得所有要調整的欄寬
    var cells = $(this).find('.sort-item');
    //統計總寬度
    cells.each(function() {
        sum += $(this).width();
    });
    //設定平均欄寬 
    var cellWidth = sum / cells.length;
    cells.each(function() {
        $(this).width(cellWidth);
    });
});

2.限制checkbox選取


有一個多選的CheckboxList,需要限制最大的選取數量
如果超過則不能選擇:

//傳入CheckboxList Container的ID
bindMultiSelectLimit = function(id,limit) {
    $('#' + id + ' input:checkbox').click(function() {
        //使用Jquery selector直接找出所有已選之Checkbox
        if ($('#' + id + ' input:checked').length > limit) {
            return false;
        }
    });
};

3.限制排序問題重覆選取


有一個問卷題型叫排序題,結構上是由許多RadioButtonGroup所構成,
讓使用者能排列喜好選項的順序 : (ex, 有三個選項, 可以選擇 3,2,1 或 1,2,3的排序 )
但使用者希望能夠有防呆機制,讓已經於其他選項選過的排序不能再選第二次
(ex:三個選項的排序可為 1,2,3. 3,2,1 . 但不可為 2,2,1 )
後來選擇了一個比較簡單的作法:當排序被選取時,清空其他有同樣排序值的RadioButton

//傳入ContainerID
bindSortRules = function(id) {
    $('#' + id + ' input').click(function() {
    //設定每個排序RadioButton有同樣的value,將其他有相同value的值都設為false
    $('#' + id + ' input[value=' + $(this).val() + ']').attr('checked', false);
        //設定目前選擇的值
        $(this).attr('checked', true);
    });
}

以上的需求如果使用Javascript不知道要做多久...
所以說JQuery真的是能夠有效增加前端生產力的一個好框架啊,
只要有用到Web的開發者真的都需要接觸一下

[.Note] 10 Things I Learned from JQuery Source (or more then 10?)


10 Things I Learned From The JQuery Source
From Paul Irish

一篇很棒的演講,由專家帶領我們從JQuery的原始碼中學習一些JQuery所用的JavaScript Pattern以及設計方式.

自從在OSDC2010上聽了Gugod的Less is More,JQuery這個框架的簡潔性以及設計的原則就一直吸引著我.
這個演講剛好讓我以後在用JQuery的時候能更輕易的去看source.

以下是筆記:

1.JQuery的Convention之一: Closure Pattern:
(function(){ ... })();

!function(){ ... }()

後面的括號代表這是self executing function: run itself immediately

favorite pattern:
(function(window,document,undefined){
    ....
})(this,document)

把window,document當成變數傳入closure,這樣的好處是:
1.如果有其他全域變數例如 undefined = true; // break all undifined comparison
而closure避免了這些干擾
2.minification:
最佳化後會變成: function(A,B,C){}(this,document), 可以省下一些字元

2. async recursion

Self repeating: 會不斷的執行,不論前一項有沒有執行完,
例如
setInterval(function(){ 
   doStuff();
},100) // is very evil

而self executing function能確保執行到尾巴之後才會執行第二遍
(function loops(){
    doStuff();
    $('#update').load('awesomething.php',function(){
        loops();
    })
    setTimeout(loops,100);
})()

3.如何找到函式: 找 function name + : , ex: "noConflict:"

4.Jquery.noConflict:
在開始時將 原本的 $ 儲存為 _$, 並在呼叫noConflict時復原.

5.jQuery.props
小型的參數字典,自動將Html與Dom Api上一些相同意思但名稱不同的參數作對應
讓開發者不需要記得所有的東西.
也可以用在.attr:
ex: WAI ARIA
$(elem).attr('aria-disabledby','asdasdasd');

$.props['adb'] = 'aria-disabledby';
=>
$(elem).attr('adb') = 'asdasdasd';

6. fadeIn() : defined your own speeds:
JQuery內部的 speed 定義了各種速度:
speeds: {slow:800 ,fast:200 ,_default:800}
可以由外部加入自訂的速度
jQuery.fx.speeds.fastopen= ($.browser.msie && $.browser.version < 8 ) ? 800 : 400;
//在IE7以下速度為800,其他瀏覽器為400

$('#stuff').fadeIn('fastopen');
7.JQuery.ready(...) 會檢查DOM準備好沒,在準備完畢時執行function,

bindReady(); // IEContentLoad: solve by great Italian hacker,

using doScroll check to check if DOM ready in IE :

doScroll(left); //will raise exception if DOM not ready.

8.getJSON : shorthand methods:

jQuery ajax() holds anything, but get,post,getJSON,getScript shorten the varible.

9.selector performence.
$('#id') vs $('#id tag.thing')
$('#id tag.thing') will self parse to => $('#id').find('tag.thing');
$('#id').find('tag.thing')
$(':password') === $('*:password') 
so better provide tagname ex: $('input:password');

10.getJSON: function protect 會用regex檢查資料是否為JSON,如果是的話就pass,
不是的話會呼叫 (new Function("return" + data))();
這叫Function constructor: 回傳
function(){return data;}
=== eval('('+data')');
但是避開使用邪惡的eval 

11 $.unique(err) : duck punch
$.unique能夠過濾相同的DOM元素,讓陣列只有unique的元素
但不對應基本物件 使用duck punch來擴充unique方法:
(function($){

    _old = $.unique()

    if(!!arr[0].nodeType){
        return _old.apply(this,arguments);
    } else {
        return $.grep(arr,function(v,k){
            return $.inArray(v,arr) === k
        });
    }
})(jQuery);

12.quene: $(elem).fadeIn().delay(1000).fadeOut(); 可以使用quene方法改寫成
$(elem).quene(function(){
        $(elem).delay(1000).fadeOut();
});

13.$.support
support使用一個HTML div,內部包含table,/a等等各項元素,
support會檢查瀏覽器能不能辨識其中的元素,來做瀏覽器的相容性檢查

14.bit.ly/jqsource : 一起來看JQuery Source

[Syntax highlighter & Prettify] 如何在網誌中加入語法高亮效果?

最近想要給之前貼的code加入一些語法高亮效果,讓code看起來比較清楚,
就survey了兩套javascript library,心得與安裝方法如下:

1.google code prettify


如何安裝?


1.加入javascript與css到網頁上:
<script type="text/javascript 
src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script>
<link type="text/css" 
href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css"></link>
*host on google code,未壓縮(57KB) 有網頁空間的可以自己下載來用
*http://jsgears.googlecode.com/svn/trunk/prettify.min/ 這裡有壓縮版(16KB)的檔案可以引用

2.於讀取網頁時執行語法高亮函式:

<body onload="prettyPrint">

如果與其他設定重複了可加入Event Handler:
<script type="text/javascript">
    if(window.addEventListener){
        addEventListener('load',function(){prettyPrint();},false);
    }else{
        attachEvent('onload',function(){prettyPrint();});
    }
</script>

3.於想要加強語法效果處加入class="prettyprint":
<pre class="prettyprint">
並可設定想加強的語法關鍵字:
<pre class="prettyprint lang-js">


2.Syntax Highlighter


如何安裝?


1.加入基本的javascript與css設定:
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' 
rel='stylesheet' type='text/css'/> 
    <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js'
 type='text/javascript'></script> 
*hosting on amazon s3,shCore.js為壓縮版(21K)

2.加入要使用的語法以及css主題:
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'></script> 
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'></script> 
主題預覽可以看這個網頁:http://blog.cartercole.com/2009/10/awesome-syntax-highlighting-made-easy.html

3.執行Syntax Highlighter:
在blogger要多設定bloggerMode= true;
還有為了執行剪貼簿功能要多load一個clipboard.swf,因為javascript不能存取剪貼簿
updated:最新的版本取消了這個功能,現在只要double click就可以選取全文
<script type='text/javascript'>
    SyntaxHighlighter.config.bloggerMode = true;
    SyntaxHighlighter.all();
</script>

4.於想要加強語法效果處加入class="brush: [語法]":

<pre class="brush:js;"


可設定無行號的light模式:
<pre class="brush:js;light:true;">

可指定行號加入強調效果:
<pre class="brush:js;highlight:[1];">

比較:


大小:兩者差不多,syntax highlighter要讀取比較多的語法檔與css主題,而prettify比較簡單
但syntax highlighter有官方的壓縮檔host

效果:syntax highlighter效果比較好,有行號,高亮,還有各種不同主題與剪貼簿功能 

對應語言:各有長處,但syntax highlighter的語法檔比較好懂

不過最後我發現prettify在ie7會有把多行擠成一行的bug,
所以決定用Syntax Highlighter了 :)

updated:最新的3.0版讓版面變得有點討厭...不會自動換行,現在正在修改中...

[JQuery] 如何判斷元素是否存在

最近遇到了一個bug,
是因為jQuery沒有將事件綁定到指定的物件上所產生的

所以加上了檢查Html元素是否存在的邏輯:

if($("#obj") != null){...}

可是結果還是一樣,括弧內的邏輯一定會執行到.

打開debugger檢查之後,發現Jquery使用了Null Object
就是即使找不到元素,JQuery還是會回傳一個空的JQuery物件.
讓對物件的操作不會因為null reference而產生錯誤.

但是Null Object的缺點就是,如果其他程式設計師不知道使用了Null Object,
就會寫出錯誤的檢查...像我一樣.

所以這裡應該檢查元素的length屬性,如果是空值的話就會傳回0:

if($("#obj").length > 0){...}

由於javascript的boolean判斷會將0判斷成false,1以上的值判斷成true,
所以也可以這樣寫:

if($("#obj").length){...}

參考文章:http://www.aaronrussell.co.uk/blog/check-if-an-element-exists-using-jquery/


同場加映:

於內嵌的PDF IFrame讀取時使用jquery.blockUI:

$(function() {  
    var iframe = $("#PDFiframe");
    if(iframe.length){
        //ie在綁定Iframe事件的時候會產生錯誤,必須要用windows.frames[]來取得iframe
        //另外如果直接用jquery接frames物件的話,於判斷length時一定會傳回true...
        if($.browser.msie){
            iframe = $(frames["PDFiframe"]); 
        }
        $.blockUI();
        iframe.load(function() { $.unblockUI(); });
    }
});