ポップアップメニューを手軽に扱う

提供: MeryWiki
移動先: 案内検索

マクロではないのですが、Meryのポップアップメニューを手軽に扱える関数を書いてみました。

function ShowPopupMenu(menu_obj, position, separator, esc){
    var MAX_NEST = 5;//ネストの最大深度
 
    var id_counter = 1;
    var item_list = [];
    var popup
    var selected_id;
 
    //メニューをESCキーで閉じた時の挙動を登録
    if(esc === undefined){
        item_list[0] = function(){Quit();};
    }
    else{
        item_list[0] = esc;
    }
 
    //メニュー位置の初期化
    if(position !== mePosMouse) {
        position = 0;
    }
 
    //セパレーターを挿入する条件
    var isSeparator = function(str){
        if(separator === false){
            return false;
        }
        else if(typeof separator === "string"){
            return (str.indexOf(separator) !== -1);
        }
        else{
            return (str.indexOf("----") !== -1);
        }
    };
 
    var ObjectOrArray = function(target){
        if(target){
            switch(Object.prototype.toString.call(target) ){
                case "[object Object]":
                    return "Object";
                    break;
                case "[object Array]":
                    return "Array";
                    break;
                default:
                    return "Other";
                    break;
            }
        }
        else{
            return "Other";
        }
    };
 
    var ArrayToPopup = function(list){
        var menu = CreatePopupMenu();
 
        for(var i =0; i < list.length; i++){
            if(isSeparator(list[i].toString() ) ){
                menu.Add("dummy", 999, meMenuSeparator);
            }
            else{
                menu.Add(list[i].toString(), i + 1);
            }
            item_list[i + 1] = list[i];
        }
        return menu;
    };
 
    var  ObjectToPopup = function(obj, nest){
        var menu = CreatePopupMenu();
 
        for(var key in obj){
            if(isSeparator(key) ){
                menu.Add("dummy", 999, meMenuSeparator);
            }
            else{
                if(ObjectOrArray(obj[key] ) !== "Object"){
                    menu.Add(key, id_counter);
                    item_list[id_counter] = obj[key];
                    id_counter++;
                }
                else{
                    if(nest < MAX_NEST){
                        menu.AddPopup(key, ObjectToPopup(obj[key], nest + 1) );
                    }
                }
            }
        }
        return menu;
    };
    //ここまで変数、関数の定義
    //関数の本体はここから
    switch(ObjectOrArray(menu_obj) ){
        case "Object":
            popup =  ObjectToPopup(menu_obj, 0);
            break;
        case "Array":
            popup = ArrayToPopup(menu_obj);
            break;
        default://第1引数が配列かオブジェクト以外の時
            throw new Error("第1引数には配列またはオブジェクトを指定してください");
            break;
    }
 
    selected_id = popup.Track(position);
 
    if(typeof(item_list[selected_id] ) === "function"){
        return item_list[selected_id]();
    }
    else{
        return item_list[selected_id];
    }
}

簡単な使い方[編集]

var x = ShowPopupMenu(["Spring","Summer","Autumn","Winter"] );
Document.Write(x);

選択された文字列が挿入されます。

リファレンス[編集]

function ShowPopupMenu(
    menu_obj : Object | Array,
    position : int,
    separator : Boolean | String,
    esc : Anything
)

返り値 : 選択されたメニューに対応する値。後述。

menu_obj : 必ず指定する。メニューを定義したオブジェクトまたは配列。

position : 省略可能。メニューを表示する位置。mePosMouseを指定するとカーソル位置に表示される。

serarator : 省略可能。セパレーターを挿入する条件。後述。

esc : 省略可能。ESCキーでメニューを閉じた時の挙動。後述。

使い方[編集]

配列を指定する場合[編集]

第1引数に配列を指定するとその配列内の要素をメニューに表示します。

var list = ["メニュー1","メニュー2","メニュー3","メニュー4"]

SowPopupMenu関数の返り値は選択された要素になります。

オブジェクトを指定する場合[編集]

オブジェクトのキーがメニューに表示ます。キーに対応する値が返り値になります。(値が関数オブジェクトの時は後述。)

var menu = {};
menu["メニュー1"] = "メニュー1";
menu["メニュー2"] = 2;

こうするとサブメニューを作れます。

menu["グループ1"] = {};
menu["グループ1"]["サブメニュー1"] = "SubMenu1";

連続したハイフン4つ(----)をキー内に含む場合セパレータになります。

