<commit_before>
describe('Binding: CSS classes', function() {
    beforeEach(jasmine.prepareTestNode);

    it('Should give the element the specific CSS class only when the specified value is true', function () {
        var observable1 = new ko.observable();
        var observable2 = new ko.observable(true);
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1, anotherModelProperty: observable2 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 unrelatedClass2 anotherRule");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 unrelatedClass2 anotherRule myRule");
        observable2(false);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 unrelatedClass2 myRule");
    });

    it('Should give the element a single CSS class without a leading space when the specified value is true', function() {
        var observable1 = new ko.observable();
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("myRule");
    });

    it('Should toggle multiple CSS classes if specified as a single string separated by spaces', function() {
        var observable1 = new ko.observable();
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 myRule _another-Rule123");
        observable1(false);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
    });

    it('Should set/change dynamic CSS class(es) if string is specified', function() {
        var observable1 = new ko.observable("");
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
        observable1("my-Rule");
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 my-Rule");
        observable1("another_Rule  my-Rule");
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 another_Rule my-Rule");
        observable1(undefined);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
    });

    it('Should work with any arbitrary class names', function() {
        // See https://github.com/SteveSanderson/knockout/issues/704
        var observable1 = new ko.observable();
        testNode.innerHTML = "
Something
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("complex/className complex.className");
    });

    // When there is SVG support in the browser, we want to ensure the CSS binding works with Knockout.
    //
    // According to http://caniuse.com/
    //  - IE9+ supports SVG (http://caniuse.com/#search=svg)
    //  - IE10+ supports classList (http://caniuse.com/#search=classList)
    // So we run the following test for SVG from
    // - http://stackoverflow.com/questions/4118254
    // See also:
    // - http://voormedia.com/blog/2012/10/displaying-and-detecting-support-for-svg-images
    // - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg.js
    if (document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1")) {
        it("should change the class of an SVG tag if classList is supported", function () {
            var observable = ko.observable();
            testNode.innerHTML = "<svg class='Y' data-bind='css: {x: someModelProperty}'></svg>";
            ko.applyBindings({someModelProperty: observable}, testNode);
            expect(testNode.childNodes[0].getAttribute('class')).toEqual("Y");
            observable(true);
            expect(testNode.childNodes[0].getAttribute('class')).toEqual("Y x");
        });
    }
});
<commit_msg>SVG/classList test pass for IE10+; skip for <= IE9<commit_after>
describe('Binding: CSS classes', function() {
    beforeEach(jasmine.prepareTestNode);

    it('Should give the element the specific CSS class only when the specified value is true', function () {
        var observable1 = new ko.observable();
        var observable2 = new ko.observable(true);
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1, anotherModelProperty: observable2 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 unrelatedClass2 anotherRule");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 unrelatedClass2 anotherRule myRule");
        observable2(false);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 unrelatedClass2 myRule");
    });

    it('Should give the element a single CSS class without a leading space when the specified value is true', function() {
        var observable1 = new ko.observable();
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("myRule");
    });

    it('Should toggle multiple CSS classes if specified as a single string separated by spaces', function() {
        var observable1 = new ko.observable();
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 myRule _another-Rule123");
        observable1(false);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
    });

    it('Should set/change dynamic CSS class(es) if string is specified', function() {
        var observable1 = new ko.observable("");
        testNode.innerHTML = "
Hallo
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
        observable1("my-Rule");
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 my-Rule");
        observable1("another_Rule  my-Rule");
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1 another_Rule my-Rule");
        observable1(undefined);
        expect(testNode.childNodes[0].className).toEqual("unrelatedClass1");
    });

    it('Should work with any arbitrary class names', function() {
        // See https://github.com/SteveSanderson/knockout/issues/704
        var observable1 = new ko.observable();
        testNode.innerHTML = "
Something
";
        ko.applyBindings({ someModelProperty: observable1 }, testNode);

        expect(testNode.childNodes[0].className).toEqual("");
        observable1(true);
        expect(testNode.childNodes[0].className).toEqual("complex/className complex.className");
    });

    // When there is SVG support in the browser, we want to ensure the CSS binding works with Knockout.
    //
    // According to http://caniuse.com/
    //  - IE9+ supports SVG (http://caniuse.com/#search=svg)
    //  - IE10+ supports classList (http://caniuse.com/#search=classList)
    // So we run the following test for SVG from
    // - http://stackoverflow.com/questions/4118254
    // See also:
    // - http://voormedia.com/blog/2012/10/displaying-and-detecting-support-for-svg-images
    // - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg.js
    if ('classList' in document.createElement('div')) {
        it("should change the class of an SVG tag if classList is supported", function () {
            var observable = ko.observable();
            testNode.innerHTML = "<svg class='Y' data-bind='css: {x: someModelProperty}'></svg>";
            ko.applyBindings({someModelProperty: observable}, testNode);
            expect(testNode.childNodes[0].getAttribute('class')).toEqual("Y");
            observable(true);
            expect(testNode.childNodes[0].getAttribute('class')).toEqual("Y x");
        });
    }
});
<|endoftext|>


<commit_before>import { h, render } from 'preact';
import { initDevTools } from 'preact/devtools';

import asyncComponent from 'asyncComponent';

if (module.hot) {
    require('preact/debug');
}

let App = asyncComponent(() => import(/* webpackChunkName: "app" */'./app/app.js').then(module => module.default));

const mountPoint = document.getElementById('nethloader');

render(<App />, mountPoint, mountPoint.lastChild);
<commit_msg>Remove "preact/dev-tools" improt<commit_after>import { h, render } from 'preact';

import asyncComponent from 'asyncComponent';

if (module.hot) {
    require('preact/debug');
}

let App = asyncComponent(() => import(/* webpackChunkName: "app" */'./app/app.js').then(module => module.default));

const mountPoint = document.getElementById('nethloader');

render(<App />, mountPoint, mountPoint.lastChild);
<|endoftext|>


<commit_before>var _myNewObject = null;

function onChatSend(name, desc, tag) {
    var o = objNew();
    o = o.own();
    o = objName(o, name);
    //o = objAddTag(o, 'Message');
    if (desc)
        o = objAddDescription(o, desc);
    if (tag)
        o = o.add(tag);

    $N.pub(o/*, function() {
     }, function() {
     }*/);
    _myNewObject = o;
}

