選択したドロップダウンリストウィジェット:位置の動的な追加を実装します

選択したトピックに基づいて、 ドロップダウンリストをよりわかりやすくします



かなりいいウィジェットで、時には役に立つこともあります(たとえば、特定の設計要件がある場合)。 しかし現時点では、ウィジェットはポジションを動的に追加することを許可しません。これは同志alexsrdk 、そして私も怒らせました:)今、この問題を修正しようとします。



ソースコードは生の形で提示され、すぐに書かれました、リファクタリングする何かがあると思います、問題を解決するためのアプローチを示すために記事が教育目的で書かれたので、私はこれに時間を費やしませんでした(しかし、実用的な可能性を排除しません)。



jQueryバージョンのオプション



パッチウィジェットコード


jQueryバージョンでは、Chosenウィジェットのメインクラスに到達する方法が見つからなかったため、ウィジェットのメインソースに少しパッチを適用する必要がありました(これは悪いアプローチであると理解しています)。



選ばれたクラスに到達するための多くのオプションがあり、少なくとも3つが思い浮かびます:

  1. 同様の方法でカスタムjQuery.fn.chosen関数で本文を変更します

    $.fn.extend({

    chosen: function (data, options) {

    var createdInstances = [];

    $( this ).each( function (input_field) {

    if (!($( this )).hasClass( "chzn-done" )) {

    createdInstances.push( new Chosen( this , data, options));

    }

    });

    return createdInstances;

    }

    });




    * This source code was highlighted with Source Code Highlighter .






  2. 作成したインスタンスをアイテムストアに保存できます。

    $.fn.extend({

    chosen: function (data, options) {

    return $( this ).each( function (input_field) {

    if (!($( this )).hasClass( "chzn-done" )) {

    return $( this ).data( 'chosenInstance' , new Chosen( this , data, options));

    }

    });

    }

    });




    * This source code was highlighted with Source Code Highlighter .






    同様の方法でChosenオブジェクトを取得できます。









    var createdChosenInstance = $( '#bears_multiple' ).chosen()。data( 'chosenInstance' );



    *このソースコードは、 ソースコードハイライターで強調表示されました。


  3. 別の関数を作成してクラスを取得できます

    $.fn.extend({

    chosenClass: function () {

    return Chosen;

    }

    });




    * This source code was highlighted with Source Code Highlighter .








私はjQueryライブラリをほとんど使用せず(主にYUIで作業します)、APIを手元に置いているため、おそらくこれらのオプションは最適ではありません。



次のコードは、3番目のオプションを使用してウィジェットクラスにアクセスします。 Chosenクラスの変更はプロトタイプレベルで行われます(メソッドは一般的です。つまり、変更はクラスの新しく作成されたすべてのインスタンスに影響します)。 原則として、すでに作成されたオブジェクトを展開できます(オプション1または2に従って作成されたオブジェクトを取得)が、変更がすべてのウィジェットに影響する場合は、プロトタイプを使用することをお勧めします。



jQueryウィジェットバージョンのメイン拡張コード


( function ($, ChosenClass) {

var dynamicItemInstance;



function DynamicItem(chosenInstance) {

$(( this .chosen = chosenInstance).search_results).parent().prepend(

this .elContainer = $( document .createElement( 'div' )));

this .elContainer.addClass( 'chzn-results-additemcontainer' );

this .elContainer.append( this .elButton = $( document .createElement( 'button' )));

this .elButton.click($.proxy( this .addNewItem, this ));

}

DynamicItem.prototype = {

constructor: DynamicItem,

show: function () {

var data = this .chosen.results_data,

text = this .text,

isNotSelected = true ;



if ( this .chosen.choices) {

( this .chosen.search_choices.find( "li.search-choice" ).each( function (el) {

var itemIdx = this .id.substr( this .id.lastIndexOf( "_" ) + 1),

item = data[itemIdx];



if (item.value === text) {

isNotSelected = !isNotSelected;

return false ;

}

}));

}



this .elContainer[isNotSelected ? 'show' : 'hide' ]();

},

update: function (terms) {

if (( this .text = terms).length) {

this .elButton.text( 'Add new item "' + this .text + '"' );

this .show();

} else {

this .elContainer.hide();

}

},

addNewItem: function (terms) {

this .chosen.form_field.options.add( new Option( this .text, this .text));

this .chosen.form_field_jq.trigger( 'liszt:updated' );

this .chosen.result_highlight = this .chosen.search_results.children().last();

return this .chosen.result_select();

}

};



$.extend(ChosenClass.prototype, {

no_results: ( function (fnSuper) {

return function (terms) {

(dynamicItemInstance || (dynamicItemInstance = new DynamicItem( this ))).update(terms);

return fnSuper.call( this , terms);

};

})(ChosenClass.prototype.no_results),

results_hide: ( function (fnSuper) {

return function () {

dynamicItemInstance && dynamicItemInstance.elContainer.hide();

return fnSuper.call( this );

};

})(ChosenClass.prototype.results_hide),

winnow_results_set_highlight: ( function (fnSuper) {

return function () {

dynamicItemInstance && dynamicItemInstance.elContainer.hide();

return fnSuper.apply( this , arguments);

};

})(ChosenClass.prototype.winnow_results_set_highlight)

});

})(jQuery, jQuery.fn.chosenClass());



