Chapter 9. Form Elements and Validation
2010/09/02(木) 18:29 Javascriptはてブ情報 はてブに登録 はてブ数

9.0 Introduction

form要素はユーザーとデベロッパーを繋ぐものである。
Javascriptはform要素を改変することもできるが、JavaScriptは要素に取って代わるわけではなくそれらを高めるために使うべきだ。JavaScript enhances, not replaces.
JavaScriptをOFFにしてブラウジングしている人もいる。

これでできる! クロスブラウザJavaScript入門:第13回 簡単なアプリケーションの作成|gihyo.jp … 技術評論社
これのsubmit要素にイベントを付けることで、JavaScriptオフでも通常のsubmitで検索ができるような感じでJavaScriptオフでも使えるようにしておくべき。

9.1 Accessing Form Text Input Values

inputのvalueを取得。
var formValue = document.forms["formname"].elements["elementname"].value;
documentオブジェクトはformオブジェクトのコレクションを持っているので、上のようにnameを使ってアクセスできる。
普通にidを振ってアクセスするのもあり。
var txtValue = document.getElementByid("pattern").value;

9.2 Dynamically Disabling and Enabling Form Elements

form要素はdisabledプロパティを持っていてtrue,falseの指定ができる。

9.3  Getting Information from a Form Element Based on an Event

form要素にはイベントを付けて、そのイベント時に要素見て処理を行う。
使えるイベントの要素ごと一覧。
ElementsEvents
button, submitclick, keypress, focus, blur
checkboxclick, keypress
radiobuttonclick, keypress
textareaselect, change, focus, blur, click, keypress, mousedown, mouseup, keydown, keyup
password, textchange, focus, blur, keypress, select
selectionchange, focus, blur
filechange, focus, blur
他のイベントと同じく DOM Level 0のon*でも使える。

9.4  Performing an Action When a Radio Button Is Clicked

ラジオボタンの例
選択肢のoneを選択した場合はline_textを無効にする。
window.onload=function() {
  var radios = document.forms[0].elements["group1"];
  for (var i = 0; i < radios.length; i++)
    radios[i].onclick=radioClicked;
}
function RadioClicked() {
    if (this.value == "one") {
      document.forms[0].elements["line_text"].disabled=true;
   }
}
これだと複数あったときの関係がわかりにくいので、下記みたいにswitchで分けると見やすくなる
function radioClicked() {
  // find out which radio button was clicked and
  // disable/enable appropriate input elements
  switch(this.value) {
    case "one" :
       document.forms[0].elements["intext"].disabled=false;
       document.forms[0].elements["intext2"].disabled=true;
       document.forms[0].elements["intext3"].disabled=true;
       break;
    case "two" :
       document.forms[0].elements["intext2"].disabled=false;
       document.forms[0].elements["intext"].disabled=true;
       document.forms[0].elements["intext3"].disabled=true;
       break;
    case "three" :
       document.forms[0].elements["intext3"].disabled=false;
       document.forms[0].elements["intext"].disabled=true;
       document.forms[0].elements["intext2"].disabled=true;
       break;
  }
}

9.6  Canceling a Form Submission

submitをキャンセルする。
以前でてきたcancelイベントを使う。
formのsubmitにキャンセルするかを判断するイベントリスナーを登録して、値が変だったらキャンセルする。
// listen to an event
function listenEvent(eventObj, event, eventHandler) {
   if (eventObj.addEventListener) {
      eventObj.addEventListener(event, eventHandler,false);
   } else if (eventObj.attachEvent) {
      event = "on" + event;
      eventObj.attachEvent(event, eventHandler);
   } else {
      eventObj["on" + event] = eventHandler;
   }
}
// cancel event
function  cancelEvent (event) {
   if (event.preventDefault) {
      event.preventDefault();
   } else {
      event.returnValue = false;
   }
}
window.onload=function() {// イベントを付ける
   var form = document.forms["picker"];
   listenEvent(form,"submit",validateFields);
}
function validateFields(evt) {
   evt = evt ? evt : window.event;
   //... 処理
   if (invalid) {// 結果がおかしかったらキャンセル
      cancelEvent(evt);
   }
}

9.7  Preventing Duplicate Form Submissions