function newChatView(v) {
    var oldestNewObjectMS = 10 * 60 * 1000; //10 min

    var content = v;//newDiv().addClass('ChatViewContent');
    var input = newChatInput(onChatSend).addClass('ChatViewInput');
    var updates = newDiv().addClass('ChatViewUpdates').addClass('ui-widget-content');

    //v.append(content);
    //v.append(input);
    v.append(updates);

    var nearBottom = false;
    var displayedObjects = [];
    var updatesAvailable = false;
    var newObjects = {};
    var rootsUnaffected = {};
    var modifiedDate = {};
    var changed = [];

    $(content).scroll(function() {
        var height = content.prop('scrollHeight');
        var position = content.scrollTop();
        var visible = content.height();

        if (position + visible > height - 25) {
            if (!nearBottom)
                if (updatesAvailable)
                    updateContent(true);

            nearBottom = true;
        }
        else {
            nearBottom = false;
        }
    });

    var scrollbottom = _.debounce(function() {
        content.scrollTop(content.prop('scrollHeight'));
    }, 150);
    var scrolltop = _.debounce(function() {
        content.scrollTop(0);
    }, 150);

    //TODO toggle replies
    //TODO adjust highlight history period

    function forceUpdate() {
        updateContent(true);
        //scrollbottom();
    }

    function updateContent(force) {
        var numPreviousDisplayed = displayedObjects.length;

        var sort = 'Recent';
        var scope = 'Public';
        var semantic = 'Any';
        var maxItems = 75;

        var rel = getRelevant(sort, scope, semantic, $N, maxItems);
        var toDisplay = rel[0];
        var toDisplayObj = {};
        toDisplay.forEach(function(d) {
            toDisplayObj[d] = $N.object[d];
        });

        var toDisplayWithReplies = $N.getAllReplies(toDisplay);

        var added = _.difference(toDisplayWithReplies, displayedObjects);
        var removed = _.difference(displayedObjects, toDisplayWithReplies);
        var newlyChanged = _.filter(toDisplayWithReplies, function(D) {
            var dd = D.modifiedAt || D.createdAt;
            var c = false;
            if (modifiedDate[D.id]) {
                if (modifiedDate[D.id] === dd) {
                    c = false;
                }
                else {
                    c = true;
                }
            }
            modifiedDate[D.id] = dd;
            return c;
        });

        changed = _.union(changed, newlyChanged);

        if (!force) {
            if ((added.length === 0) && (removed.length === 0) && (changed.length === 0)) {
                updatesAvailable = false;
                updates.hide();
                return;
            }
            else if (!nearBottom) {
                //buffer changes
                updatesAvailable = true;

                updates.html('Updates available.
');
                var updateButton = $('<button>Update</button>').click(forceUpdate).appendTo(updates);
                updates.fadeIn();

                return;
            }
            else if (nearBottom) {
                var addedContainsReplies = false;
                for (var i = 0; i < added.length; i++) {
                    var A = $N.getObject(added[i]);
                    if (A) {
                        if (A.replyTo) {
                            addedContainsReplies = true;
                            break;
                        }
                    }
                }
                if (addedContainsReplies) {
                    updates.html('Replies available.
');
                    var updateButton = $('<button>Update</button>').click(forceUpdate).appendTo(updates);
                    updates.fadeIn();
                    return;
                }
            }
        }

        updates.hide();

        var rootsAffected = null;

        if (numPreviousDisplayed != 0) {
            rootsAffected = {};
            _.union(added, removed, changed).forEach(function(c) {
                var roots = $N.getReplyRoots(c);
                roots.forEach(function(r) {
                    rootsAffected[r] = true;

                    //affected, so remove from cache
                    if (rootsUnaffected[r]) {
                        rootsUnaffected[r].remove();
                        delete rootsUnaffected[r];
                    }
                });
            });
            content.find('.objectView').each(function() {
                var xid = $(this).data('xid');
                var X = toDisplayObj[xid];

                if (!X)
                    return;
                if (X.replyTo)
                    return;

                if (!rootsAffected[xid])
                    rootsUnaffected[xid] = $(this).parent().parent().detach();
            });
        }

        content.empty();

        if (toDisplay.length === 0) {
            content.html('No messages.');
            return;
        }

        displayedObjects = [];

        for (var i = toDisplay.length - 1; i >= 0; i--) {
            var td = toDisplay[i];
            if (rootsUnaffected[td]) {
                content.append(rootsUnaffected[td]);
            }
            else {
                var x = $N.getObject(td);
                content.append(newObjectLogLine(x));
            }
        }

        var now = Date.now();
        if (numPreviousDisplayed != 0) {
            _.each(newObjects, function(v, k) {
                if (now - v > oldestNewObjectMS)
                    delete newObjects[k];
            });
            _.union(added, changed).forEach(function(a) {
                newObjects[a] = now;
            });
        }

        content.find('.objectView').each(function() {
            var xid = $(this).data('xid');
            displayedObjects.push(xid);

            var when = newObjects[xid];
            if (!when) {
                var O = toDisplayObj[xid] || $N.getObject(xid);
                if (O)
                    when = O.modifiedAt || O.createdAt;
            }
            if (when) {
                var age = now - when;
                if (age < oldestNewObjectMS) {
                    age /= oldestNewObjectMS;
                    var c = 'rgba(0,255,0,' + 0.2 * (1.0 - age) + ');';
                    var highlightStyle = 'background-color: ' + c + '; border-right: 4px solid ' + c;
                    $(this).attr('style', highlightStyle);
                }
            }
        });

        updatesAvailable = false;
        changed = [];

        if (force)
            if (typeof force != "boolean") {
                var scrollToObject = force;
                //existing scroll position should be good if it's a reply
                if (scrollToObject.replyTo)
                    return;
            }

        //later(scrollbottom);
    }

    function updateFocus() {
        _myNewObject = $N.focus();
    }

    $N.on('change:focus', updateFocus);

    content.onChange = function() {
        later(function() {
            updateContent(_myNewObject);
            _myNewObject = null;
        })
    };

    content.destroy = function() {
        _.values(rootsUnaffected).forEach(function(x) {
            x.remove();
        }); //destroy the DOM cache
        $N.off('change:focus', updateFocus);

        _myNewObject = null;
        displayedObjects = null;
        newObjects = null;
        rootsUnaffected = null;
        modifiedDate = null;
        changed = null;

    };

    updateContent(true);

    setTimeout(function() {
        later(scrollbottom);
    },500);

    var viewMenu = $('#ViewMenu');
    $('<button title="Scroll to Top">↑</button>').appendTo(viewMenu).click(scrolltop);
    $('<button title="Scroll to Bottom">↓</button>').appendTo(viewMenu).click(scrollbottom);
    viewMenu.append(input.children());

    return content;
}

function newInlineSelfButton(s) {
    return newEle('a').data({
        'aid': s.id
    }).addClass('InlineSelfButton')
      .append(newAvatarImage(s), newEle('div').html(s.name));
}

function newObjectLogLineOnHover() {
    $(this).addClass('ChatViewContentLineHover');
}
function newObjectLogLineOffHover() {
    $(this).removeClass('ChatViewContentLineHover');
}
function newObjectLogLineClick() {
    var author = $(this).data('aid');
    newPopupObjectView(author);
}

function lineClickFunction() {
    var line = $(this);

    var e = $(line.children()[1]);

    var x = $N.getObject(line.data('xid'));

    function showFull() {
        var s = newObjectView(x, {
            showActionPopupButton: false,
            showSelectionCheck: false,
            transparent: true
        });
        s.hide();

        e.append(s);

    }

    e.empty();
    if (showingMini) {
        showFull();
    }
    else {
        showMini();
    }

}

function defaultChatReplyCallback(r) {
    _myNewObject = r;
}

function newObjectLogLine(x) {
    var line = newEle('div').addClass('ChatViewContentLine').data('xid', x.id);

    if (configuration.device == configuration.DESKTOP)
        line.hover(newObjectLogLineOnHover, newObjectLogLineOffHover);

    var d = newDiv().addClass('chatViewLineAuthor').appendTo(line);
    var e = newDiv().addClass('chatViewLineContent').appendTo(line);

    var s = newObjectView(x, {
        showActionPopupButton: false,
        showSelectionCheck: false,
        transparent: true,
        hideAuthorNameAndIconIfZeroDepth: true,
        replyCallback: defaultChatReplyCallback,
        startMinimized: true
    }).appendTo(e);

    if (x.author) {
        var author = $N.instance[x.author];
        if (author) {
            b = newInlineSelfButton(author);
        }
        else {
            b = newEle('a').text(x.author).data({'aid': x.author});
        }
        b.click(newObjectLogLineClick);
        d.append(b);
    }
    else {
        d.append(' ');
    }

    return line;
}

function newChatInput(onSend) {
    var d = newDiv();

    var inputBar = $('<input placeholder="Chat" x-webkit-speech/>');
    inputBar.keyup(function(event) {
        if (event.keyCode === 13) {
            if (onSend)
                onSend(inputBar.val());
            inputBar.val('');
        }

    });
    d.append(inputBar);

    var webcamButton = $('<button title="Add Webcam..."></button>');
    webcamButton.click(function() {
        newWebcamWindow(function(imgURL) {
            if (onSend)
                onSend(inputBar.val(), null, {id: 'gif', value: imgURL});
            inputBar.val('');
        });
    });
    d.append(webcamButton);

    var moreButton = $('<button title="Add Detailed Object...">..</button>');
    moreButton.click(function() {
        var n = objNew();
        n.setName(inputBar.val());
        inputBar.val('');
        newPopupObjectEdit(n);
    });
    d.append(moreButton);

    return d;
}
<commit_msg>chat showing green highlight again<commit_after>var _myNewObject = null;

function onChatSend(name, desc, tag) {
    var o = objNew();
    o = o.own();
    o = objName(o, name);
    //o = objAddTag(o, 'Message');
    if (desc)
        o = objAddDescription(o, desc);
    if (tag)
        o = o.add(tag);

    $N.pub(o/*, function() {
     }, function() {
     }*/);
    _myNewObject = o;
}

function newChatView(v) {
    var oldestNewObjectMS = 10 * 60 * 1000; //10 min

    var content = v;//newDiv().addClass('ChatViewContent');
    var input = newChatInput(onChatSend).addClass('ChatViewInput');
    var updates = newDiv().addClass('ChatViewUpdates').addClass('ui-widget-content');

    //v.append(content);
    //v.append(input);
    v.append(updates);

    var nearBottom = false;
    var displayedObjects = [];
    var updatesAvailable = false;
    var newObjects = {};
    var rootsUnaffected = {};
    var modifiedDate = {};
    var changed = [];

    $(content).scroll(function() {
        var height = content.prop('scrollHeight');
        var position = content.scrollTop();
        var visible = content.height();

        if (position + visible > height - 25) {
            if (!nearBottom)
                if (updatesAvailable)
                    updateContent(true);

            nearBottom = true;
        }
        else {
            nearBottom = false;
        }
    });

    var scrollbottom = _.debounce(function() {
        content.scrollTop(content.prop('scrollHeight'));
    }, 150);
    var scrolltop = _.debounce(function() {
        content.scrollTop(0);
    }, 150);

    //TODO toggle replies
    //TODO adjust highlight history period

    function forceUpdate() {
        updateContent(true);
        //scrollbottom();
    }

    function updateContent(force) {
        var numPreviousDisplayed = displayedObjects.length;

        var sort = 'Recent';
        var scope = 'Public';
        var semantic = 'Any';
        var maxItems = 75;

        var rel = getRelevant(sort, scope, semantic, $N, maxItems);
        var toDisplay = rel[0];
        var toDisplayObj = {};
        toDisplay.forEach(function(d) {
            toDisplayObj[d] = $N.object[d];
        });

        var toDisplayWithReplies = $N.getAllReplies(toDisplay);

        var added = _.difference(toDisplayWithReplies, displayedObjects);
        var removed = _.difference(displayedObjects, toDisplayWithReplies);
        var newlyChanged = _.filter(toDisplayWithReplies, function(D) {
            var dd = D.modifiedAt || D.createdAt;
            var c = false;
            if (modifiedDate[D.id]) {
                if (modifiedDate[D.id] === dd) {
                    c = false;
                }
                else {
                    c = true;
                }
            }
            modifiedDate[D.id] = dd;
            return c;
        });

        changed = _.union(changed, newlyChanged);

        if (!force) {
            if ((added.length === 0) && (removed.length === 0) && (changed.length === 0)) {
                updatesAvailable = false;
                updates.hide();
                return;
            }
            else if (!nearBottom) {
                //buffer changes
                updatesAvailable = true;

                updates.html('Updates available.
');
                var updateButton = $('<button>Update</button>').click(forceUpdate).appendTo(updates);
                updates.fadeIn();

                return;
            }
            else if (nearBottom) {
                var addedContainsReplies = false;
                for (var i = 0; i < added.length; i++) {
                    var A = $N.getObject(added[i]);
                    if (A) {
                        if (A.replyTo) {
                            addedContainsReplies = true;
                            break;
                        }
                    }
                }
                if (addedContainsReplies) {
                    updates.html('Replies available.
');
                    var updateButton = $('<button>Update</button>').click(forceUpdate).appendTo(updates);
                    updates.fadeIn();
                    return;
                }
            }
        }

        updates.hide();

        var rootsAffected = null;

        if (numPreviousDisplayed != 0) {
            rootsAffected = {};
            _.union(added, removed, changed).forEach(function(c) {
                var roots = $N.getReplyRoots(c);
                roots.forEach(function(r) {
                    rootsAffected[r] = true;

                    //affected, so remove from cache
                    if (rootsUnaffected[r]) {
                        rootsUnaffected[r].remove();
                        delete rootsUnaffected[r];
                    }
                });
            });
            content.find('.objectView').each(function() {
                var xid = $(this).data('xid');
                var X = toDisplayObj[xid];

                if (!X)
                    return;
                if (X.replyTo)
                    return;

                if (!rootsAffected[xid])
                    rootsUnaffected[xid] = $(this).parent().parent().detach();
            });
        }

        content.empty();

        if (toDisplay.length === 0) {
            content.html('No messages.');
            return;
        }

        displayedObjects = [];

        for (var i = toDisplay.length - 1; i >= 0; i--) {
            var td = toDisplay[i];
            if (rootsUnaffected[td]) {
                content.append(rootsUnaffected[td]);
            }
            else {
                var x = $N.getObject(td);
                content.append(newObjectLogLine(x));
            }
        }

        var now = Date.now();
        if (numPreviousDisplayed != 0) {
            _.each(newObjects, function(v, k) {
                if (now - v > oldestNewObjectMS)
                    delete newObjects[k];
            });
            _.union(added, changed).forEach(function(a) {
                newObjects[a] = now;
            });
        }

        content.find('.objectView').each(function() {
            var xid = $(this).data('xid');
            displayedObjects.push(xid);

            var when = newObjects[xid];
            if (!when) {
                var O = toDisplayObj[xid] || $N.instance[xid];
                if (O)
                    when = O.modifiedAt || O.createdAt;
            }
            if (when) {
                var age = now - when;
                if (age < oldestNewObjectMS) {
                    age /= oldestNewObjectMS;
                    var c = 'rgba(0,255,0,' + 0.2 * (1.0 - age) + ');';
                    var highlightStyle = 'background-color: ' + c + '; border-right: 4px solid ' + c;
                    $(this).attr('style', highlightStyle);
                }
            }
        });

        updatesAvailable = false;
        changed = [];

        if (force)
            if (typeof force != "boolean") {
                var scrollToObject = force;
                //existing scroll position should be good if it's a reply
                if (scrollToObject.replyTo)
                    return;
            }

        //later(scrollbottom);
    }

    function updateFocus() {
        _myNewObject = $N.focus();
    }

    $N.on('change:focus', updateFocus);

    content.onChange = function() {
        later(function() {
            updateContent(_myNewObject);
            if (_myNewObject)
                scrollbottom();
            _myNewObject = null;
        })
    };

    content.destroy = function() {
        _.values(rootsUnaffected).forEach(function(x) {
            x.remove();
        }); //destroy the DOM cache
        $N.off('change:focus', updateFocus);

        _myNewObject = null;
        displayedObjects = null;
        newObjects = null;
        rootsUnaffected = null;
        modifiedDate = null;
        changed = null;

    };

    updateContent(true);

    setTimeout(function() {
        later(scrollbottom);
    },500);

    var viewMenu = $('#ViewMenu');
    $('<button title="Scroll to Top">↑</button>').appendTo(viewMenu).click(scrolltop);
    $('<button title="Scroll to Bottom">↓</button>').appendTo(viewMenu).click(scrollbottom);
    viewMenu.append(input.children());

    return content;
}

function newInlineSelfButton(s) {
    return newEle('a').data({
        'aid': s.id
    }).addClass('InlineSelfButton')
      .append(newAvatarImage(s), newEle('div').html(s.name));
}

function newObjectLogLineOnHover() {
    $(this).addClass('ChatViewContentLineHover');
}
function newObjectLogLineOffHover() {
    $(this).removeClass('ChatViewContentLineHover');
}
function newObjectLogLineClick() {
    var author = $(this).data('aid');
    newPopupObjectView(author);
}

function lineClickFunction() {
    var line = $(this);

    var e = $(line.children()[1]);

    var x = $N.getObject(line.data('xid'));

    function showFull() {
        var s = newObjectView(x, {
            showActionPopupButton: false,
            showSelectionCheck: false,
            transparent: true
        });
        s.hide();

        e.append(s);

    }

    e.empty();
    if (showingMini) {
        showFull();
    }
    else {
        showMini();
    }

}

function defaultChatReplyCallback(r) {
    _myNewObject = r;
}

function newObjectLogLine(x) {
    var line = newEle('div').addClass('ChatViewContentLine').data('xid', x.id);

    if (configuration.device == configuration.DESKTOP)
        line.hover(newObjectLogLineOnHover, newObjectLogLineOffHover);

    var d = newDiv().addClass('chatViewLineAuthor').appendTo(line);
    var e = newDiv().addClass('chatViewLineContent').appendTo(line);

    var s = newObjectView(x, {
        showActionPopupButton: false,
        showSelectionCheck: false,
        transparent: true,
        hideAuthorNameAndIconIfZeroDepth: true,
        replyCallback: defaultChatReplyCallback,
        startMinimized: true
    }).data('xid', x.id).appendTo(e);

    if (x.author) {
        var author = $N.instance[x.author];
        if (author) {
            b = newInlineSelfButton(author);
        }
        else {
            b = newEle('a').text(x.author).data({'aid': x.author});
        }
        b.click(newObjectLogLineClick);
        d.append(b);
    }
    else {
        d.append(' ');
    }

    return line;
}

function newChatInput(onSend) {
    var d = newDiv();

    var inputBar = $('<input placeholder="Chat" x-webkit-speech/>');
    inputBar.keyup(function(event) {
        if (event.keyCode === 13) {
            if (onSend)
                onSend(inputBar.val());
            inputBar.val('');
        }

    });
    d.append(inputBar);

    var webcamButton = $('<button title="Add Webcam..."></button>');
    webcamButton.click(function() {
        newWebcamWindow(function(imgURL) {
            if (onSend)
                onSend(inputBar.val(), null, {id: 'gif', value: imgURL});
            inputBar.val('');
        });
    });
    d.append(webcamButton);

    var moreButton = $('<button title="Add Detailed Object...">..</button>');
    moreButton.click(function() {
        var n = objNew();
        n.setName(inputBar.val());
        inputBar.val('');
        newPopupObjectEdit(n);
    });
    d.append(moreButton);

    return d;
}
<|endoftext|>


<commit_before>require('./spec_helper.js');

describe('Delete', function() {
  var deleter;
  var recordType = 'inventoryitem';
  var idList     = ['123', '456', '789'];
  global.nlapiDeleteRecord = function() {};

  beforeEach(function() {
    deleter = new Deleter(recordType, idList);
    spyOn(global, 'nlapiDeleteRecord').andReturn(null);
  });

  describe('#init', function() {
    it("should set the record type", function() {
      expect(deleter.recordType).toEqual(recordType);
    });
  });

  describe('#deleteRecords', function() {

  });

  describe('#reply', function() {
  });
});
<commit_msg>Finish initial tests for delete.js<commit_after>require('./spec_helper.js');

describe('Delete', function() {
  var deleter;
  var recordType = 'inventoryitem';
  var idList     = ['123', '456', '789'];
  global.nlapiDeleteRecord = function() {};

  beforeEach(function() {
    deleter = new Deleter(recordType, idList);
    spyOn(global, 'nlapiDeleteRecord').andReturn(null);
  });

  describe('#init', function() {
    it("should set the record type", function() {
      expect(deleter.recordType).toEqual(recordType);
    });
  });

  describe('#deleteRecords', function() {
    it("should call the Netsuite deletion function", function() {
      expect(global.nlapiDeleteRecord).toHaveBeenCalled();
    });

    it("should have an equal count between the replyList and idList", function() {
      expect(deleter.replyList.length).toEqual(deleter.idList.length);
    });
  });

  describe('#addFormattedReply', function() {
    beforeEach(function() {
      deleter.deleteRecords();
      this.missing = false;
    });

    it("should have an equal element count between idList and replyList", function() {
      expect(deleter.idList.length).toEqual(deleter.replyList.length);
    });

    it("should have a params key for each reply element", function() {
      for(index in deleter.replyList) {
        if(!deleter.replyList[index].hasOwnProperty('params') && !this.missing) {
          this.missing = true;
        }
      }

      expect(this.missing).toEqual(false);
    });

    it("should have a result key for each reply element", function() {
      for(index in deleter.replyList) {
        if(!deleter.replyList[index].hasOwnProperty('result') && !this.missing) {
          this.missing = true;
        }
      }
      expect(this.missing).toEqual(false);
    });

    it("should have a success key for each reply element", function() {
      for(index in deleter.replyList) {
        if(!deleter.replyList[index].hasOwnProperty('success') && !this.missing) {
          this.missing = true;
        }
      }
      expect(this.missing).toEqual(false);
    });
  });

  describe('#reply', function() {
    beforeEach(function() {
      deleter.deleteRecords();
    });

    it("should return the replyList", function() {
      expect(deleter.reply()).toEqual(deleter.replyList);
    });
  });
});
<|endoftext|>


<commit_before>describe('FlindersTimetable clash service', function () {
    var clashService;

    beforeEach(module('flindersTimetable.timetable'));
    beforeEach(inject(function ($injector) {
        clashService = $injector.get('clashService');
    }));

    it('should be defined', inject(function () {
        expect(clashService).toBeDefined();
    }));

    it('should detect a session clashes with itself', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 PM",
            timeEndsAt: "1:50 PM",
            secondsStartsAt: 43200,
            secondsEndsAt: 49800,
            secondsDuration: 6600,
            room: null
        };

        expect(clashService.sessionsClash(a, a)).toBeTruthy();
    });

    it('should detect no clash for two identical sessions on different days', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 PM",
            timeEndsAt: "1:50 PM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        var b = {
            firstDay: "2013-08-07",
            lastDay: "2013-11-06",
            dayOfWeek: "Wednesday",
            timeStartsAt: "12:00 PM",
            timeEndsAt: "1:50 PM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        expect(clashService.sessionsClash(a, b)).toBeFalsy();
    });

    it('should detect no clash for two successive sessions', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 AM",
            timeEndsAt: "12:10 AM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        var b = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:10 AM",
            timeEndsAt: "12:20 AM",
            secondsStartsAt: 600,
            secondsEndsAt: 1200,
            secondsDuration: 600,
            room: null
        };

        expect(clashService.sessionsClash(a, b)).toBeFalsy();
    });

    it('should detect no clash for two completely discrete sessions', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 AM",
            timeEndsAt: "12:10 AM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        var b = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:20 AM",
            timeEndsAt: "12:30 AM",
            secondsStartsAt: 1200,
            secondsEndsAt: 1800,
            secondsDuration: 600,
            room: null
        };

        expect(clashService.sessionsClash(a, b)).toBeFalsy();
    });
});

