anti scroll

ブラウザと小説の新しい関係を模索する

Chrome Extensionのmanifest.json内version値を更新するスクリプト

手作業でやるのが面倒になってきたので書きました。

事前にnpm install minimistが必要です。

// update-manifest-version.js

var fs = require("fs");
var args = require("minimist")(process.argv.slice(2));

var update_version = function(version, target){
  var parts = version.split(".");
  var map = {major:0, minor:1, build:2, revision:3};
  var index = map[target] || 2;
  parts[index] = parseInt(parts[index]) + 1;
  return parts.join(".");
};

var file = args.f || "./manifest.json";
var target = args.t || "build";
var encoding = args.e || "utf8";
var json = JSON.parse(fs.readFileSync(file, encoding));

json.version = update_version(json.version, target);

fs.writeFileSync(file, JSON.stringify(json, null, 2), "utf8");

使い方

例えば今のバージョンが1.2.5(major=1, minor=2, build=5)で、buildバージョンだけ1つ上げたい場合

node update-manifest-version.js -f /path/to/manifest.json -t build -e utf8

とやります。

textNodeの出力オプションを追加

2chからのアクセスに、珍しくリファラが付いてたので、元スレを覗いてみたのですが、縦書き文庫に投稿された作品へのリンクに「踏まないほうがいいよね?」ってレスが付いていて、地味に傷ついたのでした。

capturePageTextオプション

それはさておき、表題の件です。

まだリリースはされていませんが、nehan.jsのリポジトリ上では、 Nehan.PageStreamsetContentや、 Nehan.PageStreamasyncGetという関数のオプションに、capturePageTextという新しいオプションが追加されました。

これを有効にすると、出力されるページに、DOMElementで言うところのtextNode的な文字列が入ってきます。

var pe = Nehan.createPagedElement().setContent("<p>foo</p>", {
  capturePageText:true, // textNodeを出力する
  onProgress:function(tree, ctx){
    console.log(tree.text); // "foo"
  }
});

この機能を使えば、例えばビューアーに検索機能を付けたい場合、filter関数を使って、

var search_pages = function(pe, keyword){
  return pe.filter(function(page){
    return page.text.indexOf(keyword) >= 0;
  });
};

var cool_pages = search_pages(pe, "cool!");

とかやれば、キーワードにマッチするページ配列が取得できるようになります。

Nehan.BoxとNehan.Pageの違い

ちょっとした捕捉ですが、filterが返すのは、Nehan.Pageの配列ではなく、Nehan.Boxの配列であることに注意して下さい。

つまり、上のプログラムにおけるcool_pagesのそれぞれには、elementメンバが存在しません。

console.log(typeof cool_pages[0]); // "Box"
console.log(typeof cool_pages[0].element); // "undefined"

これはなぜかというと、nehan.jsが計算するページは、実際にそのページが画面に表示されるまでは論理レイアウトNehan.Box)として保存されているからです。

nehan.jsでは、画面に表示されるときになって初めて、論理レイアウト(Nehan.Box)がon the flyで実レイアウト(Nehan.Page)に変換されます(これはたかだか1ページぶんの変換なので、一瞬で終わります。もちろん評価が済んだページはキャッシュされるので、再計算も発生しません)。こうやって生DOMの生成を遅延することで、全体のパーススピードを上げているわけです。

まだ表示されていないページを検索結果に含めるために、filter関数の戻り値はNehan.Boxの配列となっています。

余談

最後にnehan.jsの検索性について、ちょっと余談です。

よくnehan.jsのbrタグについて「CTRL+Fの検索が使えない」と言う人がいますが、段組みで表示する場合はその通りとして、ページ送りの組版にとってはどのみちCTRL+Fはあまり意味がないことに留意していただきたく。

例えば、検索ワードが最終ページにヒットするケースを考えて下さい。

そういう場合、いま見ているページをすっ飛ばして、いきなり最終ページにジャンプするわけにはいかないじゃないですか。

だから、ページ送りで表示するドキュメントの場合、どのみち検索機能は別のUIを用意する必要があるわけです。