何かふるーいソースで見かけるような感じがする重複送信の防止。
フォームの重複送信はUIで最悪な問題だ。課金のボタンなど実害の問題になることもあり得る。
この重複問題は場合によってどのくらいstrictにするべきかを考える。
  • コメント欄
重複送信が実際に起きてもちょっとしたノイズになるくらいなので、軽く判定するだけでいい。
  • 購入ボタン
これは重複や予想外のsubmitが起きると問題になるため、厳密に判定する必要がある。
  • カスタマーフィードバックの送信
何か問題が起きたときにユーザーに送ってもらうフィードバック送信ボタンの場合。
ユーザーはちゃんとフィードバックが送信できたか心配になるので、alertなど大げさに送信した事を伝えて、再度クリックできないように送信ボタンをdisabledにするなどの工夫がいる。

disabledにしっぱなしなのは明らかに動作がおかしいときに困るので、戻すボタンが一緒にあるといい。

9.9  Modifying a Selection List Based on Other Form Decisions

リストで選択したら次の選択肢がでるようなパターン。
IEではselect.addの第2引数をサポートしてないので、try..catchしてるとか。
      try {
        city.add(opt,null);
      } catch(e) {
        city.add(opt);
      }
内容的にはかなり優しいものが多いけど、WebサイトとしてこうあるべきだってJavaScriptの機能以外についても触れている。

第1部 Web概論
2010/08/30(月) 24:21 Webはてブ情報 はてブに登録 はてブ数

  1. Web APIはAPIを使ったインターフェイス
  2. Webサービスは提供してるサービスサイトを指す

2.6 Web APIをめぐる議論

SOAP VS RESTが起きて、AmazonによってRESTみたいなものが注目された。
SOAPとWS*は複雑過ぎて仕様がばらばらになっていた、逆にRESTは扱いやすく簡易だったので普及。

3.1 アーキテクチャスタイルの重要性

RESTはWebのアーキテクチャスタイル。
同類にMVCやイベントシステムやクライアント/サーバがある。
抽象化のレベルWebでの例
アーキテクチャスタイルREST
アーキテクチャブラウザ、サーバ、HTTP、HTML
実装Apache ,Firefox
アーキテクチャスタイルは抽象度高め。

3.3 リソース

* リソースの名前としてのURI
リソースは名前(=URL)を持っている。
URLは一意なものなのでプログラムはリソースへアクセスできる。
* リソースのアドレス可能性
* 複数のURIを持つリソース
リソースは複数の名前を持てる。
* リソースの表現と状態
サーバクライアントのやりとり(リソースの表現)によってリソースは変化することがある。

3.4 スタイルを組み合わせてRESTを構成する

コードオンデマンドはjsやFlashのようにダウンロードしてクライアント側で実行すること。
クライアントを後から拡張できるのが利点だが、プロトコルの可視性は低下する。

RESTはクライアントサーバでサーバ側がアプリケーションの状態(クッキーのような)ものを持たないステートレスサーバであり、キャッシュのアーキテクチャスタイルを持ち、統一的なインターフェイスでシステムを階層化していて、コードオンデマンドなものを組み合わせたアーキテクチャスタイル。

3.5 RESTの2つの側面

RESTはリソースをリンクで接続することで一つのアプリケーションを構築するという間が方が基幹にある。(=接続性)

Chapter 8. Browser Pieces
2010/08/30(月) 18:06 Javascriptはてブ情報 はてブに登録 はてブ数

8.0 Introduction

window, navigator, screen, history, and locationなどのBrowser Object Model (BOM)についての話。

8.2  Creating a New, Stripped-Down Browser Window

window.open("http://oreilly.com", "namedWindow");について。
引数なしだとabout;blankと_blankが入る。
HTML5では第4引数にreplaceが加わっている。
window . open

8.3  Finding Out About the Browser Accessing the Page

Navigator objectはmimeTypesやpluginsなどもとれたりするよ。

8.5  Changing Stylesheets Depending on Color Support

カラー深度とかとれるのかー
if (window.screen.colorDepth <= 8) {
   var style = document.documentElement.style ?
document.documentElement.style : document.body.style;
   style.backgroundColor="#ffffff";
}

8.6  Modifying Image Dimensions Depending on Page Size

また本題と関係ないけど、window.screen.availWidthでスクリーンサイズが取得できる。

8.7  Creating Breadcrumbs in a CMS Template Page