describe('FlindersTimetable dayService', function () {
    var dayService;

    beforeEach(module('flindersTimetable.timetable'));
    beforeEach(inject(function ($injector) {
        dayService = $injector.get('dayService');
    }));

    it('should have a dummy test', inject(function () {
        expect(true).toBeTruthy();
    }));

    it('should convert day names to integers correctly', function () {
        expect(dayService.dayOfWeekToDayName(0)).toBe("Monday");
        expect(dayService.dayOfWeekToDayName(1)).toBe("Tuesday");
        expect(dayService.dayOfWeekToDayName(2)).toBe("Wednesday");
        expect(dayService.dayOfWeekToDayName(3)).toBe("Thursday");
        expect(dayService.dayOfWeekToDayName(4)).toBe("Friday");
    });

    it('should work symmetrically between dayOfWeekToDayName and dayNameToDayOfWeek', function () {
        for (var i = 0; i < 5; i++) {
            expect(dayService.dayNameToDayOfWeek(dayService.dayOfWeekToDayName(i))).toBe(i);
        }
    });

});

describe('flindersTimetable TopicController', function () {
    var scope;
    var topicController;

    beforeEach(module('flindersTimetable.timetable'));
    beforeEach(inject(function ($rootScope, $controller, $injector) {
        scope = $rootScope.$new();
        //topicFactory bypass
        var topicFactory = {};
        topicController = $controller('TopicController', {$scope: scope, chosenTopicService: $injector.get('chosenTopicService'), topicFactory: topicFactory, urlService: $injector.get('urlService')});
    }));

    it('should have a dummy test', inject(function() {
        expect(true).toBeTruthy();
    }));

    it('should define scope', function () {
        expect(scope).toBeDefined();
    });

});<commit_msg>simple error tests added<commit_after>describe('FlindersTimetable clash service', function () {
    var clashService;

    beforeEach(module('flindersTimetable.timetable'));
    beforeEach(inject(function ($injector) {
        clashService = $injector.get('clashService');
    }));

    it('should be defined', inject(function () {
        expect(clashService).toBeDefined();
    }));

    it('should detect a session clashes with itself', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 PM",
            timeEndsAt: "1:50 PM",
            secondsStartsAt: 43200,
            secondsEndsAt: 49800,
            secondsDuration: 6600,
            room: null
        };

        expect(clashService.sessionsClash(a, a)).toBeTruthy();
    });

    it('should detect no clash for two identical sessions on different days', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 PM",
            timeEndsAt: "1:50 PM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        var b = {
            firstDay: "2013-08-07",
            lastDay: "2013-11-06",
            dayOfWeek: "Wednesday",
            timeStartsAt: "12:00 PM",
            timeEndsAt: "1:50 PM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        expect(clashService.sessionsClash(a, b)).toBeFalsy();
    });

    it('should detect no clash for two successive sessions', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 AM",
            timeEndsAt: "12:10 AM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        var b = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:10 AM",
            timeEndsAt: "12:20 AM",
            secondsStartsAt: 600,
            secondsEndsAt: 1200,
            secondsDuration: 600,
            room: null
        };

        expect(clashService.sessionsClash(a, b)).toBeFalsy();
    });

    it('should detect no clash for two completely discrete sessions', function () {
        var a = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:00 AM",
            timeEndsAt: "12:10 AM",
            secondsStartsAt: 0,
            secondsEndsAt: 600,
            secondsDuration: 600,
            room: null
        };

        var b = {
            firstDay: "2013-08-06",
            lastDay: "2013-11-05",
            dayOfWeek: "Tuesday",
            timeStartsAt: "12:20 AM",
            timeEndsAt: "12:30 AM",
            secondsStartsAt: 1200,
            secondsEndsAt: 1800,
            secondsDuration: 600,
            room: null
        };

        expect(clashService.sessionsClash(a, b)).toBeFalsy();
    });
});

