Google Chrome のページ翻訳機能は [日本語のページ] を英語と判定する事がある

概要

Google Chrome 12 日本語版は仕様書リンク のページを [英語のページ] と判定して日本語に翻訳しようとする。

再現ソース

HTMLソース。

<!DOCTYPE html> 
<html lang="ja"> 
<head> 
  <meta charset="UTF-8" /> 
  <title>仕様書リンク</title> 

.htaccess

Header set Content-Language ja

HTTPレスポンスヘッダ。

Content-Language: ja

考察(というか愚痴)

HTMLやヘッダで指定した言語コードを全く信用していないのは何故なんでしょう…?

IE8- の Node#cloneNode はイベントまでコピーする

DOM2 規定の cloneNode()

DOM Level 2 Core で規定されている Node#cloneNode は「すべての属性と値をコピーします」が、参照は新しく形成されます。
つまり、<p onclick="alert('click');"> のようにHTMLに埋め込んであるイベントはコピーしますが、addEventListener 等で形成されたイベントはコピーしません。

<p id="Sample-1" onclick="alert('onclick attribute')">Click Me!</p>
<script type="text/javascript">
(function () {
  var p = document.getElementById('Sample-1');

  p.addEventListener('click', function () {
    alert('EventListener click');
  }, false);

  p = p.cloneNode(true); // クローンを生成する
  p.id = 'Sample-2';
  document.body.appendChild(p.cloneNode(true));
})();
</script>

IE8- の cloneNode()

IE8- の cloneNode() は attachEvent で形成されたイベントまでコピーします。(IE9で修正済みとの事)

<p id="Sample-1" onclick="alert('onclick attribute')">Click Me!</p>
<script type="text/javascript">
(function () {
  var p1 = document.getElementById('Sample-1');

  p1.attachEvent('onclick', function () {
    alert('attached click');
  });

  var p2 = p.cloneNode(true); // クローンを生成する
  p2.id = 'Sample-2';
  document.body.appendChild(p2.cloneNode(true));

  p1.style.color = 'red';
})();
</script>

IE の cloneNode は似て非なるもの - latest logではIE の cloneNode は参照をコピーするように説明されていますが、IE8 では参照をコピーしないようです。IE7- もしくは IE6- では参照をコピーするのかもしれません。

ECMAScript 5 の Strict Mode でグローバルオブジェクトを得る

Strict Mode

ECMAScript 5 には Strict Mode という仕組みがあり、Strict Mode では様々な機能(誤解の元となる機能、危険な機能)が制限されています。Strcit Mode になると関数コード内で this === undefined となり、this でグローバルオブジェクトを参照できません。

"use strict"; // Strict Mode を宣言する

(function () {
  // グローバルコードで Strict Mode を宣言すると下位の関数コードも Strict Mode になる
  console.log(this);   // undefined
  console.log(window); // [object Window]
})();

ブラウザの JavaScript では window がグローバルオブジェクトですが、Node.js では global がグローバルオブジェクトになります。実装依存をなくすためには this を利用したいところです。

Strict Mode でグローバルオブジェクトを得る

グローバルコードでは this がグローバルオブジェクトとなります。

"use strict";
console.log(this); // [object Window]

関数コードでは new Function() を利用します。

"use strict";

(function () {
  console.log(new Function('return this')()); // [object Window]
  console.log(Function('return this')());     // [object Window]
})();

実は ECMAScript 5 では "use strict"; が宣言されたとき、下位の 関数宣言(FunctionDeclaration), 関数式(FunctionExpression) も Strict Mode になると規定されており、new Function() はその影響下にないのです。

10.1.1 Strict Mode Code

...

  • Function code that is part of a FunctionDeclaration, FunctionExpression, or accessor PropertyAssignment is strict function code if its FunctionDeclaration, FunctionExpression, or PropertyAssignment is contained in strict mode code or if the function code begins with a Directive Prologue that contains a Use Strict Directive.
http://es5.github.com/#x10.1.1

そのため、new Function('return this') は Strict Mode にならず、this でグローバルオブジェクトを参照できます。

new Function() で Strict Mode にする

new Function() でも "use strict"; を宣言すれば Strict Mode になります。

new Function('"use strict"; return this;')(); // undefined

JSON.parse を利用できない実装でJSON文字列をパースする時など、どうしても new Function() が必要な場合に Strict Mode にすれば比較的安全にコードを評価できます。

CSS の簡略記述特性は指定しなかった特性を初期値で上書きする

簡略記述特性とは

複数の特性を一度に指定できるプロパティの性質を「簡易記述特性」と呼びます。

body {
  font: normal normal normal medium normal serif; /* font-style, font-variant, font-weight, font-size, line-height, font-family */
}
p {
  border: solid 1px red; /* border-style, border-width, border-color をまとめて指定する */
}