window.locationのプロパティ
window.locationのプロパティ
PropertyDescriptionExample
hashPart of URL following #, including the ##mysection
hostHostname and optional portburningbird.net or [burningbird.net]:80
hostnameHostnameburningbird.net
hrefFull URLhttp://burningbird.net/jscb#test
pathnameRelative path name/jscb#test
portPort number80
protocolURL protocolhttp:
searchPart of the URL following ?, including ??q=username
URLを分割していけば、パンくずリストみたいなものが作れる。
  // split relative path
  var items = location.pathname.substr(1).split("/");
  // build main path
  var mainpath = "<a href='" + location.protocol + "//" +
   location.hostname + "/";
  // begin breadcrumb
  var breadcrumbTrail = "<p>";
  for (var i = 0; i < items.length; i++) {
    // trailing slash
    if (items[i].length == 0 ) break;
    // extend main path for new level
    mainpath+=items[i];
    // add slash after all but last item
    if (i < items.length-1)
      mainpath+="/";
    // create breadcrumb component
    // add arrows for interior items only
    if (i > 0 && i < items.length)
      breadcrumbTrail+=" -> ";
    // add crumb
    breadcrumbTrail+= mainpath + "'>" + items[i] + "</a>";
  }
  // insert into page
  breadcrumbTrail+="</p>";
console.log(breadcrumbTrail);

8.9  Preserving State for Back Button, Page Refresh