describe('FlindersTimetable dayService', function () {
    var dayService;

    beforeEach(module('flindersTimetable.timetable'));
    beforeEach(inject(function ($injector) {
        dayService = $injector.get('dayService');
    }));

    it('should have a dummy test', inject(function () {
        expect(true).toBeTruthy();
    }));

    it('should convert day names to integers correctly', function () {
        expect(dayService.dayOfWeekToDayName(0)).toBe("Monday");
        expect(dayService.dayOfWeekToDayName(1)).toBe("Tuesday");
        expect(dayService.dayOfWeekToDayName(2)).toBe("Wednesday");
        expect(dayService.dayOfWeekToDayName(3)).toBe("Thursday");
        expect(dayService.dayOfWeekToDayName(4)).toBe("Friday");
    });

    it('should work symmetrically between dayOfWeekToDayName and dayNameToDayOfWeek', function () {
        for (var i = 0; i < 5; i++) {
            expect(dayService.dayNameToDayOfWeek(dayService.dayOfWeekToDayName(i))).toBe(i);
        }
    });

});

describe('flindersTimetable TopicController', function () {
    var scope;
    var topicController;

    beforeEach(module('flindersTimetable.timetable'));
    beforeEach(inject(function ($rootScope, $controller, $injector) {
        scope = $rootScope.$new();
        //topicFactory bypass
        var topicFactory = {getTopicsAsync: function() {},
            getTopicAsync: function() {},
            createTopicFromUniqueTopicCode: function() {},
            loadTopicFromSerialAsync: function() {},
            loadTimetableForTopicAsync: function() {}
        };
        topicController = $controller('TopicController', {$scope: scope, chosenTopicService: $injector.get('chosenTopicService'), topicFactory: topicFactory, urlService: $injector.get('urlService')});
    }));

    it('should have a dummy test', inject(function() {
        expect(true).toBeTruthy();
    }));

    it('should define scope', function () {
        expect(scope).toBeDefined();
    });

    it('should define searchTopics', function() {
        expect(scope.searchTopics).toBeDefined();
    });

    it('should define topicSearch', function() {
        expect(scope.topicSearch).toBeDefined();
    });

    it('topicSearch of \'\' should return all members of the list', function() {
        scope.topicSearch = '';
        var topicArray = [];
        for (var i = 0; i < 10; i++) {
            topicArray.push({name: "topic" + i, code: "ENGR000"});
        }
        expect(topicArray.length).toBe(10);
        topicArray.filter(scope.searchTopics);
        expect(topicArray.length).toBe(10);
    });

});<|endoftext|>


