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)]は廃盤としました。>詳細


MoonPhase が 2.6.0 に update されて、localStorage が使えるようになったので、前から作りたかったシールを作りました。

ですが、残念ながら、欲しい機能が実現できませんでした。それでも、「ないよりマシ」かもしれませんし、最低でも、「今後こんな機能が欲しい」というたたき台にはなると思いますので、以下の注意点をお読みの上、酔狂な方だけご使用下さい。

Download : [双方向リンク登録シール], [双方向リンク元検索シール(1)], [双方向リンク元検索シール(2)]

注意点

まず、不安定です。特に例の "電源投入時に「内部エラー」と頻繁に表示される問題につきまして" に該当する方は結構やばいかもしれません。うちの子(MOON)も入院しました。退院して随分ましになりましたが、残りの不安定さが、私のコードによるものなのか、OS(ver.2.6.0)によるものなのかわかりません。もし私のコードの不備が分かる方おられましたら、ぜひ教えて下さい。また、動作は大変遅いです。

不安定なことに目をつむっても、使い勝手が悪いです。下記の「使い方」にあるように、「リンク作成」シールと、「リンク元検索」シールがあるのですが、後者で、「検索して移動」と「シールを剥がす」を一度に行うことができません。必ず、用済みのシールが残ります。あまりに使い勝手が悪いので、「検索シール」は、(1)貼り付けで検索、タップで削除、と(2)タップで検索、指で囲んで削除、の 2 バージョン用意しました。

あくまでも「実証実験」と考えてください。

以下の「使い方」をお読みの上、使いやすい方をお使い下さい。

Download : [双方向リンク登録シール], [双方向リンク元検索シール(1)], [双方向リンク元検索シール(2)]

どんなものか

ページからページへ、一方向ではなく、双方向のリンクを可能にするものです。
enchantMOON が他のタブレットの手書きメモに勝る(?)部分は、ノートのページ相互がハイパーリンクを形成できることです。が、現在の実装では一方向のリンクしか作成できません。MOON を見て誰もが連想した BTRON では、実身/仮身で、双方向にリンクをたどれます。(使ったことないので、誤解してたらご容赦を

2013/10/27 追記: @shi3z 社長から直々に「BTRONでは実身から仮身を辿れなかった」とのコメントをいただきました。やはり、知らないものをイメージだけで語るのはだめですね。上記訂正します。)

まともに双方向リンクを作成するのは大変なので、できる範囲で実現しています。あるページからリンク元を検索すると、そのページに対して(今回のシールを使って)リンクを張ってあるページの一覧を表示します。一覧から選んだページに移動できます。

「このページに飛んできた元のページに戻る」という動作ではありませんが、リンク元をピックアップできるだけでも、ないよりマシでしょう。

OS レベルで手を入れれば、同様の機能を実現するのは難しくないはずですが、「どんな使い勝手にするのがよいか、そもそも、こういう機能にどの程度需要があるか」という実験、リサーチくらいの位置づけでとらえてください。(そもそも不安定ですので)具体的な意見がたくさん出れば、開発チームの機能設計も楽になるでしょう。

使い方

二枚のシールを組み合わせて使います。他のページにリンクを張って登録するシール(registBiLinkTo - 以降「登録シール」と記述)、とリンク元ページの一覧を検索するシール(searchBilinkFrom - 以降「検索シール」と記述)の二枚です。

「登録シール」をページに貼ってから、タップするとリンク先選択画面が開きます。リンク先を選ぶと、そのシールに情報が登録され、以降はタップするとリンク先ページに移動します。(遅いですが)何かの誤動作で、リンク先情報が消失している場合は、タップすると改めてリンク先選択画面が開きます。「登録シール」は、一つのページに何枚でも貼り込むことができますので、画面イメージは以下のようになるでしょうか。

Bilinksticker_2

 

「登録シール」をいくつかのページに貼ってリンクを形成した後で、「検索シール」を使用します。特定のページで「検索シール」を貼ると、そのページにリンクを張っているページの一覧を表示します。この時表示されるのは「登録シール」でリンクを張ったページだけで、通常の、指で丸を描いて出てくるメニューから張ったリンクは検索できません。(システムレベルで作成したリンクの情報を拾い上げることは、今の処無理でした)

使い方はこれだけです。動作が速くて、システムが不安定にさえならなければ、そこそこ使えるとは思います。

技術的注釈

長くなりそうなので、解説や注釈は、日を改めます。

ソース提示

登録シール : hack.js

