JavaScriptが使えるePubリーダーならシンタックスハイライトも楽

epub3ではJavaScriptが使えます。コードのシンタックスハイライトをしたいなーって思ったら、いつもWebでやっているようにそういうライブラリをちょちょいと読みこめばいいだけです。

google-code-prettifyを使用した例:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<title>epub-test</title>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="prettify.css" />
<script src="prettify.js"></script>
</head>
<body onload="prettyPrint()">
<section id="0">
<h1>hoge</h1>
<pre class="prettyprint lang-js">function hoge() {
return 'hoge';
}</pre>
</section>
</body>
</html>

めちゃくちゃ簡単ですね。こんなに簡単なんですからepub3で出版される技術書はどれもこれも綺麗にシンタックスハイライトされてることでしょう。

epubのサンプル:
epub-test.epub
posted by 右京 | javascript

Firefox 15でDataViewがサポートされる他

Firefox 15でようやくDataViewがサポートされる。これで主要なブラウザがDataViewをサポートしたことになるので、DataViewのpolyfillはもういらなくなる。ただし、DataViewって使ってると結構機能が足りないなーって思うんだよね。例えばバイナリファイルのシグニチャを取得するときとかわかりやすく文字列で取得したいなとか、24bitの数値を読み書きしたいなとか思うんだけど、これがないんだよ。仕様に入れてくれよ(ffDataViewではそういう不満も解消できるようになっているので使ってみてね)。

あと、Typed Arrays関係だとBlobコンストラクタがArrayBufferViewを受け取るようになった(File APIの仕様が変わったらしい)。実はchromeもこの仕様通りに動作するようになったはけっこう最近で、その前まではArrayBufferViewを渡そうものなら暗黙的にObject.prototype.toStringしやがってた(これは最悪)。あと、ArrayBufferViewのbufferがbyteLengthと一致しない場合にかなりミスりやすかった(のでblob生成が前提なプログラムはヘタにUint8Arrayとか返せなくなる)のはちょっとなーとか思ってた(エラー出ないからうざい)。今の仕様は最高だね。ただし、ArrayBufferは今後非推奨になるので、ぼちぼち修正する必要はあるかな。
posted by 右京 | javascript

jsziptoolsのカスタムビルド

使いたいモジュールだけを選べるようになりました。詳しいことはhttps://github.com/ukyo/jsziptools#custom-buildに書いてあります。

オプションを色々指定すると色々できます。

cd path/to/jsziptools/
# -C Closure Compilerのパスを指定
# -m 使用するモジュールを指定
# -o 出力先のパスを指定
./build.py -C path/to/compiler.jar -m zip.unpack -o unzip.min.js

設定ファイルを書くことでもうちょっとだけ詳細に設定することができます。

{
"compiler": "./compiler.jar",
"output": "./build/jsziptools.unzip.min.js",
"files": [
"src/jsziptools.js",
"src/utils.js",
"src/algorithms/crc32.js",
"src/algorithms/inflate.js",
"src/zip.unpack.js"
]
}

こんな感じで使います。

./build.py -c buildconf.json

Enjoy! :-)
posted by 右京 | javascript

jsでお絵かきチャット作るの個人的メモ

前提:websocketで線の情報を送る

線の情報:
色(1byte*3)、線幅(1byte)、始点(2byte*2)、終点(2byte*2)

//json 44~58byte JSON.stringify,parseのコストが高い?
'{"c":"FFFFFF","w":255,"x":1000,"y":1000,"X",1001,"y":1001}'
//普通に文字列をカンマ区切り 16~30byte str.split(',')と文字列->数値の変換コストくらい
'FFFFFF,255,1000,1000,1001,1001'
//bytestringにしてしまう 12byte 処理は多少面倒だけどそんなに遅くないのでは
'\xff\xff\xff\xff\x03\xe8\x03\xe8\x03\x03\xe9\x03\xe9'
//Typed Array 12byte 多分一番速い サーバの実装依存(BinaryJSを使うとよい?)
socket.binaryType = 'arraybuffer';