<commit_before>(function() {
  'use strict';

  var app = angular.module('radar.ui');

  var DEFAULT_SORT_BY = 'id';
  var DEFAULT_PER_PAGE = 10;

  app.directive('listHelper', ['$parse', '_', 'escapeRegExp', 'dateSearch', 'anyValue', function($parse, _, escapeRegExp, dateSearch, anyValue) {
    return {
      scope: false,
      controller: ['$scope', '$attrs', function($scope, $attrs) {
        var self = this;

        var listHelper = $attrs.listHelper;
        var match = /\s*(\S+)\s+as\s+(\S+)\s*/.exec(listHelper);

        if (match) {
          var collectionExpression = match[1];
          var aliasExpression = match[2];

          var collectionGetter = $parse(collectionExpression);
          var aliasSetter = $parse(aliasExpression).assign;

          client(collectionGetter, aliasSetter);
        } else {
          var paramsGetter = $parse(listHelper);
          server(paramsGetter);
        }

        function client(collectionGetter, aliasSetter) {
          aliasSetter($scope, self);

          var options = $parse($attrs.listHelperOptions)($scope) || {};
          var deep = options.deep !== false;
          var perPage = options.perPage || DEFAULT_PER_PAGE;
          var reverse = options.reverse === true;
          var sortBy = options.sortBy || DEFAULT_SORT_BY;
          var sortId = options.sortId || sortBy;

          var items = [];
          var filteredItems = [];
          var sortedItems = [];
          var paginatedItems = [];
          var sortScope = $scope;
          var search = '';
          var page = 1;

          $scope.$watchCollection(function() {
            return collectionGetter($scope) || [];
          }, function(value) {
            items = value;
            _filter();
          });

          $scope.$watch('items', function() {
            _filter();
          }, deep);

          _filter();

          self.sort = sort;
          self.filter = filter;
          self.getSortBy = getSortBy;
          self.getReverse = getReverse;
          self.getSortId = getSortId;
          self.getPage = getPage;
          self.setPage = setPage;
          self.getPerPage = getPerPage;
          self.setPerPage = setPerPage;
          self.getTotalPages = getTotalPages;
          self.getCount = getCount;
          self.getItems = getItems;

          function sort(newSortBy, newReverse, newSortId, newSortScope) {
            sortBy = newSortBy;
            reverse = newReverse;
            sortId = newSortId;
            sortScope = newSortScope;
            page = 1;
            _sort();
          }

          function filter(newSearch) {
            search = newSearch;
            page = 1;
            _filter();
          }

          function getSortId() {
            return sortId;
          }

          function getSortBy() {
            return sortBy;
          }

          function getReverse() {
            return reverse;
          }

          function getPage() {
            return page;
          }

          function setPage(newPage) {
            page = newPage;
            _paginate();
          }

          function getPerPage() {
            return perPage;
          }

          function setPerPage(newPerPage) {
            perPage = newPerPage;
            _paginate();
          }

          function getTotalPages() {
            return Math.ceil(filteredItems.length / perPage);
          }

          function getCount() {
            return filteredItems.length;
          }

          function getItems() {
            return paginatedItems;
          }

          function _filter() {
            filteredItems = items;

            if (search) {
              var searchRegExp = new RegExp(escapeRegExp(search.trim()), 'i');
              var searchMatcher = function(value) {
                return searchRegExp.test(value);
              };

              var dateMatcher = dateSearch(search);

              var matcher = function(value) {
                return searchMatcher(value) || dateMatcher(value);
              };

              filteredItems = _.filter(filteredItems, function(x) {
                return anyValue(x.getData(), matcher);
              });
            }

            _sort();
          }

          function _sort() {
            sortedItems = filteredItems;

            if (sortBy !== null) {
              var getter = $parse(sortBy);

              sortedItems = _.sortBy(sortedItems, function(item) {
                // Note: AngularJS doesn't check the prototype of the locals argument
                return getter(item, sortScope);
              });
            }

            if (reverse) {
              sortedItems.reverse();
            }

            _paginate();
          }

          function _paginate() {
            if (perPage === null) {
              paginatedItems = sortedItems;
            } else {
              var startIndex = (page - 1) * perPage;
              var endIndex = page * perPage;
              paginatedItems = _.slice(sortedItems, startIndex, endIndex);
            }

          }
        }

        function server(apiGetter) {
          var api = apiGetter($scope);

          $scope.$watch(function() {
            return apiGetter($scope);
          }, function(value) {
            api = value;
          });

          self.sort = sort;
          self.getSortBy = getSortBy;
          self.getReverse = getReverse;
          self.getSortId = getSortId;
          self.getPage = getPage;
          self.setPage = setPage;
          self.getPerPage = getPerPage;
          self.setPerPage = setPerPage;
          self.getTotalPages = getTotalPages;
          self.getCount = getCount;
          self.getItems = getItems;

          function sort(sortBy, reverse) {
            if (api) {
              api.sort(sortBy, reverse);
            }
          }

          function getSortId() {
            return getSortBy();
          }

          function getSortBy() {
            return api ? api.getSortBy() : 'id';
          }

          function getReverse() {
            return api ? api.getReverse() : false;
          }

          function getPage() {
            return api ? api.getPage() : 1;
          }

          function setPage(page) {
            if (api) {
              api.setPage(page);
            }
          }

          function getPerPage() {
            return api ? api.getPerPage() : DEFAULT_PER_PAGE;
          }

          function setPerPage(perPage) {
            if (api) {
              api.setPerPage(perPage);
            }
          }

          function getTotalPages() {
            return api ? api.getTotalPages() : 0;
          }

          function getCount() {
            return api ? api.getCount() : 0;
          }

          function getItems() {
            return api ? api.getItems() : [];
          }
        }
      }]
    };
  }]);

  app.factory('ListHelperProxy', function() {
    function ListHelperProxy(callback, params) {
      this.items = [];
      this.count = 0;

      this.page = 1;
      this.perPage = DEFAULT_PER_PAGE;

      this.sortBy = 'id';
      this.reverse = false;

      this.callback = callback;

      if (params) {
        if (params.perPage) {
          this.perPage = params.perPage;
        }

        if (params.sortBy) {
          this.sortBy = params.sortBy;
        }

        if (params.reverse) {
          this.reverse = params.reverse;
        }
      }

      this.lastParams = null;
    }

    ListHelperProxy.prototype.sort = function(sortBy, reverse, load) {
      if (load === undefined) {
        load = true;
      }

      this.page = 1;
      this.sortBy = sortBy;
      this.reverse = reverse;

      if (load) {
        this.load();
      }
    };

    ListHelperProxy.prototype.getSortBy = function() {
      return this.sortBy;
    };

    ListHelperProxy.prototype.getReverse = function() {
      return this.reverse;
    };

    ListHelperProxy.prototype.getPage = function() {
      return this.page;
    };

    ListHelperProxy.prototype.setPage = function(page) {
      this.page = page;
      this.load();
    };

    ListHelperProxy.prototype.getPerPage = function() {
      return this.perPage;
    };

    ListHelperProxy.prototype.setPerPage = function(perPage) {
      this.perPage = perPage;
      this.load();
    };

    ListHelperProxy.prototype.getTotalPages = function() {
      return Math.ceil(this.getCount() / this.getPerPage());
    };

    ListHelperProxy.prototype.setCount = function(count) {
      this.count = count;
    };

    ListHelperProxy.prototype.getCount = function() {
      return this.count;
    };

    ListHelperProxy.prototype.setItems = function(items) {
      this.items = items;
    };

    ListHelperProxy.prototype.getItems = function() {
      return this.items;
    };

    ListHelperProxy.prototype.getParams = function() {
      var params = {
        page: this.getPage(),
        perPage: this.getPerPage()
      };

      if (this.getReverse()) {
        params.sort = '-' + this.getSortBy();
      } else {
        params.sort = this.getSortBy();
      }

      return params;
    };

    ListHelperProxy.prototype.load = function() {
      var params = this.getParams();

      // Params have changed
      if (!angular.equals(params, this.lastParams)) {
        this.callback(this, params);
        this.lastParams = angular.copy(params);
      }
    };

    return ListHelperProxy;
  });
})();
<commit_msg>Move back a page when the last item on the page is deleted<commit_after>(function() {
  'use strict';

  var app = angular.module('radar.ui');

  var DEFAULT_SORT_BY = 'id';
  var DEFAULT_PER_PAGE = 10;

  app.directive('listHelper', ['$parse', '_', 'escapeRegExp', 'dateSearch', 'anyValue', function($parse, _, escapeRegExp, dateSearch, anyValue) {
    return {
      scope: false,
      controller: ['$scope', '$attrs', function($scope, $attrs) {
        var self = this;

        var listHelper = $attrs.listHelper;
        var match = /\s*(\S+)\s+as\s+(\S+)\s*/.exec(listHelper);

        if (match) {
          var collectionExpression = match[1];
          var aliasExpression = match[2];

          var collectionGetter = $parse(collectionExpression);
          var aliasSetter = $parse(aliasExpression).assign;

          client(collectionGetter, aliasSetter);
        } else {
          var paramsGetter = $parse(listHelper);
          server(paramsGetter);
        }

        function client(collectionGetter, aliasSetter) {
          aliasSetter($scope, self);

          var options = $parse($attrs.listHelperOptions)($scope) || {};
          var deep = options.deep !== false;
          var perPage = options.perPage || DEFAULT_PER_PAGE;
          var reverse = options.reverse === true;
          var sortBy = options.sortBy || DEFAULT_SORT_BY;
          var sortId = options.sortId || sortBy;

          var items = [];
          var filteredItems = [];
          var sortedItems = [];
          var paginatedItems = [];
          var sortScope = $scope;
          var search = '';
          var page = 1;

          $scope.$watchCollection(function() {
            return collectionGetter($scope) || [];
          }, function(value) {
            items = value;
            _filter();
            checkPage();
          });

          $scope.$watch('items', function() {
            _filter();
          }, deep);

          _filter();

          self.sort = sort;
          self.filter = filter;
          self.getSortBy = getSortBy;
          self.getReverse = getReverse;
          self.getSortId = getSortId;
          self.getPage = getPage;
          self.setPage = setPage;
          self.getPerPage = getPerPage;
          self.setPerPage = setPerPage;
          self.getTotalPages = getTotalPages;
          self.getCount = getCount;
          self.getItems = getItems;

          function sort(newSortBy, newReverse, newSortId, newSortScope) {
            sortBy = newSortBy;
            reverse = newReverse;
            sortId = newSortId;
            sortScope = newSortScope;
            page = 1;
            _sort();
          }

          function filter(newSearch) {
            search = newSearch;
            page = 1;
            _filter();
          }

          function getSortId() {
            return sortId;
          }

          function getSortBy() {
            return sortBy;
          }

          function getReverse() {
            return reverse;
          }

          /*
           * Move back a page when the last item on the page is deleted.
           */
          function checkPage() {
            var totalPages = getTotalPages();

            if (getPage() > totalPages) {
              setPage(totalPages);
            }
          }

          function getPage() {
            return page;
          }

          function setPage(newPage) {
            page = newPage;
            _paginate();
          }

          function getPerPage() {
            return perPage;
          }

          function setPerPage(newPerPage) {
            perPage = newPerPage;
            _paginate();
          }

          function getTotalPages() {
            return Math.ceil(filteredItems.length / perPage);
          }

          function getCount() {
            return filteredItems.length;
          }

          function getItems() {
            return paginatedItems;
          }

          function _filter() {
            filteredItems = items;

            if (search) {
              var searchRegExp = new RegExp(escapeRegExp(search.trim()), 'i');
              var searchMatcher = function(value) {
                return searchRegExp.test(value);
              };

              var dateMatcher = dateSearch(search);

              var matcher = function(value) {
                return searchMatcher(value) || dateMatcher(value);
              };

              filteredItems = _.filter(filteredItems, function(x) {
                return anyValue(x.getData(), matcher);
              });
            }

            _sort();
          }

          function _sort() {
            sortedItems = filteredItems;

            if (sortBy !== null) {
              var getter = $parse(sortBy);

              sortedItems = _.sortBy(sortedItems, function(item) {
                // Note: AngularJS doesn't check the prototype of the locals argument
                return getter(item, sortScope);
              });
            }

            if (reverse) {
              sortedItems.reverse();
            }

            _paginate();
          }

          function _paginate() {
            if (perPage === null) {
              paginatedItems = sortedItems;
            } else {
              var startIndex = (page - 1) * perPage;
              var endIndex = page * perPage;
              paginatedItems = _.slice(sortedItems, startIndex, endIndex);
            }

          }
        }

        function server(apiGetter) {
          var api = apiGetter($scope);

          $scope.$watch(function() {
            return apiGetter($scope);
          }, function(value) {
            api = value;
          });

          self.sort = sort;
          self.getSortBy = getSortBy;
          self.getReverse = getReverse;
          self.getSortId = getSortId;
          self.getPage = getPage;
          self.setPage = setPage;
          self.getPerPage = getPerPage;
          self.setPerPage = setPerPage;
          self.getTotalPages = getTotalPages;
          self.getCount = getCount;
          self.getItems = getItems;

          function sort(sortBy, reverse) {
            if (api) {
              api.sort(sortBy, reverse);
            }
          }

          function getSortId() {
            return getSortBy();
          }

          function getSortBy() {
            return api ? api.getSortBy() : 'id';
          }

          function getReverse() {
            return api ? api.getReverse() : false;
          }

          function getPage() {
            return api ? api.getPage() : 1;
          }

          function setPage(page) {
            if (api) {
              api.setPage(page);
            }
          }

          function getPerPage() {
            return api ? api.getPerPage() : DEFAULT_PER_PAGE;
          }

          function setPerPage(perPage) {
            if (api) {
              api.setPerPage(perPage);
            }
          }

          function getTotalPages() {
            return api ? api.getTotalPages() : 0;
          }

          function getCount() {
            return api ? api.getCount() : 0;
          }

          function getItems() {
            return api ? api.getItems() : [];
          }
        }
      }]
    };
  }]);

  app.factory('ListHelperProxy', function() {
    function ListHelperProxy(callback, params) {
      this.items = [];
      this.count = 0;

      this.page = 1;
      this.perPage = DEFAULT_PER_PAGE;

      this.sortBy = 'id';
      this.reverse = false;

      this.callback = callback;

      if (params) {
        if (params.perPage) {
          this.perPage = params.perPage;
        }

        if (params.sortBy) {
          this.sortBy = params.sortBy;
        }

        if (params.reverse) {
          this.reverse = params.reverse;
        }
      }

      this.lastParams = null;
    }

    ListHelperProxy.prototype.sort = function(sortBy, reverse, load) {
      if (load === undefined) {
        load = true;
      }

      this.page = 1;
      this.sortBy = sortBy;
      this.reverse = reverse;

      if (load) {
        this.load();
      }
    };

    ListHelperProxy.prototype.getSortBy = function() {
      return this.sortBy;
    };

    ListHelperProxy.prototype.getReverse = function() {
      return this.reverse;
    };

    ListHelperProxy.prototype.getPage = function() {
      return this.page;
    };

    ListHelperProxy.prototype.setPage = function(page) {
      this.page = page;
      this.load();
    };

    ListHelperProxy.prototype.getPerPage = function() {
      return this.perPage;
    };

    ListHelperProxy.prototype.setPerPage = function(perPage) {
      this.perPage = perPage;
      this.load();
    };

    ListHelperProxy.prototype.getTotalPages = function() {
      return Math.ceil(this.getCount() / this.getPerPage());
    };

    ListHelperProxy.prototype.setCount = function(count) {
      this.count = count;
    };

    ListHelperProxy.prototype.getCount = function() {
      return this.count;
    };

    ListHelperProxy.prototype.setItems = function(items) {
      this.items = items;
    };

    ListHelperProxy.prototype.getItems = function() {
      return this.items;
    };

    ListHelperProxy.prototype.getParams = function() {
      var params = {
        page: this.getPage(),
        perPage: this.getPerPage()
      };

      if (this.getReverse()) {
        params.sort = '-' + this.getSortBy();
      } else {
        params.sort = this.getSortBy();
      }

      return params;
    };

    ListHelperProxy.prototype.load = function() {
      var params = this.getParams();

      // Params have changed
      if (!angular.equals(params, this.lastParams)) {
        this.callback(this, params);
        this.lastParams = angular.copy(params);
      }
    };

    return ListHelperProxy;
  });
})();
<|endoftext|>