importJS(["lib/MOON.js", "main.js"], function() {

    function isStickerClipPlain() {
        var myID = getStickerID();
        var clip = MOON.getPaperJSON( myID ).clip;
        return ( clip.data[0] < 1.0 );
    }

    function shrinkStickerClip() {
        var myID = getStickerID();
        var paperJSON = MOON.getPaperJSON( myID );
        paperJSON.clip.data = [
72.0,40.2,0.05,71.83147,43.6306,0.05,
71.32748,47.02816,0.05,70.49291,50.35996,0.05,
69.33578,53.59392,0.05,67.86724,56.69889,0.05,
66.10144,59.64496,0.05,64.05537,62.40376,0.05,
61.74874,64.94874,0.05,59.20376,67.25537,0.05,
56.44496,69.30144,0.05,53.49889,71.06724,0.05,
50.39392,72.53578,0.05,47.15996,73.69291,0.05,
43.82816,74.52748,0.05,40.4306,75.03147,0.05,
37.0,75.2,0.05,33.5694,75.03147,0.05,
30.17184,74.52748,0.05,26.84004,73.69291,0.05,
23.60608,72.53578,0.05,20.50111,71.06724,0.05,
17.55504,69.30144,0.05,14.79624,67.25537,0.05,
12.25126,64.94874,0.05,9.94463,62.40376,0.05,
7.89856,59.64496,0.05,6.13276,56.69889,0.05,
4.66422,53.59392,0.05,3.50709,50.35996,0.05,
2.67252,47.02816,0.05,2.16853,43.6306,0.05,
2.0,40.2,0.05,2.16853,36.7694,0.05,
2.67252,33.37184,0.05,3.50709,30.04004,0.05,
4.66422,26.80608,0.05,6.13276,23.70111,0.05,
7.89856,20.75504,0.05,9.94463,17.99624,0.05,
12.25126,15.45126,0.05,14.79624,13.14463,0.05,
17.55504,11.09856,0.05,20.50111,9.33276,0.05,
23.60608,7.86422,0.05,26.84004,6.70709,0.05,
30.17184,5.87252,0.05,33.5694,5.36853,0.05,
37.0,5.2,0.05,40.4306,5.36853,0.05,
43.82816,5.87252,0.05,47.15996,6.70709,0.05,
50.39392,7.86422,0.05,53.49889,9.33276,0.05,
56.44496,11.09856,0.05,59.20376,13.14463,0.05,
61.74874,15.45126,0.05,64.05537,17.99624,0.05,
66.10144,20.75504,0.05,67.86724,23.70111,0.05,
69.33578,26.80608,0.05,70.49291,30.04004,0.05,
71.32748,33.37184,0.05,71.83147,36.7694,0.05
        ];
        MOON.setPaperJSON( myID, paperJSON );
    }

    var sticker = Sticker.create();

    sticker.ontap = function(event) {
        var linkToID = referMyLinkToID();
        if ( linkToID ) {
            moveToPage( linkToID );
            MOON.finish();
        } else {
            if ( isStickerClipPlain() ) {
                shrinkStickerClip();
                selectPageToLink();
                MOON.finish();
            } else {
                MOON.alert( "link 先情報が登録されていません", function() {
                    selectPageToLink();
                    MOON.finish();
                });
            }
        }
        MOON.finish();
    };

    sticker.onattach = function(event) {
        MOON.finish();
    };

    sticker.ondetach = function(event) {
        removeMyLink();
        MOON.finish();
    };

    sticker.register();
});

検索シール(1) : hack.js

importJS(["lib/MOON.js", "main.js"], function() {
    var sticker = Sticker.create();

    function shrinkStickerClip() {
        var myID = getStickerID();
        var paperJSON = MOON.getPaperJSON( myID );
        paperJSON.clip.data = [0.0,0.0,0.05,104.0,0.0,0.05,
          104.0,85.0,0.05,0.0,85.0,0.05,0.0,0.0,0.05
        ];
        paperJSON.width = 105;
        paperJSON.height = 86;
        paperJSON.image = "peel.png";
        MOON.setPaperJSON( myID, paperJSON );
    }

    sticker.ontap = function(event) {
//        MOON.finish();

        MOON.peel();
    };

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

        MOON.finish();
    };

    sticker.ondetach = function(event) {
        MOON.finish();
    };

    sticker.register();
});

検索シール(2) : hack.js

importJS(["lib/MOON.js", "main.js"], function() {
    var sticker = Sticker.create();

    sticker.ontap = function(event) {
        var query = queryForLinkedSearch();
        MOON.searchStorage( query );
//        MOON.peel();

        MOON.finish();
    };

    sticker.onattach = function(event) {
        MOON.finish();
    };

    sticker.ondetach = function(event) {
        MOON.finish();
    };

    sticker.register();
});

全体での共用ルーチン : main.js

var JISSIN_LINK = 'jissinLink';
var KASIN_SEARCH = 'kasinSearch';

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];
}

//
//
//
function getFromLocalStorage( tag, nullDefault ) {
    nullDefault = nullDefault || {};
    var obj = localStorage[ tag ];
    if ( obj == null ) {
        return nullDefault;
    } else {
        return obj;
    }
}

//
// localStorage に、値 obj を 名 tag で登録する。
// 但し、値が null, {}, [] の場合は削除する。
//
function setToLocalStorage( tag, obj ) {
    if ( (typeof obj).match( /number/i ) ) obj = obj.toString();
    var isObj = (typeof obj).match( /string/i );

    if ( (obj == null)
      || ( (typeof obj).match( /object/i ) && Object.keys( obj ).length <= 0 )
    ) {
        if ( localStorage[ tag ] ) localStorage.removeItem( tag );
    } else {
            localStorage[ tag ] = obj;
    }
}