始点、終点を12bitずつにすると2byte減る。けどそこまでやる必要ないよね。
posted by 右京 | javascript

Typed Arrayの良記事

HTML5ROCKSの型付き配列の記事。Typed Arrays: Binary Data in the Browser - HTML5 Rocks

結構網羅的。エンディアン問題とかはすごく耳の痛い話だけど、現状インテルかAMDだしリトルエンディアンだけでも、まぁ、いいじゃないかとか思う(ダメな思考)。HTML5のAPIとの絡みとか、サードパーティライブラリも結構触っている。

型付き配列はHTML5で効率的なアプリケーションを作るのに欠かせない存在なので読むべきかなと思いました。

追記:
プルリクエストを送ったのでそのうち日本語になるかも。
posted by 右京 | javascript

Chrome 21+ではフォルダーのドロップをサポートしています

Chrome 21+ではフォルダーのドロップが可能になっています。ドロップされた各要素(dataTransfer.files)はgetAsEntry(実際にはwebkitGetAsEntry)することでFileSystem APIと同じインターフェースで扱うことができます。今までだと同じフォルダーの複数ファイルを扱うのが精一杯でしたが、この機能を使えば複雑な階層を持つフォルダーでも簡単に扱うことができます。

DEMO:
http://ukyo.github.com/js-epub-builder
ePubの仕様を満たすように作られたフォルダーをドロップすると、epubファイルを生成してDownloadフォルダに保存します。

参考:
Drag and drop a folder onto Chrome now available - HTML5Rocks Updates
Exploring the FileSystem APIs - HTML5 Rocks
posted by 右京 | javascript

ブラウザ上でepubを作るツールのサンプル

ロジックは完成。UIがもうちょっと。現状だとコンソール開いてepubにエクスポートといったかんじ。

で、そのツールで生成したepubのサンプルがこれ(ちょっと間違っていたので修正)↓
syntax_highlight_test.epub


ソースコードの表示が結構おしゃれ。
Screenshot_from_2012-07-19 05:15:12.png

作った感想としては、epubの中身が実質HTML5でWEBの資産がかなり使えるのでいろいろと楽できるねってことと、現状ViewerのJavascriptの対応状況がよくわからないんだけど、インタラクティブなコンテンツでも今までのWEBの手法とか資産がそのまま使えそう(素晴らしいことですね!)で楽しみってことですかねー。
posted by 右京 | javascript

epub editor作るのでメモ

生成方法
epubは大体html5→JSで生成できる。
zipで固める→jsziptoolsを使う(個別に圧縮率を設定できるのでOK)。
保存→Chrome、IE10は問題なし(ローカルに落とせる)。Firefoxは一応OK(ファイル名つけられない)。あとはDropboxと連携とか。


エディタ部分
ace editor
markdown.js
と自分で作った拡張ファイル
前に作ったマークダウンエディタを流用


必要そうなファイル
mimetype: "application/epub+zip"という文字列。
container.xml: ルートファイルへのパス。ルートファイル名にこだわらなければ同じでよし。
package.opf: ルートファイル。各リソースファイルへのパスや読み込み順、メタデータを記述。JSで生成する。
nav.xhtml: 目次。JSで生成する。アンカーってどうすんだろ。
body.xhtml: 本文。markdown.jsで変換してゴニョゴニョしてinnerHTMLかなぁ。
style.css: とくにこだわらなければ同じでよし。


その他メモ
実はepubに必要な各ファイルの生成だけやればよさそう。Dropboxと連携、サーバ立てるとかすると面倒。そもそもサーバ使うならそっちでepub生成できるというお話。クライアントだけで実装する場合に一番現実的で未来があるのはChrome Extension。ブラウザで動かすだけ→Chrome、IE10。Firefoxはaのdownloadを実装すればなぁ、もしくはFileSystem API。Safari、Operaとその他は見なかったことに。
posted by 右京 | javascript

JavascriptでDRYな継承2