<commit_before>
function AMESuggestSetup(itemID, treeContainerElem, treeElem, field, buttonID)
{
    	var form = document.getElementById('org_datadryad_app_xmlui_aspect_ame_AMEForm_div_ame-item');

	var container = document.getElementById(treeContainerElem);
	var tree = document.getElementById(treeElem);
	container.style.display = 'block';
	$(tree).dynatree("destroy");
	$(tree).dynatree({
	      checkbox: true,
	      selectMode: 2,
	      minExpandLevel: 10,
	      initAjax: {
	          url: "../JSON/ame/suggest/" + itemID + "/" + field
	      },
              onCustomRender: function(node) {
                var html = "" + node.data.title + "";

                if (node.data.origin) {
                    html +=  "[" + node.data.origin + "]";
                }

                html += "
";

                if (node.data.broaders) {
                   html += "> ";
                   for (i=0; i < node.data.broaders.length; i++) {
                      if (i > 0)
                          html += "; ";
                      var parent = node.data.broaders[i];
                      html +=  "" + parent.title + "";
                   }
                }

		html += "";

                if (node.data.path)
                   return html;
              },
	      onSelect: function(select, node) {
	        // Display list of selected nodes
	        var selNodes = node.tree.getSelectedNodes();
	        // convert to title/key array
	        var selKeys = $.map(selNodes, function(node){
	             return "[" + node.data.key + "]: '" + node.data.title + "'";
	        });
	      },
	      onClick: function(node, event) {
                  if (event.target.className == "dynatree-title") {
	            window.open(node.data.url);
                  }
                  else if (event.target.className != "dynatree-checkbox") {
	            window.open(event.target);
                  }
	      },
	      onKeydown: function(node, event) {
	        if( event.which == 32 ) {
	          node.toggleSelect();
	          return false;
	        }
	      },
	      // The following options are only required, if we have more than one tree on one page:
	      cookieId: "dynatree-Cb2",
	      idPrefix: "dynatree-Cb2-",
              classNames: {
                  nodeIcon: "custom-node-icon"
              }

	    });

        var addButton = document.getElementById(buttonID);
        $(addButton).button();
        $(addButton).click(
            function() {
	        var selected = $(tree).dynatree("getSelectedNodes");
                for (i=0; i<selected.length; i++) {
                   var el = document.createElement("input");
                   el.type = "hidden";
                   el.name = "add_" + field + "_" + i;
                   el.value = selected[i].data.title;
                   form.appendChild(el);

                   var confidence = document.createElement("input");
                   confidence.type = "hidden";
                   confidence.name = "add_" + i + "_confidence";
                   confidence.value = "ACCEPTED";
                   form.appendChild(confidence);

                   var authority = document.createElement("input");
                   authority.type = "hidden";
                   authority.name = "add_" + i + "_authority";
                   authority.value = selected[i].data.url;
                   form.appendChild(authority);
                }
                var submit = document.createElement("input");
                submit.type = "hidden";
                submit.name = "submit_" + field + "_add";
                submit.value = "Add";
                form.appendChild(submit);
                form.submit();
            }
        );
  }

  $(function(){
        $('.ame-item-remove').attr("title", "Removes the selected entry.");
        $('[title]').tooltip({
		tipClass: 'ame-tooltip'
        });
        $('.ame-item-remove').tooltip({
		tipClass: 'ame-tooltip'
        });

  });
<commit_msg>Fixed problem with ame.js not working with jQuery.noConflict<commit_after>
function AMESuggestSetup(itemID, treeContainerElem, treeElem, field, buttonID)
{
    	var form = document.getElementById('org_datadryad_app_xmlui_aspect_ame_AMEForm_div_ame-item');

	var container = document.getElementById(treeContainerElem);
	var tree = document.getElementById(treeElem);
	container.style.display = 'block';
	jQuery(tree).dynatree("destroy");
	jQuery(tree).dynatree({
	      checkbox: true,
	      selectMode: 2,
	      minExpandLevel: 10,
	      initAjax: {
	          url: "../JSON/ame/suggest/" + itemID + "/" + field
	      },
              onCustomRender: function(node) {
                var html = "" + node.data.title + "";

                if (node.data.origin) {
                    html +=  "[" + node.data.origin + "]";
                }

                html += "
";

                if (node.data.broaders) {
                   html += "> ";
                   for (i=0; i < node.data.broaders.length; i++) {
                      if (i > 0)
                          html += "; ";
                      var parent = node.data.broaders[i];
                      html +=  "" + parent.title + "";
                   }
                }

		html += "";

                if (node.data.path)
                   return html;
              },
	      onSelect: function(select, node) {
	        // Display list of selected nodes
	        var selNodes = node.tree.getSelectedNodes();
	        // convert to title/key array
	        var selKeys = jQuery.map(selNodes, function(node){
	             return "[" + node.data.key + "]: '" + node.data.title + "'";
	        });
	      },
	      onClick: function(node, event) {
                  if (event.target.className == "dynatree-title") {
	            window.open(node.data.url);
                  }
                  else if (event.target.className != "dynatree-checkbox") {
	            window.open(event.target);
                  }
	      },
	      onKeydown: function(node, event) {
	        if( event.which == 32 ) {
	          node.toggleSelect();
	          return false;
	        }
	      },
	      // The following options are only required, if we have more than one tree on one page:
	      cookieId: "dynatree-Cb2",
	      idPrefix: "dynatree-Cb2-",
              classNames: {
                  nodeIcon: "custom-node-icon"
              }

	    });

        var addButton = document.getElementById(buttonID);
        jQuery(addButton).button();
        jQuery(addButton).click(
            function() {
	        var selected = jQuery(tree).dynatree("getSelectedNodes");
                for (i=0; i<selected.length; i++) {
                   var el = document.createElement("input");
                   el.type = "hidden";
                   el.name = "add_" + field + "_" + i;
                   el.value = selected[i].data.title;
                   form.appendChild(el);

                   var confidence = document.createElement("input");
                   confidence.type = "hidden";
                   confidence.name = "add_" + i + "_confidence";
                   confidence.value = "ACCEPTED";
                   form.appendChild(confidence);

                   var authority = document.createElement("input");
                   authority.type = "hidden";
                   authority.name = "add_" + i + "_authority";
                   authority.value = selected[i].data.url;
                   form.appendChild(authority);
                }
                var submit = document.createElement("input");
                submit.type = "hidden";
                submit.name = "submit_" + field + "_add";
                submit.value = "Add";
                form.appendChild(submit);
                form.submit();
            }
        );
        jQuery('.ame-item-remove').attr("title", "Removes the selected entry.");
  }
<|endoftext|>


<commit_before>import React from 'react'
import {reducer as reducerUtil} from 'tocco-util'
import {actionEmitter, appFactory, externalEvents, notifier} from 'tocco-app-extensions'
import PropTypes from 'prop-types'

import Merge from './components/Merge'
import reducers, {sagas} from './modules/reducers'
import {setSelection} from './modules/merge/actions'

const packageName = 'merge'

const EXTERNAL_EVENTS = [
  'emitAction',
  'onSuccess'
]