//
// 自シールに対して登録されているリンク先ページの ID を参照
//
function referMyLinkToID() {
    var jissinLink = getFromLocalStorage( JISSIN_LINK, {} );
    return jissinLink[ getStickerID() ];
}

//
// { myStikerID => linkToID } から成る object を scan.
// 自ページのシール以外からの link 情報が紛れていたら
// ゴミとして削除する。
//
function sweepJissinLinkInfo( jLink ) {
    var stickers = MOON.getCurrentPage().papers;
    var keys = Object.keys( jLink );
    for ( var i = 0, l = keys.length; i < l; i++ ) {
        if ( stickers.indexOf( keys[i] ) < 0 ) delete jLink[ keys[i] ];
    }
    return jLink;
}

//
// { myStikerID => linkToID } から成る object を基に、
// link 先 ID を ':' 連結した文字列を作成して戻す。
// 処理するべき情報がない場合は null を返す。
//
function makeLinkedSearchInfo( linkToObj )  {
    var tmpObj = {}, tmpArray = [], k;

    for ( k in linkToObj ) {
        tmpObj[ linkToObj[ k ] ] = true;
    }
    for ( k in tmpObj ) {
        tmpArray.push( k );
    }

    return ( tmpArray.length > 0 ) ? ( ':' + tmpArray.join( ':' ) ) : null;
}

//
// MOON.searchStorage() に渡す、文字列化した query を返す。
// pageID に対する link 情報の存在する page が検索にかかる。
//
function getLinkedListQuery( pageID ) {
    return 'function matches(s){var ks = s[\"' + KASIN_SEARCH + '\"]; return ((ks != null) && (ks.indexOf(\":' + pageID + '\") >= 0));}';
}

/*-------------------------------------------------------------------------//
// makeLinkedSerchInfo を、文字列でなく、object (=連想配列) として
// 実装する案。こちらの方がカッコイイが、scalability を考えなければ
// 文字列案の方が、MOON.searchStorage() の際の実行コストが低くなるか?

//
// { myStikerID => linkToID } から成る object を基に、
// 検索用情報を格納した object を返す。
// 処理するべき情報がない場合は {} を返す。
//
function makeLinkedSearchInfo( linkToObj )  {
    var linkedListObj = {}, k;

    for ( k in linkToObj ) {
        linkedListObj[ linkToObj[ k ] ] = true;
    }
    return linkedListObj;
}

//
// MOON.searchStorage() に渡す、文字列化した query を返す。
// pageID に対する link 情報の存在する page が検索にかかる。
//
function getLinkedListQuery( pageID ) {
    return 'function matches(j){\
var ks = j[\"' + KASIN_SEARCH + '\"];\
if ( ks ) { return ks[\"' + pageID + '\"]; } else { return false; }\
            }';
}

//-------------------------------------------------------------------------*/

//
// linkToID で指定されたページへの link 情報を localStorage に登録する。
// 引数が null であれば、link 情報の削除処理を行う。
//
function registMyLink( linkToID ) {
    var myID = getStickerID();
    var jissinLink = getFromLocalStorage( JISSIN_LINK, {} );

    if ( linkToID ) {
        jissinLink[ myID ] = linkToID;
    } else {
        delete jissinLink[ myID ];
    }

    jissinLink = sweepJissinLinkInfo( jissinLink );
    setToLocalStorage( JISSIN_LINK, jissinLink );
    setToLocalStorage( KASIN_SEARCH, makeLinkedSearchInfo( jissinLink ) );
}

//
// 自 link シールが担当している link 情報を削除する
//
function removeMyLink() {
    registMyLink( null );
}

//-------------------------------------------------------------------------//

//
// 指定された link 先へ移る。
//
function moveToPage( linkToID ) {
    if ( linkToID ) {
        MOON.openPage( linkToID );
    } else {
        MOON.alert( 'Link 先ページが登録されていません', function() {
            MOON.finish();
        } );
    }
}

//
// link 先ページを選ぶ。link 情報を localStorage に登録する。
//
function selectPageToLink() {
    MOON.openNotebook( function( pageID ) {
        registMyLink( pageID );
        MOON.finish();
    });
}

//
// link 元ページの一覧を表示するための query を返す。
//
function queryForLinkedSearch() {
    return getLinkedListQuery( getPageID() );
}

解説と言い訳は、明日にでも。

Download : [双方向リンク登録シール], [双方向リンク元検索シール(1)], [双方向リンク元検索シール(2)]

« enchantMOON : シール、作りたいけど作れない | トップページ | enchantMOON : 双方向リンクシールを作りました(解説&言い訳) »

enchantMOON」カテゴリの記事

コメント

コメントを書く

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

トラックバック

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

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

« enchantMOON : シール、作りたいけど作れない | トップページ | enchantMOON : 双方向リンクシールを作りました(解説&言い訳) »