だからbrはたいして問題じゃないように思うわけですが、どうなんでしょうね?

段落の先頭に自動で空白を入れる

サッカーのページを見ていたら、サイドメニューあった「ストレスと友達になる方法」というリンクが「スアレスと友達になる方法」に見えてしまいました。

ストレスともスアレスとも友達になれそうにない自分ですが、せめて段落の先頭に自動で空白を入れるぐらいのことはできるのではないか…

ということで、以下は「Pタグで表現された段落なら、自動で空白を埋め込む」スタイル設定です。

サンプル1

まずはシンプルに文字を注入する方法です。

{
  p:{
    onload:function(ctx){
      var markup = ctx.getMarkup();
      var content = markup.getContent();
      var head_char = new Nehan.Char(content.substring(0,1));

      // 先頭が全角スペース、カッコ開始、その他の特殊スペースじゃない
      if(!head_c1.isIdeographicSpace() && 
         !head_char.isKakkoStart() && 
         !head_char.isSpace()){
          // 先頭に全角スペースを注入
          markup.setContent(" " + content);
      }
    }
  }
}

よりちゃんと動かすためには「先頭がタグ開始文字だったらスキップして、本当の先頭文字を取りに行く」という処理が必要ですが、ほとんどの場合において、正しく動くでしょう。

サンプル2

ついでに、別のやり方も紹介しておきます。

以下は、pseudo-elementfirst-letterを使う方法です。

{
  "p::first-letter":{
    display:"inline",
    padding:function(ctx){
       var letter = ctx.getMarkupContent().substring(0,1);
       var chr = new Nehan.Char(letter);
       if(!chr.isIdeographicSpace() && !chr.isKakkoStart() && !chr.isSpace()){
         return {start:"1em"};
       }
       return null;
     }
  }
}

こういう自動処理は、サービス側で用意してもいいのですが、ユーザーに制御する自由があると、より小回りがきくと思います。

スタイル編集機能で、プログラマブルな小説投稿

新たにスタイル編集ページを追加しました。

詳しくは縦書き文庫のヘルプから「スタイル編集」のページを確認して下さい。

注意事項

スタイルはcssではなく、JSON形式で宣言します。

{
   ".foo":{
       margin:{
          after:"1em"
       }
    },
   "span.fuga":{
       "font-size":"2em" // fontSizeでもOK
    }
}

afterってのが見慣れないかもしれませんが、これは論理方向です。詳しくはヘルプの解説を見て下さい。

あと、bodyタグの編集はできません

bodyのスタイルは「表示設定」ボタンでのみ変更できるようにしたいからです。

紳士の嗜みとして、ここは一つ「bodyタッチはNG」ということで、ご理解いただければと思います。

ちなみに、このスタイル編集の面白い点は、なんといってもプロパティとして関数が書ける点です。

なので、その辺りのサンプルを2つほど紹介したいと思います。

サンプル1

例えば、縦書きや横書きで文字列を替えたい場合があると思います。

数字を横書きでは半角で、縦書きでは漢数字で、とか。

そういうことをするタグを、例えばこんな風に定義できます。

{
  // 使いかた
  // <replace-if-vert text="一九八四">1984</replace-if-vert>年
  "replace-if-vert":{
    display:"inline",
    onload:function(ctx){
      if(ctx.isTextVertical()){
        var markup = ctx.getMarkup();
        markup.setContent(markup.getAttr("text"));
      }
    }
  }
}

こうやって定義した後に

<replace-if-vert text="一九八四">1984</replace-if-vert>

と書くと、横書きなら「1984年」、縦書きなら漢数字で「一九八四年」と表示されます。

サンプル2

スタイル編集の中で変数を使うにはどうしたらいいでしょうか。

スタイルは、最終的に1つのJSONを返せばいいわけなので、次のように関数に囲ってJSONを返す処理にしてしまえば、変数を使うこともできます。

(function(){
  var colors = ["red", "green", "blue"];
  return {
    ".rgb-list li":{
      color:function(ctx){
        var index = ctx.getChildIndex();
        return colors[index % colors.length];
      }
    }
  };
})()