const initApp = (id, input, events = {}, publicPath) => {
  const store = appFactory.createStore(reducers, sagas, input, packageName)
  actionEmitter.addToStore(store, events.emitAction)
  externalEvents.addToStore(store, events)
  const handleNotifications = !events.emitAction
  notifier.addToStore(store, handleNotifications)

  const content = <>
    {handleNotifications && <notifier.Notifier/>}
    <Merge/>
  </>

  return appFactory.createApp(
    packageName,
    content,
    store,
    {
      input,
      events,
      actions: [
        setSelection(input.selection)
      ],
      publicPath,
      textResourceModules: ['component', 'common', packageName]
    }
  )
}

(() => {
  if (__PACKAGE_NAME__ === packageName) {
    appFactory.registerAppInRegistry(packageName, initApp)

    if (__DEV__) {
      const input = require('./dev/input.json')
      input.navigationStrategy = {}
      input.navigationStrategy.ListLink = ({children}) => children

      if (!__NO_MOCK__) {
        const fetchMock = require('fetch-mock').default
        fetchMock.config.overwriteRoutes = false
        const setupFetchMocks = require('./dev/fetchMocks').default
        setupFetchMocks(packageName, fetchMock)
        fetchMock.spy()
      }

      const app = initApp(packageName, input)

      if (module.hot) {
        module.hot.accept('./modules/reducers', () => {
          const reducers = require('./modules/reducers').default
          reducerUtil.hotReloadReducers(app.store, reducers)
        })
      }

      appFactory.renderApp(app.component)
    }
  }
})()

const MergeApp = props => {
  const events = EXTERNAL_EVENTS.reduce((events, event) => {
    if (props[event]) {
      events[event] = props[event]
    }
    return events
  }, {})

  return initApp('merge', props, events).component
}

MergeApp.propTypes = {
  selection: PropTypes.object,
  ...EXTERNAL_EVENTS.reduce((propTypes, event) => {
    propTypes[event] = PropTypes.func
    return propTypes
  }, {})
}

export default MergeApp
<commit_msg>refactor(merge): adjust to new notification<commit_after>import React from 'react'
import {reducer as reducerUtil} from 'tocco-util'
import {actionEmitter, appFactory, externalEvents, notification} from 'tocco-app-extensions'
import PropTypes from 'prop-types'

import Merge from './components/Merge'
import reducers, {sagas} from './modules/reducers'
import {setSelection} from './modules/merge/actions'

const packageName = 'merge'

const EXTERNAL_EVENTS = [
  'emitAction',
  'onSuccess'
]

const initApp = (id, input, events = {}, publicPath) => {
  const store = appFactory.createStore(reducers, sagas, input, packageName)
  actionEmitter.addToStore(store, events.emitAction)
  externalEvents.addToStore(store, events)
  const handleNotifications = !events.emitAction
  notification.addToStore(store, handleNotifications)

  const content = <>
    {handleNotifications && <notification.Notifier/>}
    <Merge/>
  </>

  return appFactory.createApp(
    packageName,
    content,
    store,
    {
      input,
      events,
      actions: [
        setSelection(input.selection)
      ],
      publicPath,
      textResourceModules: ['component', 'common', packageName]
    }
  )
}

(() => {
  if (__PACKAGE_NAME__ === packageName) {
    appFactory.registerAppInRegistry(packageName, initApp)

    if (__DEV__) {
      const input = require('./dev/input.json')
      input.navigationStrategy = {}
      input.navigationStrategy.ListLink = ({children}) => children

      if (!__NO_MOCK__) {
        const fetchMock = require('fetch-mock').default
        fetchMock.config.overwriteRoutes = false
        const setupFetchMocks = require('./dev/fetchMocks').default
        setupFetchMocks(packageName, fetchMock)
        fetchMock.spy()
      }

      const app = initApp(packageName, input)

      if (module.hot) {
        module.hot.accept('./modules/reducers', () => {
          const reducers = require('./modules/reducers').default
          reducerUtil.hotReloadReducers(app.store, reducers)
        })
      }

      appFactory.renderApp(app.component)
    }
  }
})()

const MergeApp = props => {
  const events = EXTERNAL_EVENTS.reduce((events, event) => {
    if (props[event]) {
      events[event] = props[event]
    }
    return events
  }, {})

  return initApp('merge', props, events).component
}

MergeApp.propTypes = {
  selection: PropTypes.object,
  ...EXTERNAL_EVENTS.reduce((propTypes, event) => {
    propTypes[event] = PropTypes.func
    return propTypes
  }, {})
}

export default MergeApp
<|endoftext|>


<commit_before>var DURATION = 2000;

var interval;

function cleanup()
{
    // Cancel any interval started by a previous slide
    clearInterval(interval);
}

function setupVisualizations(slideshow)
{
    slideshow.on('afterShowSlide', function (slide)
    {
        cleanup();

        if (slide.properties.viz && document.getElementById(slide.properties.viz))
        {
            d3.select('#' + slide.properties.viz).call(startViz);
        }
    });

    // start visualizations with a click in the container
    d3.selectAll(".viz-container").on("click", function()
    {
        cleanup();

        viz(this);
    });
}

function viz(element)
{
    startViz(d3.select(element));
}

function startViz(selection)
{
    var id = selection.attr("id");
    console.log('starting viz %s', id);
    window[id](selection);
}

function width(selection)
{
    var svg = selection.select('svg'),
        $svg = jQuery(svg[0]);

    return $svg.width();
}

function startInterval(cb, duration)
{
    interval = setInterval(cb, duration || DURATION);

    cb();
}

////////////////////////////////////////////////////////////////////////

function vizSelections1(selection)
{
    selection.select('rect')
        .transition().duration(DURATION)
        .style("fill", "green");
}

function vizSelections2(selection)
{
    selection.selectAll('rect')
        .transition().duration(DURATION)
        .style("fill", "green");
}

function vizSelections3(selection)
{
    selection.selectAll('rect')
        .transition().duration(DURATION)
        .attr("height", "150")
        .transition().duration(DURATION)
        .attr("width", "100")
        .transition().duration(DURATION)
        .style("fill", "gray")
        .transition().duration(DURATION)
        .style("stroke", "indigo").style("stroke-width", 15);
}

function vizSelections4(selection)
{
    selection.selectAll('rect')
        .transition().duration(DURATION)
        .attr("height", "150")
        .transition().duration(DURATION)
        .attr("width", 100)
        .transition().duration(DURATION)
        .style("fill", function (d, i) {
            return ["gray", "orange"][i];
        })
}

function vizSelectionsPractice(selection)
{
    startInterval(function ()
    {
        selection.selectAll('circle')
            .transition().duration(DURATION)
            .attr("r", function () {
                return Math.random() * 200;
            })
            .attr("class", function (d, i) {
                return ['php', 'js', 'ruby'][i] + ' transparent';
            });
    });
}

function vizDataJoin1(selection)
{
    var data = [200, 100, 15];

    var circles = selection.select('g').selectAll('circle').data(data);

    var circleEnter = circles.enter().append("circle").attr("r", 0);

    circles.transition().duration(DURATION)
        .attr("r", function (d, i)
        {
            return d;
        })
        .attr("class", function (d, i)
        {
            return ['js', 'php', 'ruby'][i];
        });

}

vizDataJoin2 = vizDataJoin1;

function vizEUE1(selection)
{
    var data = [
        {lang: 'js',   popularity: 200},
        {lang: 'php',  popularity: 100},
        {lang: 'ruby', popularity: 15},
    ];

    var circles = selection.select('g').selectAll('circle').data(data);

    var circleEnter = circles.enter().append("circle").attr("r", 0);

    circles.transition().duration(DURATION)
        .attr("r", function (d, i)
        {
            return d.popularity;
        })
        .attr("class", function (d, i)
        {
            return d.lang;
        });
}

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

var eue2Data = [
    {lang: 'js',   popularity: 200},
    {lang: 'php',  popularity: 100},
];

eue2Data.times = 2;

function vizEUE2(selection)
{
    switch (eue2Data.times++ % 3)
    {
        case 0:
            eue2Data.push({lang: 'ruby', popularity: 60});
            break;

        case 1:
            eue2Data[1].popularity = 70 + _.random(0, 130);
            break;

        case 2:
            eue2Data.length =  2;
            break;
    }

    console.log(JSON.stringify(eue2Data));

    var circles = selection.select('g').selectAll('circle').data(eue2Data);

    circles.enter()
        .append("circle")
        .style("opacity", 0)
        .attr("r", 0);

    circles
        .transition().duration(DURATION)
        .style("opacity", 1)
        .attr("r", function (d, i)
        {
            return d.popularity;
        })
        .attr("class", function (d, i)
        {
            return d.lang;
        });

    circles.exit()
        .transition().duration(DURATION)
        .style("opacity", 0)
        .remove();
}

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

function vizAxisDemo(selection)
{
    var svg = selection.select('svg');

    svg.append("g");

    var factor = 1;

    var tScale = d3.time.scale()
        .range([0, width(selection)])
        .nice();

    var tAxis = d3.svg.axis().ticks(5).scale(tScale);

    function refresh()
    {
        factor *=  1.02;

        offset = factor * 5 * 1e3;

        console.log("refresh %s", offset);

        if (offset > 1e3 * 60 * 60 * 24 * 365 * 10)
        {
            cleanup();
        }

        tScale.domain([
            Date.now() - offset,
            Date.now()
        ]);

        svg.transition().call(tAxis);
    }

    interval = setInterval(refresh, 100);
}

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

function vizTrans1(selection)
{
    var r = 80,
        w = Math.round(width(selection) - r);

    selection.select('circle').transition()
        .ease('linear')
        .duration(8e3)
        .attr("r", r)
        .attr("cx", w)
        .attr("fill", 'yellow');
}

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

function vizTrans2(selection)
{
    var path = selection.select('path');

    var line = d3.svg.line()
        .x(function(d) { return d.x; })
        .y(function(d) { return d.y; })
        .interpolate("linear");

    function data()
    {
        var samplesize = 50;
        return _.range(0, width(selection) / samplesize)
            .map(function(d){ return d * samplesize; })
            .map(function(d){ return {x: d, y: _.random(200)} });
    }

    function draw(path)
    {
        path.attr("d", line(data()));
    }

    function transition()
    {
        var t = path.transition().ease('linear').duration(DURATION * 3)

        draw(t);
    }

    interval = setInterval(function ()
    {
        transition();
    }, DURATION * 3);

    draw(path);
    transition();
}