JavascriptでDRYな継承 :右京webの改良版。
名前付き無名関数の有効的(裏技的)な使い方。

利点
・自動でclsネームスペースに格納
・直感的。cls.extend.Parent(function Child(parent){...});
・継承するときに文字列で直接クラス名を設定する必要がない(タイプ数が減る)

欠点
・this地獄

var cls = {};
cls.extend = function (parent, F) {
var child, cp, pp, f;

if (arguments.length === 1) {
F = parent;
parent = cls.Base;
}
parent = parent || cls.Base;
F = F || function () {};

pp = parent.prototype;
f = new F(pp);
child = f.init || function () { pp.init.apply(this, arguments); };
cp = child.prototype = Object.create(pp);
Object.keys(f).forEach(function (key) { cp[key] = f[key]; });
Object.defineProperty(cp, 'constructor', {
value: child,
writable: true,
enumerable: false,
configurable: true
});

if (F.name && F.name !== 'Base') {
cls[F.name] = child;
cls.extend[F.name] = function (F) { return cls.extend(child, F); };
}
return child;
};
cls.Base = function Base () {};
cls.extend.Base = function (F) { return cls.extend(cls.Base, F); };
cls.Base.prototype.init = cls.Base;

//example
cls.extend(function A () {
this.init = function (name) {
this.name = name;
};

this.hello = function () {
console.log(this.name + ': hello!');
};

this.hai = function () {
console.log(this.name + ': hai!');
};
});

cls.extend.A(function B (sup) {
this.init = function () {
sup.init.call(this, 'b');
};

this.hello = function () {
sup.hello.call(this);
console.log(this.name + ': hello!!!');
};
});

var C = cls.extend.B(function C (sup) {
this.init = function (a, b) {
this.name = a;
this.type = b;
};

this.hello = function () {
sup.hello.call(this);
console.log(this.name + ': hello!!!!!');
console.log(this.type);
};
});

var b = new cls.B();
b.hello();

var c = new cls.C('hasuta', 'syota');
c.hello();

var c2 = new C('nyaruko', 'azatoi');
c2.hello();
posted by 右京 | javascript

JavascriptでDRYな継承

クロージャ使えばいいんじゃないかという案(すでにありそう)。個人的にはけっこうイケてると思ってる。
改良版できました。JavascriptでDRYな継承2 :右京web

利点:
・親にアクセスするときにタイプ数が減る(Hoge.__super__.fuga -> __super__.fuga)
・__super__でもsupでもparentでも_でもなんでも好きな名前でアクセスできる(さらにタイプ数が減る)
・コンストラクタ(親、子どちらも)として使っている関数の名前をやっぱり変えようというときにちょっと楽ができる
・プライベートでスタティックな変数を持てる(副作用的)

欠点:
・this地獄

追記:
やっぱりObject.keysに直した。

function extend (parent, F) {
parent = parent || Object;
F = F || function(){};

var f = new F(parent.prototype),
child = f.__init__ || function () { parent.apply(this, arguments); };

child.prototype = Object.create(parent.prototype);

Object.keys(f).forEach(function (key) {
if(key !== '__init__') child.prototype[key] = f[key];
});

Object.defineProperty(child.prototype, 'constructor', {
value: child,
writable: true,
enumerable: false,
configurable: true
});

return child;
}

//example
var A = extend(null, function () {
this.__init__ = function (name) {
this.name = name;
};

this.hello = function () {
console.log(this.name + ': hello!');
};

this.hai = function () {
console.log(this.name + ': hai!');
};
});

//この場合parentにA.prototypeが入っている
var B = extend(A, function (parent) {
var PRIVATE_STATIC_VALUE = 'private';

this.__init__ = function () {
parent.constructor.call(this, 'b');
};

this.hello = function () {
parent.hello.call(this);
console.log(this.name + ': hello!!!');
};

this.getPrivateStaticValue = function () {
return PRIVATE_STATIC_VALUE;
};
});

var b = new B();
b.hello();
console.log(b.getPrivateStaticValue());
posted by 右京 | javascript

