2015年4月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
無料ブログはココログ

« enchantMOON : 双方向リンクシールを作りました(使い方のみ) | トップページ | enchantMOON : 双方向リンクシールを作って考えた »

2013年10月27日 (日)

enchantMOON : 双方向リンクシールを作りました(解説&言い訳)

[2013/12/06 追記] バージョンアップに伴い、[双方向リンク元検索シール(1)], [双方向リンク元検索シール(2)]は廃盤としました。>詳細


昨日(というか、日付としては今日なので、前回)アップロードしたシールについて、あれこれ解説&言い訳をしてみます。

今回作ったシールは、pre-install の「お気に入りシール」をちょっとだけ拡張したものなので、そんなに高度なことはしていないのですが、結局ずいぶん苦労しました。そのうち半分くらいはタイプミスですが、残りのあれこれを書き出してみます。

やりたくてできなかったこと - ページを移動してからシールを剥がす

実現したかったのは、単にリンク元を探してリストアップすることでしたので、最初はシステムレベルで作成されたリンクを拾い出せないかと調べたのですが、さすがに他のページの情報を javascript で直接拾い出すこともできず、MOON.searchStorage() で検索できるように組み立てることになりました。

できることの範囲内で、できるだけ使いやすいように工夫しましたが、最終的にひとつだけ残念な仕様になってしまったのは、「検索が済んで用済みになったシールを自動で剥がすことができない」ことです。

リンク元を検索したいときは、事前にシールを貼って準備しておくというよりも、任意のページで、ふとリンクを逆にたどりたくなって検索するはずです。シール台帳から検索シールを選べば、すぐに検索動作になって、その後は余計なものを残さずに消えてくれるのが理想です。

「検索シール(1)」の "hack.js" の一部を以下に示しますが、

    sticker.onattach = function(event) {
        var query = queryForLinkedSearch();
        shrinkStickerClip();
        MOON.searchStorage( query );
//        MOON.peel();
        MOON.finish();
    };

当初は MOON.searchStorage() のあとに MOON.peel() でシールを剥がして終了、のつもりだったのですが、安定動作しません。リンク元へのページ移動の途中で止まってしまったり、シールの動作が終了せずに三本指キャンセルが必要になったりします。

よく考えてみると当然でした。

検索シールを貼る → MOON.searchStorage() でページを検索し、移動先を選択・タッチする → ページを移動・表示されるページが変わる → (このとき、恐らくプロセスのカレントディレクトリ或いは OS の現在ページ管理情報が、移動したページのものに変化する) → ここで、元のシールの情報に基づいて MOON.peel() を実行しても、移動先の環境では該当するシールが存在しないために "Sticker is not defined" なエラーが出る。

かといって、MOON.searchStorage() の前に MOON.peel() を実行すると、当然そこでシールが終了してしまうので、リンク元検索動作を実行できません。

しかも、MOON.serchStorage() は非同期動作のようで(?)タイミングによって動作が微妙に違います。MOON.peel() と MOON.finish() をいろんな場所に埋め込んで試してみましたが、やっぱり無理でしたので、最終的に諦めました。

そうなると、リンク元に移動してシールを終了するので、検索を開始したページにはシールが張り付いたまま残ってしまいます。あとで改めて、検索シールを剥がす手間が発生します。はっきり言って美しくない。

せめて使い勝手を多少でも選んでもらえるように、検索シールは二種類作りました。

「検索シール(1)」は、張り付けると同時に検索動作に入ります。あとでシールを剥がす手間は少しでも簡単な方がよいので、シールをタッチするだけで剥がれてくれます。使用の手間は少なくなりますが、UI としては変則的でしょう。

「検索シール(2)」は、張り付けても何も起こりません。タッチすると検索します。剥がす時には普通に指で囲んで "delete" を選択してください。こちらの方が素直な UI ですが、(1) よりひと手間増えてしまいます。但し、同じページから何度もリンク元検索を繰り返すようなら、こちらの「普通に張り付く」シールの方が便利です。

考えてみると、このような、カレントディレクトリを移動してからシールを剥がすなどという機能は、そうそう必要にはなりません。妙なシールを作ってしまった私の方が irregular だったのでしょう。

MOON.searchStorage() 周り - 結構ハマりました

機能の要となる、MOON.searchStorage() には検索用の query として、関数を文字列化して渡すのですが、これが当初なかなか動かない。動かないこと以外にデバッグの方法もなかったので、あれこれ試行錯誤した結果、以下のようなことがわかりました。(私が勘違いしていなければ)

