examples/todomvc_fancy/js/app.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict';

milo(function() {
    var scope = milo.binder();

    // components
    var todos = scope.todos
        , newTodo = scope.newTodo
        , toggleAll = scope.toggleAll
        , clearCompletedBtn = scope.clearCompletedBtn
        , activeCounter = scope.activeCounter
        , completedCounter = scope.completedCounter
        , footer = scope.footer
        , modelView = scope.modelView;

    var storedModelDataStr = window.localStorage.getItem('todos-milo');
    var storedModelData;
    if (storedModelDataStr) storedModelData = milo.util.jsonParse(storedModelDataStr);

    var m = new milo.Model;

    // connect model to list of todos
    milo.minder(m, '<<<->>>', todos.data);
    m.on('[*]', onItemAdded);
    m.on('[*].completed', onCompleteTodo);
    m.on('**', function showModel(msg, data) {
        var modelDataStr = JSON.stringify(m.get());
        modelView.data.set(modelDataStr);
        window.localStorage.setItem('todos-milo', modelDataStr);
    });
    // set model
    m.set(storedModelData || []);
    showCounters();

    newTodo.events.on('keypress', onKeyPressed);
    toggleAll.data.on('', onToggleAll);
    clearCompletedBtn.events.on('click', onClearCompleted);

    function onKeyPressed(eventType, event) {
        if (event.keyCode == 13) addTodo();
    }

    function onToggleAll(msg, data) {
        var count = m('.length').get();
        for (var i = 0; i < count; i++)
            m('[$1].completed', i).set(data.newValue);
    }

    function onClearCompleted() {
        var i = 0, len = m('.length').get();
        while (i < len)
            if (m('[$1].completed', i).get()) {
                m.splice(i, 1);
                len--;
            } else
                i++;
        showCounters();
    }

    function addTodo() {
        var title = newTodo.data.get().trim();
        if (! title) return;
        var itemData = { title: title };
        var newCount = m.push(itemData);
        var id = newCount - 1; // push returns new length, as Array push does
        newTodo.data.set('');
    }

    function onItemAdded(msg, data) {
        _.defer(function() {
            console.log('onItemAdded', msg, data);
            if (data.type != 'added') return;
            var item = itemForPath(data.path);
            if (item) connectDeleteButton(item);
            showCounters();
        });
    }

    function connectDeleteButton(item) {
        var scope = item.container.scope; // get scope inside item
        scope.deleteBtn.events.on('click', { context: item, subscriber: removeTodo });
    }

    function onCompleteTodo(msg, data) {
        _.defer(function() {
            console.log('onCompleteTodo', msg, data);
            var item = itemForPath(data.path);
            if (item)
                item.el.classList.toggle('completed', data.newValue);
            showCounters();
        });
    }

    function itemForPath(path) {
        var id = +path.replace(/^\[([0-9]*)\].*$/, '$1');
        return todos.list.item(id);
    }

    function removeTodo(eventType, event) {
        /* jshint validthis: true */
        var id = this.data.getKey();
        m.splice(id, 1);
        showCounters();
    }

    function showCounters() {
        var list = m.get()
            , totalCount = list.length
            , activeCount = list.reduce(function(memo, item) {
                return memo + (item.completed ? 0 : 1);
            }, 0)
            , completedCount = totalCount - activeCount;

        var countView = activeCount + (activeCount == 1 ? ' item' : ' items') + ' left';
        activeCounter.data.set(countView);
        completedCounter.data.set(completedCount);
        footer.dom.toggle(totalCount);
        clearCompletedBtn.dom.toggle(completedCount);

        toggleAll.data.off('', onToggleAll);
        toggleAll.data.set(completedCount && completedCount == totalCount);
        toggleAll.data.on('', onToggleAll);
    }
});