シンタックスハイライト、リアルタイムプレビュー機能つきのJavascript製Markdownエディタ

Screenshot_from_2012-06-28 10:37:29.png

手前味噌ですが。

機能:
・エディタ自体のシンタックスハイライト(Ace Editor)
・リアルタイムプレビュー
・プレビューのソースコードのシンタックスハイライト
・エディタでスクロールするとプレビューも連動
・GFM記法(これもAce Editor)

まぁ、ほぼほぼAce Editorですね。

DEMO
posted by 右京 | javascript

ふつうのjavascriptのprototypeの説明

javascriptで詰まるところといえばprototypeですよね。というわけで簡単にまとめてみたよ。
追記:ちょっと間違ってたので修正したものをgistに上げました。やっぱりmarkdownのほうが書くの楽だ。

https://gist.github.com/2990054
posted by 右京 | javascript

完璧なMarkdownエディター(笑)

index.html-063947.png

やはり、手元でシンタックスハイライトしながらプレビューもシンタックスハイライトしたいわけです。もちろんリアルタイムプレビューってのが最高なのですが、処理が重いのでプレビューボタンを押したらプレビューに反映させるということに・・・完璧じゃねぇ。

DEMO
posted by 右京 | javascript

markdown-jsを拡張してみよう!

的な感じで。GitHub Flavored Markdownのコードをハイライトするための構文がほしいなと思ったのでちょっと作ってみたよ。

markdown GFM − Gist
(function(Markdown) {

//Markdown.dialectsに色々とパースするためのクラス(ここではクラスと呼びます)が入っているよ。
//Markdown.dialects.Gruberはデフォルトで使われるクラスで、Markdown.subclassDialectを作って
//サブクラスを作るよ。作ったクラスはMarkdown.dialectsに生やせばOK。
Markdown.dialects.GFM = Markdown.subclassDialect(Markdown.dialects.Gruber);

//複数行にまたがるやつをパースする関数はMarkdown.dialects.Foo.blockに生やそう。
//blockには今パースしようとしているブロック(は改行2つ以上で分割されている)
//nextには次以降のブロックが配列で入っているよ。nextは参照渡しだよ。
Markdown.dialects.GFM.block.code_syntax_highlighting = function(block, next) {
var ret = [],
startRe = /^```(.*)\n?((.|\n)*)/,
endRe = /(.|\n)*```\n?$/,
m = block.match(startRe),
lang, code, lineRe, isEnd;

if(!block.match(startRe)) return undefined;

lang = m[1];
code = m[2];

block_search:
do {

if(isEnd = endRe.test(code)) code = code.substring(0, code.length - 3);
lineRe = new RegExp('^(?:' + (code.match(/(\s*)/)[1] || '') + ')(.*)\\n?');

var b = this.loop_re_over_block(lineRe, code, function(m) {ret.push(m[1])});

if(b.length) ret.push(b);

if(next.length && !isEnd) {
ret.push ( block.trailing.replace(/[^\n]/g, '').substring(2) );
block = next.shift();
code = block.valueOf();
} else {
break block_search;
}

} while(!isEnd);

return [['code_block', {'class': 'lang-' + lang}, ret.join('\n')]];
};

//これは書かないといけないみたいだよ。
Markdown.buildBlockOrder(Markdown.dialects.GFM.block);
Markdown.buildInlinePatterns(Markdown.dialects.GFM.inline);

})(markdown.Markdown);

使い方
markdown.toHTML(data, 'GFM');
posted by 右京 | javascript

ace editorでシンタックスハイライトだけする

ace editorで書いたのを表示用に加工したいというときに、他のシンタックスハイライター使ってもいいんだけど、書いたのと実際の表示が微妙に違うってのは嫌な人向け。シンタックスハイライトのテーマはace/lib/ace/theme at master ・ ajaxorg/ace ・ GitHubにたくさん入っているのでお好きなものを使ったらいいかと。