// -----------------------------------------------------------------------------
<commit_msg>using the transition function to save some trees<commit_after>var DURATION = 2000;

var interval;

function cleanup()
{
    // Cancel any interval started by a previous slide
    clearInterval(interval);
}

function setupVisualizations(slideshow)
{
    slideshow.on('afterShowSlide', function (slide)
    {
        cleanup();

        if (slide.properties.viz && document.getElementById(slide.properties.viz))
        {
            d3.select('#' + slide.properties.viz).call(startViz);
        }
    });

    // start visualizations with a click in the container
    d3.selectAll(".viz-container").on("click", function()
    {
        cleanup();

        viz(this);
    });
}

function viz(element)
{
    startViz(d3.select(element));
}

function startViz(selection)
{
    var id = selection.attr("id");
    console.log('starting viz %s', id);
    window[id](selection);
}

function width(selection)
{
    var svg = selection.select('svg'),
        $svg = jQuery(svg[0]);

    return $svg.width();
}

function startInterval(cb, duration)
{
    interval = setInterval(cb, duration || DURATION);

    cb();
}

////////////////////////////////////////////////////////////////////////

function vizSelections1(selection)
{
    selection.select('rect')
        .transition().duration(DURATION)
        .style("fill", "green");
}

function vizSelections2(selection)
{
    selection.selectAll('rect')
        .transition().duration(DURATION)
        .style("fill", "green");
}

function vizSelections3(selection)
{
    selection.selectAll('rect')
        .transition().duration(DURATION)
        .attr("height", "150")
        .transition().duration(DURATION)
        .attr("width", "100")
        .transition().duration(DURATION)
        .style("fill", "gray")
        .transition().duration(DURATION)
        .style("stroke", "indigo").style("stroke-width", 15);
}

function vizSelections4(selection)
{
    selection.selectAll('rect')
        .transition().duration(DURATION)
        .attr("height", "150")
        .transition().duration(DURATION)
        .attr("width", 100)
        .transition().duration(DURATION)
        .style("fill", function (d, i) {
            return ["gray", "orange"][i];
        })
}

function vizSelectionsPractice(selection)
{
    startInterval(function ()
    {
        selection.selectAll('circle')
            .transition().duration(DURATION)
            .attr("r", function () {
                return Math.random() * 200;
            })
            .attr("class", function (d, i) {
                return ['php', 'js', 'ruby'][i] + ' transparent';
            });
    });
}

function vizDataJoin1(selection)
{
    var data = [200, 100, 15];

    var circles = selection.select('g').selectAll('circle').data(data);

    var circleEnter = circles.enter().append("circle").attr("r", 0);

    circles.transition().duration(DURATION)
        .attr("r", function (d, i)
        {
            return d;
        })
        .attr("class", function (d, i)
        {
            return ['js', 'php', 'ruby'][i];
        });

}

vizDataJoin2 = vizDataJoin1;

function vizEUE1(selection)
{
    var data = [
        {lang: 'js',   popularity: 200},
        {lang: 'php',  popularity: 100},
        {lang: 'ruby', popularity: 15},
    ];

    var circles = selection.select('g').selectAll('circle').data(data);

    var circleEnter = circles.enter().append("circle").attr("r", 0);

    circles.transition().duration(DURATION)
        .attr("r", function (d, i)
        {
            return d.popularity;
        })
        .attr("class", function (d, i)
        {
            return d.lang;
        });
}

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

var eue2Data = [
    {lang: 'js',   popularity: 200},
    {lang: 'php',  popularity: 100},
];

eue2Data.times = 2;

function vizEUE2(selection)
{
    switch (eue2Data.times++ % 3)
    {
        case 0:
            eue2Data.push({lang: 'ruby', popularity: 60});
            break;

        case 1:
            eue2Data[1].popularity = 70 + _.random(0, 130);
            break;

        case 2:
            eue2Data.length =  2;
            break;
    }

    console.log(JSON.stringify(eue2Data));

    var circles = selection.select('g').selectAll('circle').data(eue2Data);

    circles.enter()
        .append("circle")
        .style("opacity", 0)
        .attr("r", 0);

    circles
        .transition().duration(DURATION)
        .style("opacity", 1)
        .attr("r", function (d, i)
        {
            return d.popularity;
        })
        .attr("class", function (d, i)
        {
            return d.lang;
        });

    circles.exit()
        .transition().duration(DURATION)
        .style("opacity", 0)
        .remove();
}

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

function vizAxisDemo(selection)
{
    var svg = selection.select('svg');

    svg.append("g");

    var factor = 1;

    var tScale = d3.time.scale()
        .range([0, width(selection)])
        .nice();

    var tAxis = d3.svg.axis().ticks(5).scale(tScale);

    interval = setInterval(function refresh()
    {
        factor *=  1.02;

        offset = factor * 5 * 1e3;

        console.log("refresh %s", offset);

        if (offset > 1e3 * 60 * 60 * 24 * 365 * 10)
        {
            cleanup();
        }

        tScale.domain([
            Date.now() - offset,
            Date.now()
        ]);

        svg.transition().call(tAxis);
    }, 100);
}

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

function vizTrans1(selection)
{
    var r = 80,
        w = Math.round(width(selection) - r);

    selection.select('circle').transition()
        .ease('linear')
        .duration(8e3)
        .attr("r", r)
        .attr("cx", w)
        .attr("fill", 'yellow');
}

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

function vizTrans2(selection)
{
    var path = selection.select('path');

    var line = d3.svg.line()
        .x(function(d) { return d.x; })
        .y(function(d) { return d.y; })
        .interpolate("linear");

    function data()
    {
        var samplesize = 50;
        return _.range(0, width(selection) / samplesize)
            .map(function(d){ return d * samplesize; })
            .map(function(d){ return {x: d, y: _.random(200)} });
    }

    function draw(path)
    {
        path.attr("d", line(data()));
    }

    function transition()
    {
        var t = path.transition().ease('linear').duration(DURATION * 3)

        draw(t);
    }

    draw(path);
    startInterval(transition, DURATION * 3);
}

// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>var beats = require("./beats.js");
var Point = require("./point.js");
var Action = require("./action.js");
var Person = require("./person.js");

/**
 * A Sequence is an ordered collection of points in spacetime.
 */
function Sequence(rawdata) {
	var data = normaliseData(rawdata);

	/**
	 * Just for backwards compatibility so unit tests can check that things haven't regressed in refactor
	 * @param {Number} bar Which bar of the music is (must be an integer).
	 * @param {Number} beat Which beat in the bar
	 * @returns {array} A list of points in spacetime
	 */
	function getPointsByTime(bar, beat) {
		var actions = getActionsByTime(bar, beat);
		var id, output = [];
		for (id in actions) {
			output.push(actions[id].getRawData());
		}
		return output;
	}
	this.getPointsByTime = getPointsByTime;

	/**
	 * Returns a list of actions for where every person is at a given time
	 * @param {Number} bar Which bar of the music is (must be an integer).
	 * @param {Number} beat Which beat in the bar
	 * @returns {object} A object containing the action that each person is doing
	 */
	function getActionsByTime(bar, beat) {
		var personid, time = beats.normalise(bar, beat);
		var action, actions = {};
		for (personid in data) {
			action = data[personid].getActionByTime(time);

			// If no action is returned, then the person isn't on the mat, so ignore them.
			if (!action) continue;
			actions[personid] = action;
		}
		return actions;
	}
	this.getActionsByTime = getActionsByTime;
}

function normaliseData(data) {
	var i, l, pointdata, output = {};

	// Group all the points by person
	for (i=0, l=data.length; i<l; i++) {
		pointdata = data[i];
		if (!(pointdata.p in output)) {
			output[pointdata.p] = new Person(pointdata.p);
		}
		output[pointdata.p].addAction(new Action(new Point({
			x: pointdata.x,
			y: pointdata.y,
			z: pointdata.z,
			bar: pointdata.bar,
			beat: pointdata.beat
		}), pointdata.c));
	}
	return output;
}

module.exports = Sequence;<commit_msg>remove old interface now tests aren't using it<commit_after>var beats = require("./beats.js");
var Point = require("./point.js");
var Action = require("./action.js");
var Person = require("./person.js");

/**
 * A Sequence is an ordered collection of points in spacetime.
 */
function Sequence(rawdata) {
	var data = normaliseData(rawdata);

	/**
	 * Returns a list of actions for where every person is at a given time
	 * @param {Number} bar Which bar of the music is (must be an integer).
	 * @param {Number} beat Which beat in the bar
	 * @returns {object} A object containing the action that each person is doing
	 */
	function getActionsByTime(bar, beat) {
		var personid, time = beats.normalise(bar, beat);
		var action, actions = {};
		for (personid in data) {
			action = data[personid].getActionByTime(time);

			// If no action is returned, then the person isn't on the mat, so ignore them.
			if (!action) continue;
			actions[personid] = action;
		}
		return actions;
	}
	this.getActionsByTime = getActionsByTime;
}

function normaliseData(data) {
	var i, l, pointdata, output = {};

	// Group all the points by person
	for (i=0, l=data.length; i<l; i++) {
		pointdata = data[i];
		if (!(pointdata.p in output)) {
			output[pointdata.p] = new Person(pointdata.p);
		}
		output[pointdata.p].addAction(new Action(new Point({
			x: pointdata.x,
			y: pointdata.y,
			z: pointdata.z,
			bar: pointdata.bar,
			beat: pointdata.beat
		}), pointdata.c));
	}
	return output;
}

module.exports = Sequence;<|endoftext|>


<commit_before>describe("helper", function() {
  it("should load the helpers", function() {
    var expectation= expect(true);

    expect(typeof(expectation.toHaveProperty)).toBe('function');
  });
});
<commit_msg>Reverted the newline change<commit_after>describe("helper", function() {
  it("should load the helpers", function() {
    var expectation= expect(true);

    expect(typeof(expectation.toHaveProperty)).toBe('function');
  });
});<|endoftext|>