簡略記述特性で全ての特性を指定しなかった場合

簡略記述特性は一つ以上の特性を指定する必要があり、指定しなかった特性はそれぞれのプロパティの初期値で上書きされます。

<style type="text/css">
p {
  color: black;
  border: solid 1px red;
}
.sample1 {
  border-style: double;
}
.sample2 {
  border: double; /* border-width, border-color を省略する */
}
</style>
</head>
<body>
<p class="sample1">sample1</p><!-- "border: dotted 1px red"  -->
<p class="sample2">sample2</p><!-- "border: dotted medium black"  -->

境界特性プロパティの初期値
プロパティ名初期値
border-stylenone
border-widthmedium
border-color要素のcolor特性の値

.sample2 では border-width, border-color を省略したため、それぞれのプロパティ初期値で上書きされています。

結論

簡略記述特性で指定しなかったプロパティには何もしない と勘違いしていると思わぬ不具合を生むので注意する必要がありそうです。(私も勘違いしてました)

CSSStyleDeclaration#setProperty と CSSStyleDeclaration#removeProperty

概要

IE8 で未定義の CSSStyleDeclaration#setProperty, CSSStyleDeclaration#removeProperty を IE8 で使えるようにしてみようという試みです。

/**
 * インラインスタイルを定義する
 */
element.style.backgroundColor = '#fee';                    // CSSOM 規定
element.style.setProperty('background-color', '#fee', ''); // CSSOM 規定
element.style.setAttribute('backgroundColor', '#fee');     // IE8の独自実装

/**
 * 定義済みのインラインスタイルを削除する
 */
element.style.backgroundColor = '';               // CSSOM 規定
element.style.removeProperty('background-color'); // CSSOM 規定
element.style.removeAttribute('backgroundColor'); // IE8の独自実装

仕様

  • IE8 の setAttribute() には priority を入力する機構がないので element.cssText をパースして !important 規則を定義する方法を採用しました。cssText のパースは簡易的なものなので誤動作する可能性はあります。原理的には property:value; の value に Block が含まれなければ問題ないと思います。

IE8- は名前付き関数式を関数宣言としても扱う

ECMAScript の 名前付き関数式

ECMAScript には「名前付き関数式」があり、変数に関数式を代入するときに名前をつけることが出来ます。

var hoge = function foo () {
  alert(foo);          // function foo() { ... }
  alert(foo === hoge); // true
};

ここでは "foo" という名前の関数を作りました。関数fooの内部では foo で関数オブジェクトを参照できますが、関数fooの外部では参照できません。

// 関数宣言
function piyo () {
  alert(piyo);
}

// 名前付き関数式
var hoge = function foo () {
  alert(foo);
};

piyo(); // 実行できる
hoge(); // 実行できる
foo();  // ReferenceError: foo is not defined||<

IE8- の名前付き関数式

IE8- では名前付き関数式を関数宣言としても扱うバグがあります。(IE9 で修正済み)

foo();               // 実行できる
alert(foo === hoge); // false

var hoge = function foo () {
  alert(foo === hoge); // false
};

これは以下のコードとほぼ同じ動作です。

/**
 * 関数宣言
 */
function foo () {
  alert(foo === hoge); // false
}

/**
 * 関数式 (本来は名前をつけますが、IE8- と挙動を合わせるためにあえて匿名関数にしています)
 */
var hoge = function () {
  alert(foo === hoge); // false
};

foo();               // 実行できる
alert(foo === hoge); // false

hoge.toString() の結果が異なる点を除いて、IE8- と Google Chrome 11 で同じ結果を得られます。

  • 関数hogeの内部で foo を参照できるのは関数宣言fooを参照しているためです。
  • 関数宣言と関数式の代入は別々に行われるため、同じ関数オブジェクトが2つできてしまいます。
  • 関数宣言と関数式は別物であるため、hoge === foo とはなりません。

IE8- で本来の名前付き関数式の振る舞いにする

名前付き関数式の代わりに関数宣言を関数スコープに閉じこめてあげれば、本来の名前付き関数式とほぼ同じように振る舞います。

var hoge = (function () {
  function foo () {
    alert(foo);
  }

  return foo;
})();

Google 検索結果をハイライトする Proxomitron フィルタ「Google: High Light by js」

概要

Google検索結果で検索語を最大7つまでハイライトします。(要 JavaScript)

仕様

  • JavaScript を利用しているため、ブラウザの JavaScript を有効にしてください。
  • インスタント検索にも対応するため、HTML5 規定の hashchange イベントを利用しています。最近のブラウザは実装していますが、IE7- はサポートしていないようです。
  • 検索語は、半角スペース()|:*% 及び、接頭語の -+~ を除いた単語として解釈されます
  • フレーズ検索に対応しています。
  • 基本的なアルゴリズムは「Google: High Light」を元にしているので性質もほぼ同じです。