/**
* syntax highlight
* @param {string} text
* @param {string} mode
* @param {string} theme
* @return HTMLElement
*/
function highlight(text, mode, theme) {
var dummy = document.createElement('p'),
result = document.createElement('ol'),
wrap = document.createElement('pre'),
lines = [],
editor;

function createLine() {
var line = document.createElement('li');
line.setAttribute('class', 'ace_line');
return line;
}

function createToken(obj) {
if(obj.type === 'text') return document.createTextNode(obj.value);
var token = document.createElement('span');
token.setAttribute('class', obj.type.split('.').map(function(v){return 'ace_' + v}).join(' '));
token.textContent = obj.value;
return token;
}

//create a dummy element and set to editor.
dummy.textContent = text;
editor = ace.edit(dummy);
editor.getSession().setMode(mode);

for(var i = 0, n = text.split('\n').length; i < n; ++i) {
lines[i] = editor.getSession().getTokens(i);
}

//convert js objects to dom.
lines.forEach(function(v) {
if(!v) return;
var line = createLine();
v.forEach(function(v) {
line.appendChild(createToken(v));
});
result.appendChild(line);
});

result.setAttribute('class', theme);
wrap.appendChild(result);
return wrap;
}

ちなみに、elem.textContent = '<div>'みたいにtextContentに文字列を挿入すると勝手にhtmlタグその他をエスケープしてくれるよ。文明の利器だね。
posted by 右京 | javascript

markdown-jsでHTML5なコードを吐き出すようにする

markdown-jsはJavaScript製のMarkdownパーサーで、最終的なHTMLコードだけでなく、中間的なJSON形式のコードも吐き出してくれるので拡張がしやすくなっている。

で、今回はHTML5で出力するわけだけど、実際のどう違うか具体的なコードで見てみる。例えばこんな感じのmarkdownのテキストがあったとすると
# 1

なにか

## 1.1

hoge

## 1.2

fuga

> 引用とか

# 2
## 2.1
### 2.1.1

HTML4(default)ではこんな感じで出力される。
<h1>1</h1>
<h2>1.1</h2>
<p>hoge</p>
<h2>1.2</h2>
<p>fuga</p>
<blockquote><p>引用とか</p></blockquote>
<h1>2</h1>
<h2>2.1</h2>
<h3>2.1.1</h3>

HTML5だとこんな感じ。
<section>
<h1>1</h1>
<section>
<h1>1.1</h1>
<p>hoge</p>
</section>
<section>
<h1>1.2</h1>
<p>fuga</p>
<blockquote>
<p>引用とか</p>
</blockquote>
</section>
</section>
<section>
<h1>2</h1>
<section>
<h1>2.1</h1>
<section>
<h1>2.1.1</h1>
</section>
</section>
</section>

このようにHTML5でマークアップする場合は各sectionごとにh1を使える。例えばブログの記事のタイトルだけ別のフォームで入れて、本文はmarkdownで書くような場合だと、わざわざ#の数を調整せずに使えるので便利だし、後からこうしたかったーっていうときもh1しか使っていないので修正も楽かと思う。cssはちょっとだけ面倒かな?でも、今はsassとかあるから平気だよ!多分!

ソースコード:https://gist.github.com/2879128
markdown.toHTML5 = function(source, dialect, options) {
return markdown.renderJsonML((function to5(tree, level) {
var i, m,
indices = [],
hx = 'h' + level,
n = tree.length,
blocks = [];

if(!n) return [];

function set(start, end) {
blocks.push(['section', ['h1', tree[start][1]]].concat(to5(tree.slice(start + 1, end), level + 1)));
}

for(i = 0; i < n && hx !== tree[i][0]; ++i) blocks.push(tree[i]);
for(i = 0; i < n; ++i) if(hx === tree[i][0]) indices.push(i);
for(i = 0, m = indices.length - 1; i < m; ++i) set(indices[i], indices[i + 1]);
if(indices.length) set(indices[m], n);

return blocks;
})(markdown.toHTMLTree(source, dialect, options), 1));
};
posted by 右京 | javascript
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。