fragment (#somevalue)についての話。
Ajaxでページを変更する際にタイマーを回して#フラグメント、ハッシュを変更する事で状態の変更が記憶され戻るボタンで一つ前に戻ることができる。
このAjaxのための戻るボタン代替のために#フラグメントを使うのはあまり好ましいものではないと考える。フラグメントは間違ってリロードした際やブックマークのリンクのためにあると考えるから。

そのうち HTML5 history objectを使ったものが主流になるはず。

Chapter 7. Handling Events
2010/08/28(土) 24:48 Javascriptはてブ情報 はてブに登録 はてブ数

第7章

7.0  Introduction

Some Common Eventsでsubmit and resetとでてきた。確かにそうかーって感じがした。
scroll eventってのもあるのか。
  • Event History and New Event Handling
onclick="clickFunction()" みたいなHTMLにかくやつやwindow.onload=someFunction;などはDOM 0。
addEventListenerはDOM Level 2のイベントの付け方。
  • New Events, New Uses
DOMNodeInserted and DOMNodeRemoved events など新しいイベントもあるがIEはまだ。
(IE9はどうだっけ)
これ以外にもMozzilaはmouse gesture eventsなど携帯デバイス向けの独自イベントなどを定義していたりします。これはまた後半の章で。

7.1 Detecting When the Page Has Finished Loading

window loadイベントを使ってDOM構築をキャッチしてからでないとDOMに触ることができない場合もあります。
なので、window.onloadを使ってやるのがベターです。
同じように<body onload="functionName()">みたくタグに書いても動作しますが、発見や変更がしにくいのでできるだけやめましょう。

7.2 Capturing the Location of a Mouse Click Event Using the Event Object

マウスクリックがどこで起きたかを取得する。
(普通はaddEventみたいなものを使うべきだけど、スペースの都合で省いてそう)
位置判定はクロスブラウザ向けに書かれている。
document.onclick=processClick;// addEvent
function processClick(evt) {
   // access event object
   evt = evt || window.event;// other || IE
   var x = 0; var y = 0;
   // if event object has pageX property
   // get position using pageX, pageY
   if (evt.pageX) {
      x = evt.pageX;
      y = evt.pageY;
    // else if event has clientX property
   } else if (evt.clientX) {
      var offsetX = 0; offsetY = 0;
       // if documentElement.scrollLeft supported
      if (document.documentElement.scrollLeft) {
          offsetX = document.documentElement.scrollLeft;
          offsetY = document.documentElement.scrollTop;
      } else if (document.body) {
          offsetX = document.body.scrollLeft;
          offsetY = document.body.scrollTop;
      }
      x = evt.clientX + offsetX;
      y = evt.clientY + offsetY;
    }
alert ("you clicked at x=" + x + " y=" + y);
}
IE8以下はeventにアクセスするために window.event と経由しないといけない。
座標を取り出すために、IE以外はpageX and pageYを使うことでできる。
IEは clientX and clientYとscroll*を足して取得する。

7.3 Creating a Generic, Reusable Event Handler Function

DOM Level 2でcross-browser friendlyな event handlingを書きましょう。
まあこの辺はいろんなところで見かけるので…
// add
function listenEvent(eventTarget, eventType, eventHandler) {
   if (eventTarget.addEventListener) {
      eventTarget.addEventListener(eventType, eventHandler,false);
   } else if (eventTarget.attachEvent) {
      eventType = "on" + eventType;
      eventTarget.attachEvent(eventType, eventHandler);
   } else {
      eventTarget["on" + eventType] = eventHandler;
   }
}
// remove
function stopListening (eventTarget,eventType,eventHandler) {
   if (eventTarget.removeEventListener) {
      eventTarget.removeEventListener(eventType,eventHandler,false);
   } else if (eventTarget.detachEvent) {
      eventType = "on" + eventType;
      eventTarget.detachEvent(eventType,eventHandler);
   } else {
      eventTarget["on" + eventType] = null;
   }
}
IE9でやっと DOM Level 2 event が入りました。

7.4 Canceling an Event Based on Changed Circumstance

イベントを途中でキャンセルする方法。
処理中のイベントが完了する前にキャンセルするためには preventDefaultを呼んでキャンセルします。(タグに直接書く場合だとreturn false;みたいな感じにやるが上と同じ理由で普通はこっちを使うべき)
// cancel event
function  cancelEvent (event) {
   event = event || window.event;
   if (event.preventDefault) {
      event.preventDefault();
   } else {// DOM 0 -IE
      event.returnValue = false;
   }
}
ただし、これは(preventDefault)はDOMを通じたイベントのさらなる伝播(propagation)を止めません。
なので、場合によってはイベントが止まってないように見えてしまいます。イベントの伝播(propagation)を止めるにはstopPropagationを使用します。

7.5 Preventing an Event from Propagating Through a Set of Nested Elements

入れ子になっている要素へのイベントの伝播(propagation)を止める。
//  stop event propagation
function  cancelPropagation (event) {
   if (event.stopPropagation) {
       event.stopPropagation();
   } else {
      event.cancelBubble = true;
   }
}
IEはバブリングとなっているように伝播の仕方が違うのもやっかい。

7.6 Capturing Keyboard Activity

textareaで入力したときのキーボードイベントをキャプチャー。
keyイベントをあげてみると
  • keydown
  • keyup
  • keypress
  • textInput - Follows keypress (Safari only).
keypress and keydownは似ているが反応するキーに違いがある。
keydownは何かのキーが押されたら反応する。
keypressは何か文字が入力されたら反応する。(入力が起きないカーソルなどは無反応)
keypressはASCII valueのキーが押されたら反応するイベントハンドラだが、そのASCII valueを取得する方法はブラウザで違いがある。
Safari, Firefox, and Chromeは charCode.
IE and Operaは keyCode.
(ブラウザ周りで違いが多くて大変なとこ)

7.7 Using the New HTML5 Drag-and-Drop

HTML5のD&D機能について。
シンプルなD&Dのサンプル
なぜか-khtml-user-dragで-khtmlというプレフィックスが使われていますが、-webkitにした方がよいです。
ここはとても読みにくいです…(D&Dの仕様のせいでもある)

まずはドラッグ可能な要素は draggable属性をtrueにする必要があります。
safariだとCSSでドラッグ可能かの設定ができて、
  • webkit-user-drag:element;でセレクタで指定した要素をドラッグ可能にします。
デフォルト(-webkit-user-drag:auto)でドラッグ可能なのがimages, links, and textなため、要素は指定しないとドラッグ可能になりません。
  • webkit-user-drag:none;でドラッグできなくなります。
この方法はWebkit系のブラウザしか使えないと思うので、setAttributeを使って属性を設定。
item.setAttribute("draggable","true");
同じように、HTMLタグにdraggable="true"しても適応できる。
dragover - 何かしらのtargetに乗ったときに反応。ユーザーへのfeedbackに使う
dragenter - targetに乗ったときに反応。ここでtargetを受け入れるかを決める。
キャンセルすることで受け入れるという直感に反する仕様。
を交えた著者のD&Dに対する意見・方針的なもの。(この辺すごくブログっぽい感じになってた)

D&Dのところだけすごく浮いていた内容だった。