menu["----"] = 0; //何らかの値を入れておく。
 
list = ["menu1","menu----2","menu3"] //配列でも可能。

使用例[編集]

var menu = {};
 
menu["メニュー1"] = "メニュー1";
menu["メニュー2"] = 2;
 
menu["グループ1"] = {};
menu["グループ1"]["サブメニュー1"] = "SubMenu1";
menu["グループ1"]["----"] = 0;
menu["グループ1"]["サブメニュー2"] = "Submenu2";

このように指定することも可能です。

var menu = {
    "メニュー1" : "メニュー1",
    "メニュー2" : 2,
    "グループ1" : {
        "サブメニュー1" : "SubMenu1",
        "----" : 0,
        "サブメニュー2" : "SubMenu2"
    }
}

返り値[編集]

オブジェクトでメニューを定義するする場合、値が関数オブジェクトかそれ以外かで返り値が変わります。 関数オブジェクトを指定するとその関数を実行して、その関数の返り値がShowPopupMenu関数の返り値になります。

function func1(){
    Document.Write("func1");
    return 0;
}
 
var menu = {};
menu["func1"] = func1; // func1() 、ではない。(括弧は付けない)

「func1」がエディターのキャレット位置に挿入され、0が返ります。

もちろんfunctionリテラルで直接書いてもかまいません。

menu["func2"] = function(){Alert("func2");};

関数オブジェクト以外を値とした場合はその値がそのまま返ります。

その他の引数の説明[編集]

第2引数にmePosMouseを指定するとマウスカーソルの位置にメニューが表示されます。

ShowPopupMenu(menu, mePosMouse)

それ以外の値の時はキャレット位置に表示します。

第3引数にfalseを指定するとセパレーターを挿入しなくなります。また文字列を指定するとその文字列が含まれるメニューをセパレータにします。それ以外の値は無視します。

ShowPopupMenu(menu,0,false) // セパレーターを挿入しない
ShowPopupMenu(menu,0,"ああああ") // 「ああああ」が含まれるメニューをセパレータにします。

第4引数でメニューをESCキーで閉じた時の挙動を変更できます。デフォルトではそこでスクリプトの実行が終了します。 関数オブジェクトを指定するとその関数を実行し、それ以外の値(undefinedを除く)の場合はその値を返します。

ShowPopupMenu(menu,0,0,-1)

上の例ではESCキーを押してもスクリプトは終了せず、関数は-1を返します。

その他[編集]

デフォルトではメニューの最大階層は5(2行目のMAX_NESTの値を書き換えることで変更可能)になっています。これは

var menu = {};
menu["メニュー1"] = 1;
menu["グループ1"] = menu;

といった再帰定義で無限ループになるのを防ぐためです。

Tips[編集]

menu["Now?"] = new Date();

こう書くとマクロを実行したとき(正確にはオブジェクトに代入した瞬間)の時間になります。これをメニューが選択された時の時間にするときは

menu["Now!!"] = function(){return new Date();};

こうやってfunctionでくるんでください。

おまけ[編集]

サブメニューとかいいから簡単に使いたいという人向け。

function ShowMenuMini(list){
    var pos = 0;
 
    var ret = 0;
    var menu = CreatePopupMenu();
 
    for(i = 0;i < list.length;i++){
        //if(list[i].toString().indexOf("----") !== -1){menu.Add("hoge",999,meMenuSeparator);continue;}
        menu.Add(list[i].toString(),i + 1);
    }
 
    ret = menu.Track(pos);
 
    if(ret === 0){
        Quit(); //ESCキーを押した時の挙動
    }
    else{
        return ret - 1;
    }
}

リファレンス[編集]

function ShowMenuMini(
    list : Array
)

引数には配列を指定する。選択された要素のインデックスが返り値になる。

使い方[編集]

var menu = ["Morning","Afternoon","Evening"];
var value = ["あんぱん","ジャムパン","カレーパン"];
 
Document.Write(value[ShowMenuMini(menu) ] );

なお、セパレーターを挿入する機能はオフにしてあります。セパレータを使いたい場合は8行目のコメントアウトを外してください。その場合はメニュの表示と返り値がずれることに注意してください。

var menu = ["Morning","Afternoon","----","Evening"];
var value = ["あんぱん","ジャムパン","ここが選ばれることはない","カレーパン"];
 
Document.Write(value[ShowMemuMini(menu) ] );