こうやって定義した後に、

<ul class="rbg-list">
  <li>これは赤</li>
  <li>これは緑</li>
  <li>これは青</li>
</ul>

と書けば、各リストアイテムが「赤」「緑」「青」の順番で色が変わります。

というわけで、使いこなすことができたら、色々と面白いことができるのではないでしょうか。

camel caseでもcssプロパティが設定できるようになりました

nehan.js 5.1.1(まだ開発版ですが)から、cssのプロパティをcamel caseでも指定できるようになりました。

どういうことかというと、ver5.1.0以前では、例えばfont-sizeを設定するとき、

Nehan.setStyle({"font-size":"1.6em"}); // chain-case

のようにしか書けなかったのですが、これが

Nehan.setStyle({fontSize:"1.6em"}); // camel-case

のようにも書けるようになりました。

ただしver5.1.0以前では、後者は反映されないので、注意して下さい。

クラス名やID名が短く書けるようになりました

これまで縦書き文庫でマークアップするとき、特定の表示を利用する場合、クラス名にnehan-という接頭辞を付けなければならなかったのですが、これが不要になりました。

例えば行末寄せは、これまでは

<p class="nehan-ta-end">行末に寄せる</p>

だったのですが、今後は

<p class="ta-end">行末に寄せる</p>

マークアップできます。

同様に、これまでnehan.jsのスタイル設定は、idセレクタもclassセレクタnehan-を付けるルールでしたが、これも不要になりました。

Nehan.setStyle(".nehan-foo", {color:"red"});
Nehan.setStyle(".foo", {color:"red"}); // 今後は"nehan-"の部分は不要に

マークアップは少しでも短いほうがいいですからね…

ちなみに今回の仕様変更によって、過去エントリーを修正する必要はありません。

過去の仕様でマークアップされていても、いままで通りに表示されます。

縦書き文庫のマークアップについての詳細は、マークアップヘルプを参照して下さい。

各ユーザーの作品を一覧できるアーカイブページを用意しました

ユーザーの作品を手早く一覧できるページを用意しました。

例えば、図書館アカウントのアーカイブページ

f:id:convertical:20150614213535p:plain

スマホからでも閲覧できるので、自作の一覧を手っ取り早く紹介するページとして便利かもしれません。

アーカイブページのURLは、以下のとおりです。末尾のところを、自分のユーザーIDに変えてください。

http://tb.antiscroll.com/archives/<あなたのユーザーID>

操作法ですが、作品のタイトルをクリックすると、ページ送りのビューアー画面に切り替わります。

f:id:convertical:20150614213555p:plain

シリーズラベルをクリックすると…

f:id:convertical:20150614213612p:plain

こんな風にシリーズの一覧が表示されます。

f:id:convertical:20150614213636p:plain

PC環境では割りと軽快に動くことを確認していますが、実際のモバイルの環境ではどうか。ちょっと心配です。

フィードバックがあれば、いつもどおりメールフォームやらツイッターにて受け付けています。

マークダウン記法をサポートしました

テキストをマークダウン記法で記述できるようになりました。

「その他の項目」の「入力方法」から設定できます。

f:id:convertical:20150602091733p:plain

でも実は「あんまり使われないかもしれないなあ」と思っています。

というのも、マークダウンで改行するには、空行をひとつ開ける必要があるからです。

それだと原稿用紙的なイメージと、直感的に異なるんですよね。

一応よく知らない人のために説明すると、例えば次のようなテキストは、マークダウンでは二行のテキストになりません。「あいうえおかきくけこ」と一行で表示されます。

あいうえお
かきくけこ

これを二行にするには

あいうえお

かきくけこ

と記述する必要があります。

ただし、次のように「ヘッダー」や「リンク」や「太字」などはマークダウンのほうが書きやすいのも事実なので、必要に応じて使い分けるのがいいと思います。

## H2の見出しテキスト

ここを**太字**にする。[リンク](http://google.com)を貼る。