JSFiddle - React, Tailwind, and code Playground

by sukobuto

HTML

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<form data-bind="submit:addItem">
    追加するアイテム: <input type="text" data-bind='value:itemToAdd, valueUpdate: "afterkeydown"' />
    <button type="submit" data-bind="enable: itemToAdd().length > 0">追加</button>
</form>
 
<p>レシピ</p>
<!--
<select multiple="multiple" height="5" data-bind="options:allItems, selectedOptions:selectedItems"> </select>
-->
<ul data-bind="foreach: { data: allItems,
                          afterRender: testAfterRender,
                          afterAdd: testAfterAdd,
                          beforeRemove: testBeforeRemove,
                          beforeMove: testBeforeMove,
                          afterMove: testAfterMove }">
    <li data-bind="text: $data,
                   css: { selected: $root.selectedItems.indexOf($data) > -1 },
                   click: $root.toggleSelect"></li>
</ul>
 
<div>
    <button data-bind="click: removeSelected, enable: selectedItems().length > 0">削除</button>
    <button data-bind="click: sortItems, enable: allItems().length > 1">ソート</button>
</div>

CSS

ul {
    user-select: none;
}
li {
    background: #eeeeff;
    border: solid 1px #aaaaee;
    margin: 10px;
    cursor: pointer;
}
li.selected {
    background: #ffdddd;
}

JavaScript

$(function() {        
var BetterListModel = function () {
    var self = this;

    this.itemToAdd = ko.observable("");
    this.allItems = ko.observableArray(["オリーブオイル", "パンチェッタ", "アボカド", "謎パスタ", "イタリアンパセリ", "岩塩ファサー", "追いオリーブ"]); // Initial items
    this.selectedItems = ko.observableArray(["Ham"]);                                // Initial selection
 
    this.addItem = function () {
        if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) // Prevent blanks and duplicates
            this.allItems.push(this.itemToAdd());
        this.itemToAdd(""); // Clear the text box
    };
 
    this.removeSelected = function () {
        this.allItems.removeAll(this.selectedItems());
        this.selectedItems([]); // Clear selection
    };
 
    this.sortItems = function() {
        this.allItems.sort();
    };

    this.toggleSelect = function(item, event) {
        if (event.ctrlKey) {
            if (self.selectedItems.indexOf(item) > -1) self.selectedItems.remove(item);
            else self.selectedItems.push(item);
        } else {
            self.selectedItems.removeAll();
            self.selectedItems.push(item);
        }
    };

    this.testAfterRender = function() {
        console.profile('afterRender');
        console.log(arguments);
        console.profileEnd();
    };
    this.testAfterAdd = function() {
        console.profile('afterAdd')
        console.log(arguments);
        console.profileEnd();
    };
    this.testBeforeRemove = function(element) {
        console.profile('beforeRemove');
        console.log(arguments);
        console.profileEnd();
        // beforeRemove をバインドした場合、エレメントは自動的に削除されなくなる。
        $(element).remove();
    };
    this.testBeforeMove = function() {
        console.profile('beforeMove');
        console.log(arguments);
        console.profileEnd();
    };
    this.testAfterMove = function() {
        console.profile('afterMove');
        console.log(arguments);
       ...