query に渡す関数は、無名関数では動作しない。しかも、関数名は何でもよいわけではなくて、"matches()" でなければ動作しない。

こんなことは、マニュアル類や、公式の API リファレンスにも書いてなかったのでハマりました。特に後者は、なかなか意表をついたトラップと言えるでしょう。そのうち改修するのかもしれませんし、まあ、情報さえあれば実害は乏しいので、そのままかもしれません。

リンク元ページの検索情報は、localStroage(その実体は storage.json ですが)に、"kasinSearch" というプロパティ名で埋め込んでいます。最初は柔軟性を考えて、連想配列(= object)で埋め込んだのですが、MOON.searchStorage() を実行すると、全てのページの storage.json を読み込んで check することになるので、あまり複雑な構造のデータだと、enchantMOON のパフォーマンスでは苦労しそうです。そう考えて、途中から、単一の文字列にデータを詰め込む形に設計を変えました。(一応、元の実装も注釈の形で残してあります)1ページに登録シールを何十枚も張り付けると、どちらの実装の方が軽くなるのかわかりませんが、数枚程度であれば、現在の実装の方が軽いと思います。

その他もろもろ

双方向 link の「登録シール」は、一つのページに複数枚張り込みたいので、シールごとにリンク先を区別して管理することが必要です。ぶっちゃけて言うと、シールそれぞれの ID を区別しなければならないのですが、以前 esmasui さんの処の blog で、「現行バージョン(2.5)のMOONPhaseは、実行されているシール自身のIDを取得する方法がありません。」とありましたので、当面あきらめていました。

しかし、@k_ohga さんの「見た目が国旗になるシール」 を読んでると、シール本体が格納されている directory 名を取得できてます。いつの間にかできるようになってた(?)んですね。ありがたく参考にさせていただいて、以下のような関数にしました。

function getStickerID() {
    var relURL = window.location.getAbsoluteURL("").split("/Data/")[1];
    return relURL.split( "/" )[2];
}

function getPageID() {
    var relURL = window.location.getAbsoluteURL("").split("/Data/")[1];
    return relURL.split( "/" )[1];
}

さて、上記の関数で、ページやシールの識別 ID を得ているのですが、この実装で気になるのが、"enchantMOON - Issue Tracker:69 - 機能要望 サムネイル画面でのページのコピー" が、どのように実現されるのか。

最も単純な実装は、複製元ページの directory 名が "XXX..." であった場合、複製先として新しいページ用の directory を作り(directory 名を "YYY..." とします)"XXX..." 以下の file, directory を丸ごと copy する方法です。ただ、これですと、MOON.getPaperJSON( pageID ) が機能しない。

元ページのストロークデータファイルが、"XXX.../xxx.../info.json" だったとして、単純丸々コピーすると、複製先は、"YYY.../xxx.../info.json" ということになります。ファイルツリーによって、名前空間の一意性は保たれています。しかし、MOON.getPaperJSON() では、どちらのストロークデータにアクセスする場合も MOON.getPaperJSON( "xxx..." ) になってしまうので一意性が確保できません。今の MoonPhase の設計では、階層を無視した各 directory 名のそれぞれが一意でないとならないのです。そのため、"XXX.../xxx.../info.json" の複製先は、例えば "YYY.../zzz.../info.json" と別の directory 名にしなければなりません。

今回作ったシールでは、上記のように異なる directory 名で複製されてしまうと、リンク情報が辿れなくなってしまいます。一応、今後の可能性も考えて、そのような場合はリンク情報の再設定が可能、かつ、リンクの再設定かシールを剥がす操作をすれば、localStorage から無効なリンク情報を削除するように作ってありますので、システムに悪影響を与えることはないと思います。

ページのコピーという機能が、どのような形で実装されるのか興味のあるところです。

もっといろいろと苦労したような気がするのですが

思い出せないのでここまでにします。

« enchantMOON : 双方向リンクシールを作りました(使い方のみ) | トップページ | enchantMOON : 双方向リンクシールを作って考えた »

enchantMOON」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1527616/53736933

この記事へのトラックバック一覧です: enchantMOON : 双方向リンクシールを作りました(解説&言い訳):

« enchantMOON : 双方向リンクシールを作りました(使い方のみ) | トップページ | enchantMOON : 双方向リンクシールを作って考えた »