* This source code was highlighted with Source Code Highlighter .






ウィジェットのソースコードを少し分析した後、位置の動的な追加を実装する方法を見つけました。 選択されたメソッドは、クロージャーを使用してオーバーライドされます。クロージャーは、別のクラスに位置を追加する機能です。 もちろん、必要に応じて、ボタンをリンクに置き換えたり、CSSスタイルを追加したりできます(マーキングクラスはボタンブロックにインストールされます)。



デモ



プロトタイプバージョンのバリアント



Prototypeバージョンのウィジェットでは、Chosenクラスはグローバル(window.Chosen)で利用できるため、パッチを適用するものはありませんでした。

( function (Chosen) {

var dynamicItemInstance;



function DynamicItem(chosenInstance) {

( this .chosen = chosenInstance).search_results.up().insert({

top: this .elContainer = $( document .createElement( 'div' ))

});

this .elContainer.addClassName( 'chzn-results-additemcontainer' );

this .elContainer.insert( this .elButton = $( document .createElement( 'button' )));

Event.observe( this .elButton, 'click' , this .addNewItem.bind( this ));

}

DynamicItem.prototype = {

constructor: DynamicItem,

show: function () {

var data = this .chosen.results_data,

text = this .text,

isNotSelected = true ;



if ( this .chosen.choices) {

( this .chosen.search_choices.select( "li.search-choice" ).each( function (el) {

var itemIdx = el.id.substr(el.id.lastIndexOf( "_" ) + 1),

item = data[itemIdx];



if (item.value === text) {

isNotSelected = !isNotSelected;

return false ;

}

}));

}



this .elContainer[isNotSelected ? 'show' : 'hide' ]();

},

update: function (terms) {

if (( this .text = terms).length) {

this .elButton.update( 'Add new item "' + this .text + '"' );

this .show();

} else {

this .elContainer.hide();

}

},

addNewItem: function (terms) {

this .chosen.form_field.options.add( new Option( this .text, this .text));

Event.fire( this .chosen.form_field, "liszt:updated" );

this .chosen.result_highlight = this .chosen.search_results.childElements().pop();

return this .chosen.result_select();

}

};



Chosen.prototype.no_results = ( function (fnSuper) {

return function (terms) {

(dynamicItemInstance || (dynamicItemInstance = new DynamicItem( this ))).update(terms);

return fnSuper.call( this , terms);

};

})(Chosen.prototype.no_results);

Chosen.prototype.results_hide = ( function (fnSuper) {

return function () {

dynamicItemInstance && dynamicItemInstance.elContainer.hide();

return fnSuper.call( this );

};

})(Chosen.prototype.results_hide);

Chosen.prototype.winnow_results_set_highlight = ( function (fnSuper) {

return function () {

dynamicItemInstance && dynamicItemInstance.elContainer.hide();

return fnSuper.apply( this , arguments);

};

})(Chosen.prototype.winnow_results_set_highlight);

})(window.Chosen);



new Chosen($( 'bears_multiple' ));



* This source code was highlighted with Source Code Highlighter .






デモ



備考



ウィジェットの作成者の代わりに、(Prototype / jQuery / Mootoolsの個別のバージョンではなく)共通のカーネルを実装します。 ライブラリのうち、ラッパー(インターフェイス)を介して、最も必要なメソッドのみを使用します。 これの目標は、ウィジェットのメインコードの1つの(一般的な)バージョンを持つことです。 現在、さまざまなフレームワークへの分岐の現在のアプローチでは、githubで何かをコミットすることにはあまり意味がありません。



カルマをキャストしたすべての人に感謝します。これにより、記事を公開することができました。



All Articles