<commit_before>// ==UserScript==
// @name         Auto mp3 downloader
// @description  Automatic download of multiple mp3s from https://www.emp3z.com. Just insert list of songs into textarea, push the button and wait till it finishes.
// @author       Bladito
// @version      0.6.5
// @homepageURL  https://greasyfork.org/en/users/55159-bladito
// @match        *://www.emp3x.ws/*
// @match        *://www.emp3z.ws/*
// @match        *://www.emp3z.co/*
// @match        *://www.emp3z.com/*
// @match        *://www.emp3c.com/*
// @match        *://www.emp3s.co/*
// @match        *://www.emp3d.co/*
// @match        *://www.emp3c.co/*
// @match        *://y-api.org/button/*
// @namespace    Bladito/auto-mp3-downloader
// @require      http://code.jquery.com/jquery-latest.js
// @grant        none
// ==/UserScript==

(function($) {
    'use strict';

    // run this code in inner cross origin iframe
    if (isSubstringInURL('/button/')) {
        log('SCRIPT 2');
        rememberUrlForSong();
        return;
    }

    log('SCRIPT 1');

    window.addEventListener('message', receiveMessage, false);

    function receiveMessage(evt) {
        log('RECEIVED MESSAGE', evt);
        if (evt.data && evt.data.indexOf('Bladito') === 0) {
            setFoundDataForCurrentSong($('.song-list ul:eq(0) li:eq(0) a b').text(), evt.data.replace('Bladito', ''));
            findUrlForNextSong();
        }
    }

    // block annoying popups
    var openWindow = window.open;
    window.open = function() {
        console.log('[Bladito/auto-mp3-downloader] Blocked opening window');
        return;
    };
    detectAdditionInDOM($('body').get(0), function(mutation) {
        if (mutation.target.tagName === 'BODY' && mutation.addedNodes[0].tagName === 'A') {
            console.log('[Bladito/auto-mp3-downloader] Removing overlay');
            $(mutation.addedNodes[0]).remove();
        }
    });

    var storageName = 'Bladito_autoDownloader_toDL';
    var storageStateName = 'Bladito_autoDownloader_state';
    var storageNowFinding = 'Bladito_autoDownloader_nowFinding';
    var storageDebugName = 'Bladito_autoDownloader_isDebug';

    var artistAndSongOnSeparateLines = false;

    var STATE = {
        IDLE:'IDLE',
        FINDING_URLS:'FINDING_URLS',
        DOWNLOADING:'DOWNLOADING'
    };

    init();

    log('state=',getState(),window.location.pathname);

    if (getState() === STATE.IDLE || getState() === STATE.DOWNLOADING) {
        insertCustomHTMLElements();
    }
    if (getState() === STATE.IDLE) {
        printResults(true);
    }

    if (getState() === STATE.FINDING_URLS) {
        if (isResultsPage()) {
            log('song found');
            window.location.href = $('a[href^="/download"')[0].href;
        } else if (isDetailPage()) {
            log('remembering download url');
            $('#dl1').click(); // this will fetch another iframe
            //rememberUrlForSong();
        } else if (isNotFoundPage()) {
            log('song not found');
            setFoundDataForCurrentSong('N/A', undefined);
            findUrlForNextSong();
        } else if (isMainPage()) {
            addResetButton();
        }
    }

    if (getState() === STATE.DOWNLOADING) {
        downloadSongs();
        printResults();
        resetInitialState(true);
    }

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

    function init() {
        if (!getState()) {
            setState(STATE.IDLE);
        }

        if (getState() === STATE.FINDING_URLS && !getNextSongToFind()) {
            setState(STATE.DOWNLOADING);
        }
    }

    function findDownloadUrls() {
        var textAreaVal = $('#my-dl-list').val(),
            mp3List = prepareMp3List(textAreaVal);

        if (typeof mp3List === 'string') {
            showError(mp3List);
            return;
        }

        setMp3List(mp3List);
        setState(STATE.FINDING_URLS);

        log('to dl ', JSON.stringify(mp3List));

        findUrlForNextSong();
    }

    function findUrlForNextSong() {
        var nextSong = getNextSongToFind();

        if (nextSong) {
            log('gonna find ', nextSong.name);

            setNowFinding(nextSong.name);

            $('input[name="search"]', window.parent.document).val(nextSong.name);
            $('input[name="search"]', window.parent.document).parents('form').submit();

            //$('input[name="search"]').val(nextSong.name);
            //$('input[name="search"]').parents('form').submit();
        } else {
            location.href = 'https://www.emp3z.com/';
        }
    }

    function setFoundDataForCurrentSong(songName, songUrl) {
        var currentSong = getNowFinding(),
            list = getMp3List();

        for (var i=0; i<list.length; i+=1) {
            if (list[i].name === currentSong) {
                list[i].processed = true;
                list[i].url = songUrl;
                list[i].foundName = songName;
                log('SAVED URL ', songUrl, ' for song ', list[i].name);
                break;
            }
        }

        setMp3List(list);
    }

    function getNextSongToFind() {
        var list = getMp3List();

        for (var i=0; i<list.length; i+=1) {
            if (list[i].processed !== true) {
                return list[i];
            }
        }

        return undefined;
    }

    function prepareMp3List(mp3listString) {
        var i, list, result = [];

        if (!mp3listString || mp3listString.length === 0) {
            return 'EMPTY_INPUT';
        }

        list = mp3listString.split('\n');

        if (artistAndSongOnSeparateLines) {
            if (list.length % 2 !== 0) {
                return 'ODD_NUMBER';
            }
            for (i=1; i<list.length; i+=2) {
                result.push({
                    name: list[i-1] + ' ' + list[i]
                });
            }
        } else {
            for (i=0; i<list.length; i+=1) {
                result.push({
                    name: list[i]
                });
            }
        }

        return result;
    }

    function rememberUrlForSong() {
        /*
        var interval = setInterval(function() {
            log('finding link...');

            var link = $($('iframe')[0].contentWindow.document).find('#ytd')[0];
            if (link && link.href && link.href.length > 0) {
                window.clearInterval(interval);
                log('found link! ', link.href);
                setFoundDataForCurrentSong($('.song-list ul:eq(0) li:eq(0) a b').text(), link.href);
                findUrlForNextSong();
            }
        }, 1000);
        */
        var interval = setInterval(function() {
            log('finding link...');

            var link = $('#button a')[0];
            if (link && link.href && link.href.length > 0) {
                window.clearInterval(interval);
                log('found link! sending message', link.href);
                window.parent.parent.postMessage('Bladito' + link.href, '*');
            }
        }, 1000);
    }

    function downloadSongs() {
        var list = getMp3List();

        for (var i=0; i<list.length; i+=1) {
            if (list[i].url) {
                openWindow(list[i].url, '_blank');
            }
        }
    }

    function resetInitialState(keepList) {
        setState(STATE.IDLE);
        setNowFinding(null);
        if (!keepList) {
            setMp3List([]);
        }
    }

    function insertCustomHTMLElements() {
        var customElements, searchForm = $('form[action^="/search"]');

        customElements =
            '
' +
            '<textarea id="my-dl-list" class="form-control" style="height: 120px;" placeholder="Insert one or multiple songs separated by enter."/>' +
            '' +
            '<button id="my-btn" class="btn btn-primary" style="height: 100%; min-height: 120px; border: none; padding: 0 14px;">Auto Download</button>' +
            '' +
            '
' +
            '
' +
            '<input type="checkbox" id="bladito-input-mode" style="margin: 0 2px 0 0; vertical-align: text-top;">Artist and song on separate lines' +
            '
'
        ;

        searchForm.append(customElements);
        $('#my-btn').click(findDownloadUrls);
        $('#bladito-input-mode').click(function() {
            artistAndSongOnSeparateLines = $(this).is(':checked');
        });
    }

    function showError(errCode) {
        var searchForm = $('form[action^="/search"]');
        $('#bladito-error-message').remove();

        if (errCode === 'ODD_NUMBER') {
            searchForm.prepend('
'+
                               'You inserted ODD number of lines. Unable to continue.
');
        } else if (errCode === 'EMPTY_INPUT') {
            searchForm.prepend('
'+
                               'No songs inserted into textarea!
');
        }
    }

    function printResults(isOldResult) {
        var resultsHtml,
            resultsMessageHtml,
            list = getMp3List(),
            failedCounter = 0,
            searchForm = $('form[action^="/search"]'),
            resultColor = isOldResult ? '#008cba;' : '#71bf44;';

        resultsHtml = '

Searched Song	Found Song
';

        for (var i=0; i<list.length; i+=1) {
            resultsHtml += '
' + list[i].name + '	' + list[i].foundName + '	';
            if (list[i].url) {
                resultsHtml += 'Redownload';
            } else {
                resultsHtml += 'Not found';
                failedCounter += 1;
            }
            resultsHtml += '
';
        }
        setMp3List(list);

        resultsHtml += '

';
        resultsHtml = $(resultsHtml);

        if (isOldResult) {
            resultsMessageHtml = '
Last time you searched for:';
        } else {
            resultsMessageHtml = '
Found: ' + (list.length - failedCounter) + '/' + list.length + ' songs.';
        }

        searchForm.append(resultsHtml);
        resultsHtml.before(resultsMessageHtml);
    }

    function addResetButton() {
        var customElements, searchForm = $('form[action^="/search"]');

        customElements =
            '
Oops, something went wrong :(.' +
            '<button id="my-reset-btn" type="button" class="btn btn-primary" style="margin-left: 15px;">Reset to initial state</button>' +
            '
'
        ;

        searchForm.append(customElements);
        $('#my-reset-btn').click(function() {
            resetInitialState();
            location.href = 'https://www.emp3z.com/';
        });
    }

    function isResultsPage() {
        return isSubstringInURL('/mp3/');
    }

    function isDetailPage() {
        return isSubstringInURL('/download/');
    }

    function isNotFoundPage() {
        return isSubstringInURL('/404.php');
    }

    function isMainPage() {
        return window.location.pathname === '/';
    }

    function isSubstringInURL(substring) {
        return window.location.pathname.substring(0, substring.length) === substring;
    }

    function log() {
        if (localStorage.getItem(storageDebugName) === 'true') {
            console.log.apply(console, arguments);
        }
    }

    function setState(state) {
        localStorage.setItem(storageStateName, state);
    }

    function getState() {
        return localStorage.getItem(storageStateName);
    }

    function setNowFinding(songName) {
        localStorage.setItem(storageNowFinding, songName);
    }

    function getNowFinding() {
        return localStorage.getItem(storageNowFinding);
    }

    function setMp3List(mp3list) {
        localStorage.setItem(storageName, JSON.stringify(mp3list));
    }

    function getMp3List() {
        return JSON.parse(localStorage.getItem(storageName));
    }

    function detectAdditionInDOM(node, callback) {
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
        if (node) {
            if (MutationObserver) {
                var obs = new MutationObserver(function(mutations, observer) {
                    mutations.forEach(function(mutation) {
                        if (mutation.addedNodes.length) {
                            callback(mutation);
                        }
                    });
                });
                obs.observe(node, { childList:true, subtree:true });
            } else if (window.addEventListener) {
                node.addEventListener('DOMNodeInserted', callback, false);
            }
        }
    }

})(jQuery);
<commit_msg>fixed script not working<commit_after>// ==UserScript==
// @name         Auto mp3 downloader
// @description  Automatic download of multiple mp3s from https://www.emp3z.com. Just insert list of songs into textarea, push the button and wait till it finishes.
// @author       Bladito
// @version      0.6.6
// @homepageURL  https://greasyfork.org/en/users/55159-bladito
// @match        *://www.emp3x.ws/*
// @match        *://www.emp3z.ws/*
// @match        *://www.emp3z.co/*
// @match        *://www.emp3z.com/*
// @match        *://www.emp3c.com/*
// @match        *://www.emp3s.co/*
// @match        *://www.emp3d.co/*
// @match        *://www.emp3c.co/*
// @match        *://www.emp3e.com/*
// @match        *://y-api.org/button/*
// @namespace    Bladito/auto-mp3-downloader
// @require      http://code.jquery.com/jquery-latest.js
// @grant        none
// ==/UserScript==

(function($) {
    'use strict';

    // run this code in inner cross origin iframe
    if (isSubstringInURL('/button/')) {
        log('SCRIPT 2');
        rememberUrlForSong();
        return;
    }

    log('SCRIPT 1');

    window.addEventListener('message', receiveMessage, false);

    function receiveMessage(evt) {
        log('RECEIVED MESSAGE', evt);
        if (evt.data && evt.data.indexOf('Bladito_link:') === 0) {
            setFoundDataForCurrentSong($('.song-list ul:eq(0) li:eq(0) a b').text(), evt.data.replace('Bladito_link:', ''));
            findUrlForNextSong();
        }
    }

    // block annoying popups
    var openWindow = window.open;
    window.open = function() {
        console.log('[Bladito/auto-mp3-downloader] Blocked opening window');
        return;
    };
    detectAdditionInDOM($('body').get(0), function(mutation) {
        if (mutation.target.tagName === 'BODY' && mutation.addedNodes[0].tagName === 'A') {
            console.log('[Bladito/auto-mp3-downloader] Removing overlay');
            $(mutation.addedNodes[0]).remove();
        }
    });

    var storageName = 'Bladito_autoDownloader_toDL';
    var storageStateName = 'Bladito_autoDownloader_state';
    var storageNowFinding = 'Bladito_autoDownloader_nowFinding';
    var storageDebugName = 'Bladito_autoDownloader_isDebug';

    var artistAndSongOnSeparateLines = false;

    var STATE = {
        IDLE:'IDLE',
        FINDING_URLS:'FINDING_URLS',
        DOWNLOADING:'DOWNLOADING'
    };

    init();

    log('state=',getState(),window.location.pathname);

    if (getState() === STATE.IDLE || getState() === STATE.DOWNLOADING) {
        insertCustomHTMLElements();
    }
    if (getState() === STATE.IDLE) {
        printResults(true);
    }

    if (getState() === STATE.FINDING_URLS) {
        if (isResultsPage()) {
            log('song found');
            window.location.href = $('a[href^="/download"')[0].href;
        } else if (isDetailPage()) {
            log('remembering download url');
            $('#dl1').click(); // this will fetch another iframe
            //rememberUrlForSong();
        } else if (isNotFoundPage()) {
            log('song not found');
            setFoundDataForCurrentSong('N/A', undefined);
            findUrlForNextSong();
        } else if (isMainPage()) {
            addResetButton();
        }
    }

    if (getState() === STATE.DOWNLOADING) {
        downloadSongs();
        printResults();
        resetInitialState(true);
    }

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

    function init() {
        if (!getState()) {
            setState(STATE.IDLE);
        }

        if (getState() === STATE.FINDING_URLS && !getNextSongToFind()) {
            setState(STATE.DOWNLOADING);
        }
    }

    function findDownloadUrls() {
        var textAreaVal = $('#my-dl-list').val(),
            mp3List = prepareMp3List(textAreaVal);

        if (typeof mp3List === 'string') {
            showError(mp3List);
            return;
        }

        setMp3List(mp3List);
        setState(STATE.FINDING_URLS);

        log('to dl ', JSON.stringify(mp3List));

        findUrlForNextSong();
    }

    function findUrlForNextSong() {
        var nextSong = getNextSongToFind();

        if (nextSong) {
            log('gonna find ', nextSong.name);

            setNowFinding(nextSong.name);

            $('input[name="search"]', window.parent.document).val(nextSong.name);
            $('input[name="search"]', window.parent.document).parents('form').submit();

            //$('input[name="search"]').val(nextSong.name);
            //$('input[name="search"]').parents('form').submit();
        } else {
            location.href = 'https://www.emp3z.com/';
        }
    }

    function setFoundDataForCurrentSong(songName, songUrl) {
        var currentSong = getNowFinding(),
            list = getMp3List();

        for (var i=0; i<list.length; i+=1) {
            if (list[i].name === currentSong) {
                list[i].processed = true;
                list[i].url = songUrl;
                list[i].foundName = songName;
                log('SAVED URL ', songUrl, ' for song ', list[i].name);
                break;
            }
        }

        setMp3List(list);
    }

    function getNextSongToFind() {
        var list = getMp3List();

        for (var i=0; i<list.length; i+=1) {
            if (list[i].processed !== true) {
                return list[i];
            }
        }

        return undefined;
    }

    function prepareMp3List(mp3listString) {
        var i, list, result = [];

        if (!mp3listString || mp3listString.length === 0) {
            return 'EMPTY_INPUT';
        }

        list = mp3listString.split('\n');

        if (artistAndSongOnSeparateLines) {
            if (list.length % 2 !== 0) {
                return 'ODD_NUMBER';
            }
            for (i=1; i<list.length; i+=2) {
                result.push({
                    name: list[i-1] + ' ' + list[i]
                });
            }
        } else {
            for (i=0; i<list.length; i+=1) {
                result.push({
                    name: list[i]
                });
            }
        }

        return result;
    }

    function rememberUrlForSong() {
        /*
        var interval = setInterval(function() {
            log('finding link...');

            var link = $($('iframe')[0].contentWindow.document).find('#ytd')[0];
            if (link && link.href && link.href.length > 0) {
                window.clearInterval(interval);
                log('found link! ', link.href);
                setFoundDataForCurrentSong($('.song-list ul:eq(0) li:eq(0) a b').text(), link.href);
                findUrlForNextSong();
            }
        }, 1000);
        */
        var interval = setInterval(function() {
            log('finding link...');

            var link = $('#button a')[0];
            if (link && link.href === 'https://y-api.org/') {
                $('#progress').click();
            }
            if (link && link.href && link.href.length > 0 && link.href !== 'https://y-api.org/') {
                window.clearInterval(interval);
                log('found link! sending message', link.href);
                window.parent.parent.postMessage('Bladito_link:' + link.href, '*');
            }
        }, 1000);
    }

    function downloadSongs() {
        var list = getMp3List();

        for (var i=0; i<list.length; i+=1) {
            if (list[i].url) {
                openWindow(list[i].url, '_blank');
            }
        }
    }

    function resetInitialState(keepList) {
        setState(STATE.IDLE);
        setNowFinding(null);
        if (!keepList) {
            setMp3List([]);
        }
    }

    function insertCustomHTMLElements() {
        var customElements, searchForm = $('form[action^="/search"]');

        customElements =
            '
' +
            '<textarea id="my-dl-list" class="form-control" style="height: 120px;" placeholder="Insert one or multiple songs separated by enter."/>' +
            '' +
            '<button id="my-btn" class="btn btn-primary" style="height: 100%; min-height: 120px; border: none; padding: 0 14px;">Auto Download</button>' +
            '' +
            '
' +
            '
' +
            '<input type="checkbox" id="bladito-input-mode" style="margin: 0 2px 0 0; vertical-align: text-top;">Artist and song on separate lines' +
            '
'
        ;

        searchForm.append(customElements);
        $('#my-btn').click(findDownloadUrls);
        $('#bladito-input-mode').click(function() {
            artistAndSongOnSeparateLines = $(this).is(':checked');
        });
    }

    function showError(errCode) {
        var searchForm = $('form[action^="/search"]');
        $('#bladito-error-message').remove();

        if (errCode === 'ODD_NUMBER') {
            searchForm.prepend('
'+
                               'You inserted ODD number of lines. Unable to continue.
');
        } else if (errCode === 'EMPTY_INPUT') {
            searchForm.prepend('
'+
                               'No songs inserted into textarea!
');
        }
    }

    function printResults(isOldResult) {
        var resultsHtml,
            resultsMessageHtml,
            list = getMp3List(),
            failedCounter = 0,
            searchForm = $('form[action^="/search"]'),
            resultColor = isOldResult ? '#008cba;' : '#71bf44;';

        resultsHtml = '

Searched Song	Found Song
';

        for (var i=0; i<list.length; i+=1) {
            resultsHtml += '
' + list[i].name + '	' + list[i].foundName + '	';
            if (list[i].url) {
                resultsHtml += 'Redownload';
            } else {
                resultsHtml += 'Not found';
                failedCounter += 1;
            }
            resultsHtml += '
';
        }
        setMp3List(list);

        resultsHtml += '

';
        resultsHtml = $(resultsHtml);

        if (isOldResult) {
            resultsMessageHtml = '
Last time you searched for:';
        } else {
            resultsMessageHtml = '
Found: ' + (list.length - failedCounter) + '/' + list.length + ' songs.';
        }

        searchForm.append(resultsHtml);
        resultsHtml.before(resultsMessageHtml);
    }

    function addResetButton() {
        var customElements, searchForm = $('form[action^="/search"]');

        customElements =
            '
Oops, something went wrong :(.' +
            '<button id="my-reset-btn" type="button" class="btn btn-primary" style="margin-left: 15px;">Reset to initial state</button>' +
            '
'
        ;

        searchForm.append(customElements);
        $('#my-reset-btn').click(function() {
            resetInitialState();
            location.href = 'https://www.emp3z.com/';
        });
    }

    function isResultsPage() {
        return isSubstringInURL('/mp3/');
    }

    function isDetailPage() {
        return isSubstringInURL('/download/');
    }

    function isNotFoundPage() {
        return isSubstringInURL('/404.php');
    }

    function isMainPage() {
        return window.location.pathname === '/';
    }

    function isSubstringInURL(substring) {
        return window.location.pathname.substring(0, substring.length) === substring;
    }

    function log() {
        if (localStorage.getItem(storageDebugName) === 'true') {
            console.log.apply(console, arguments);
        }
    }

    function setState(state) {
        localStorage.setItem(storageStateName, state);
    }

    function getState() {
        return localStorage.getItem(storageStateName);
    }

    function setNowFinding(songName) {
        localStorage.setItem(storageNowFinding, songName);
    }

    function getNowFinding() {
        return localStorage.getItem(storageNowFinding);
    }

    function setMp3List(mp3list) {
        localStorage.setItem(storageName, JSON.stringify(mp3list));
    }

    function getMp3List() {
        return JSON.parse(localStorage.getItem(storageName));
    }

    function detectAdditionInDOM(node, callback) {
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
        if (node) {
            if (MutationObserver) {
                var obs = new MutationObserver(function(mutations, observer) {
                    mutations.forEach(function(mutation) {
                        if (mutation.addedNodes.length) {
                            callback(mutation);
                        }
                    });
                });
                obs.observe(node, { childList:true, subtree:true });
            } else if (window.addEventListener) {
                node.addEventListener('DOMNodeInserted', callback, false);
            }
        }
    }

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

/* This declares to JSHint that these are global variables: */
/*global flashTimeout:false */

angular.module('messages').controller('MessagesThreadController', ['$scope', '$stateParams', '$state', '$document', '$window', '$anchorScroll', '$timeout', 'Authentication', 'Messages', 'MessagesRead', 'messageCenterService', //'Socket',
  function($scope, $stateParams, $state, $document, $window, $anchorScroll, $timeout, Authentication, Messages, MessagesRead, messageCenterService) {//, Socket

    // If no recepient defined, go to inbox
    if (!$stateParams.userId) $state.go('inboxMessages');

    // Vars
    $scope.user = Authentication.user;
    $scope.userToId = $stateParams.userId;
    $scope.isSending = false;
    var flaggedAsRead = [];

    $scope.messages = [];
    $scope.messageHandler = new Messages();
    // Attach userID for backend calls
    var fetchMessages = function(){return( $scope.messageHandler.fetchMessages({userId: $stateParams.userId}) ); };

    // No sending messages to yourself
    if ($scope.user._id === $scope.userToId) $state.go('inboxMessages');

    // Appends returned messages to model
    function addMessages(data){
      angular.forEach(data, function(msg){
        $scope.messages.push(msg);
      });
      threadLayoutUpdate();
    }

    /*
     * Gets next page of messages
     * Activates when the first(top most) message hits the top viewport
     */
    $scope.moreMessages = function(){
      if($scope.messageHandler.nextPage) {
        var oldHeight = threadLayoutThread[0].scrollHeight;

        fetchMessages().$promise.then( function(data) {
          setScrollPosition(oldHeight);
          addMessages(data);
        });
      }
    };

    /**
     * Restores scroll position after pagination
     * Timeout is in place to force function to execute after digest cycle to properly calculate scroll height.
     */
    function setScrollPosition(oldHeight) {
      $timeout(function () {
        var newHeight = threadLayoutThread[0].scrollHeight;
        angular.element(threadLayoutThread.scrollTop(newHeight - oldHeight));
      });
    }

    /**
     * Calculate thread etc layout locations with this massive pile of helpers
     */
    var threadLayoutContainer = angular.element('#thread-container'),
        threadLayoutThread = angular.element('#messages-thread'),
        threadLayoutReply = angular.element('#message-reply');

    // Add (or reset) timeout to not call the resizing function every pixel
    var threadLayoutUpdateTimeout;
    function threadLayoutUpdate() {
      $timeout.cancel(threadLayoutUpdateTimeout);
      threadLayoutUpdateTimeout = $timeout(threadLayout, 300);
    }

    // Keep thread in good condition when screen resizes/orientation changes/message textrea grows
    // This sorta should be at .less files, but the message thread is such an complicated peace of UI...
    // Mostly this is needed due growing text field
    function threadLayout() {

      $scope.replyHeight = threadLayoutReply.height() + 'px';

      // container has 15px padding on both sides when window is bigger than screen-sm-max (768px)
      var containerPadding = ($window.innerWidth < 768) ? -15 : 30;
      $scope.containerWidth = threadLayoutContainer.width() - containerPadding + 'px';
      $scope.replyWidth = threadLayoutContainer.width() - 30 + 'px';
    }

    // Add (or reset) timeout to not call the scrolling function every key stroke
    var threadScrollUpdateTimeout;
    function threadScrollUpdate() {
      $timeout.cancel(threadScrollUpdateTimeout);
      threadScrollUpdateTimeout = $timeout(threadScrollBottom, 300);
    }

    // Scroll thread to bottom to show latest messages
    function threadScrollBottom() {
      threadLayoutThread.scrollTop(threadLayoutThread[0].scrollHeight);
    }

    // Keep layout in good order with these listeners
    angular.element($window).on('resize', threadLayoutUpdate);
    angular.element($window).bind('orientationchange', threadLayoutUpdate);
    angular.element($window).bind('orientationchange', threadScrollBottom);

    // Fire html.resize() so that jQuery-Waypoints can check what's visible on the screen and mark visible messages read.
    var onScrollTimeout,
        html = angular.element('html');
    threadLayoutThread.bind('scroll', function() {
        if(onScrollTimeout) $timeout.cancel(onScrollTimeout);
        onScrollTimeout = $timeout(function(){ html.resize(); }, 300);
    });

    $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
      // Fetches first page of messages
      fetchMessages().$promise.then( function(data){
        addMessages(data);
        $timeout(threadScrollBottom,500);
      });
    });

    // Observe for the reply area height while typing your awesome message in it
    angular.element('#message-reply-content').on('input', function() {
      $scope.replyHeight = threadLayoutReply.height() + 15 + 'px';
      threadScrollUpdate();
    });

    /**
     * Send messages marked as read (at frontend) to the backend
     * Has 1s timeout to slow down continuous pinging of the API
     */
    var syncReadTimer;
    function activateSyncRead() {
      // Cancel previously set timer
      if(syncReadTimer) $timeout.cancel(syncReadTimer);
      // syncRead happens with 1s delay
      // (and gets postponed by 1s if new activateSyncRead() happens)
      if(flaggedAsRead.length > 0) {
        syncReadTimer = $timeout(syncRead, 1000);
      }
    }
    function syncRead() {
      MessagesRead.query({
        messageIds: flaggedAsRead
      }, function(response){
        flaggedAsRead = [];
      });
    }

    /**
     * Mark message read at the frontend
     * This function inits each time message div passes viewport
     * Read message id is stored at array which will be sent to backend and emptied
     *
     * @todo: kill observer after message is marked read
     */
    $scope.messageRead = function(message, scrollingUp, scrollingDown) {
      if(message.read === true) return true;

      var read = (scrollingUp === true || scrollingDown === true);

      if(message.userFrom._id !== Authentication.user._id && !message.read && read) {
        message.read = true;
        flaggedAsRead.push(message._id);
        activateSyncRead();
      }

      return read;
    };

    /**
     * Send a message
     */
    $scope.send = function() {
      $scope.isSending = true;

      if(this.content === '

' || this.content.trim() === '') {
        $scope.isSending = false;
        messageCenterService.add('warning', 'Write a message first...', { timeout: flashTimeout });
        return;
      }

      var message = new $scope.messageHandler.ajaxCall({
        content: this.content,
        userTo: $stateParams.userId,
        read: false
      });

      message.$save(function(response) {

        $scope.content = '';
        $scope.isSending = false;

        // Emit a 'chatMessage' message event
        //Socket.emit('message.sent', message);

        // Remove this when socket is back!
        $scope.messages.unshift(response);
        $timeout(threadScrollBottom, 300);

      }, function(errorResponse) {
        $scope.isSending = false;
        // Show alert
        messageCenterService.add('danger', errorResponse.data.message, { timeout: flashTimeout });
      });

    };

    /**
     * Listen to received/sent messages and add them to our model
     */
     /*
    Socket.on('message.sent', function(message) {
      message.pushed = true; // flag as pushed
      //$scope.messages.push(message);
      $scope.messages.unshift(message);
      $timeout(threadScrollBottom, 300);
    });
    // Remove the event listener when the controller instance is destroyed
    $scope.$on('$destroy', function() {
      Socket.removeListener('message.sent');
    });
    */

  }
]);
<commit_msg>Don't flash own messages unread<commit_after>'use strict';

/* This declares to JSHint that these are global variables: */
/*global flashTimeout:false */

angular.module('messages').controller('MessagesThreadController', ['$scope', '$stateParams', '$state', '$document', '$window', '$anchorScroll', '$timeout', 'Authentication', 'Messages', 'MessagesRead', 'messageCenterService', //'Socket',
  function($scope, $stateParams, $state, $document, $window, $anchorScroll, $timeout, Authentication, Messages, MessagesRead, messageCenterService) {//, Socket

    // If no recepient defined, go to inbox
    if (!$stateParams.userId) $state.go('inboxMessages');

    // Vars
    $scope.user = Authentication.user;
    $scope.userToId = $stateParams.userId;
    $scope.isSending = false;
    var flaggedAsRead = [];

    $scope.messages = [];
    $scope.messageHandler = new Messages();
    // Attach userID for backend calls
    var fetchMessages = function(){return( $scope.messageHandler.fetchMessages({userId: $stateParams.userId}) ); };

    // No sending messages to yourself
    if ($scope.user._id === $scope.userToId) $state.go('inboxMessages');

    // Appends returned messages to model
    function addMessages(data){
      angular.forEach(data, function(msg){
        $scope.messages.push(msg);
      });
      threadLayoutUpdate();
    }

    /*
     * Gets next page of messages
     * Activates when the first(top most) message hits the top viewport
     */
    $scope.moreMessages = function(){
      if($scope.messageHandler.nextPage) {
        var oldHeight = threadLayoutThread[0].scrollHeight;

        fetchMessages().$promise.then( function(data) {
          setScrollPosition(oldHeight);
          addMessages(data);
        });
      }
    };

    /**
     * Restores scroll position after pagination
     * Timeout is in place to force function to execute after digest cycle to properly calculate scroll height.
     */
    function setScrollPosition(oldHeight) {
      $timeout(function () {
        var newHeight = threadLayoutThread[0].scrollHeight;
        angular.element(threadLayoutThread.scrollTop(newHeight - oldHeight));
      });
    }

    /**
     * Calculate thread etc layout locations with this massive pile of helpers
     */
    var threadLayoutContainer = angular.element('#thread-container'),
        threadLayoutThread = angular.element('#messages-thread'),
        threadLayoutReply = angular.element('#message-reply');

    // Add (or reset) timeout to not call the resizing function every pixel
    var threadLayoutUpdateTimeout;
    function threadLayoutUpdate() {
      $timeout.cancel(threadLayoutUpdateTimeout);
      threadLayoutUpdateTimeout = $timeout(threadLayout, 300);
    }

    // Keep thread in good condition when screen resizes/orientation changes/message textrea grows
    // This sorta should be at .less files, but the message thread is such an complicated peace of UI...
    // Mostly this is needed due growing text field
    function threadLayout() {

      $scope.replyHeight = threadLayoutReply.height() + 'px';

      // container has 15px padding on both sides when window is bigger than screen-sm-max (768px)
      var containerPadding = ($window.innerWidth < 768) ? -15 : 30;
      $scope.containerWidth = threadLayoutContainer.width() - containerPadding + 'px';
      $scope.replyWidth = threadLayoutContainer.width() - 30 + 'px';
    }

    // Add (or reset) timeout to not call the scrolling function every key stroke
    var threadScrollUpdateTimeout;
    function threadScrollUpdate() {
      $timeout.cancel(threadScrollUpdateTimeout);
      threadScrollUpdateTimeout = $timeout(threadScrollBottom, 300);
    }

    // Scroll thread to bottom to show latest messages
    function threadScrollBottom() {
      threadLayoutThread.scrollTop(threadLayoutThread[0].scrollHeight);
    }

    // Keep layout in good order with these listeners
    angular.element($window).on('resize', threadLayoutUpdate);
    angular.element($window).bind('orientationchange', threadLayoutUpdate);
    angular.element($window).bind('orientationchange', threadScrollBottom);

    // Fire html.resize() so that jQuery-Waypoints can check what's visible on the screen and mark visible messages read.
    var onScrollTimeout,
        html = angular.element('html');
    threadLayoutThread.bind('scroll', function() {
        if(onScrollTimeout) $timeout.cancel(onScrollTimeout);
        onScrollTimeout = $timeout(function(){ html.resize(); }, 300);
    });

    $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
      // Fetches first page of messages
      fetchMessages().$promise.then( function(data){
        addMessages(data);
        $timeout(threadScrollBottom,500);
      });
    });

    // Observe for the reply area height while typing your awesome message in it
    angular.element('#message-reply-content').on('input', function() {
      $scope.replyHeight = threadLayoutReply.height() + 15 + 'px';
      threadScrollUpdate();
    });

    /**
     * Send messages marked as read (at frontend) to the backend
     * Has 1s timeout to slow down continuous pinging of the API
     */
    var syncReadTimer;
    function activateSyncRead() {
      // Cancel previously set timer
      if(syncReadTimer) $timeout.cancel(syncReadTimer);
      // syncRead happens with 1s delay
      // (and gets postponed by 1s if new activateSyncRead() happens)
      if(flaggedAsRead.length > 0) {
        syncReadTimer = $timeout(syncRead, 1000);
      }
    }
    function syncRead() {
      MessagesRead.query({
        messageIds: flaggedAsRead
      }, function(response){
        flaggedAsRead = [];
      });
    }

    /**
     * Mark message read at the frontend
     * This function inits each time message div passes viewport
     * Read message id is stored at array which will be sent to backend and emptied
     *
     * @todo: kill observer after message is marked read
     */
    $scope.messageRead = function(message, scrollingUp, scrollingDown) {

      // It was read earlier
      if(message.read === true) return true;

      // Own messages are always read
      if(message.userFrom._id === $scope.user._id) return true;

      // It got marked read just now
      var read = (scrollingUp === true || scrollingDown === true);
      if(message.userFrom._id !== Authentication.user._id && !message.read && read) {
        message.read = true;
        flaggedAsRead.push(message._id);
        activateSyncRead();
      }

      return read;
    };

    /**
     * Send a message
     */
    $scope.send = function() {
      $scope.isSending = true;

      if(this.content === '

' || this.content.trim() === '') {
        $scope.isSending = false;
        messageCenterService.add('warning', 'Write a message first...', { timeout: flashTimeout });
        return;
      }

      var message = new $scope.messageHandler.ajaxCall({
        content: this.content,
        userTo: $stateParams.userId,
        read: false
      });

      message.$save(function(response) {

        $scope.content = '';
        $scope.isSending = false;

        // Emit a 'chatMessage' message event
        //Socket.emit('message.sent', message);

        // Remove this when socket is back!
        $scope.messages.unshift(response);
        $timeout(threadScrollBottom, 300);

      }, function(errorResponse) {
        $scope.isSending = false;
        // Show alert
        messageCenterService.add('danger', errorResponse.data.message, { timeout: flashTimeout });
      });

    };

    /**
     * Listen to received/sent messages and add them to our model
     */
     /*
    Socket.on('message.sent', function(message) {
      message.pushed = true; // flag as pushed
      //$scope.messages.push(message);
      $scope.messages.unshift(message);
      $timeout(threadScrollBottom, 300);
    });
    // Remove the event listener when the controller instance is destroyed
    $scope.$on('$destroy', function() {
      Socket.removeListener('message.sent');
    });
    */

  }
]);
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose');

mongoose.model('User', require('./User'));

mongoose.connect("mongodb://localhost/passport-lesson");

module.exports = mongoose;
<commit_msg>Set mongoose to use native promises<commit_after>'use strict';

var mongoose = require('mongoose');
mongoose.Promise = Promise;

mongoose.model('User', require('./User'));

mongoose.connect("mongodb://localhost/passport-lesson");

module.exports = mongoose;
<|endoftext|>


<commit_before>const Table = require('cli-table');
const HTMLTable = require('./html-table');
const formatRow = require('./format-row');

require('colors');

const lineBreak = '\n';

const write = (processedFiles, activeMinifiers, asHTML, measureGzip, showTotal, filter) => {
  process.stdout.write(lineBreak);

  const data = activeMinifiers.slice(0).map(minifier => {
    if (asHTML && minifier.url)
      return `<a href="${minifier.url}">${minifier.name} - ${minifier.version}</a>`;
    return `${minifier.name} - ${minifier.version}`;
  });

  // this is needed for the table's first `th`
  data.unshift('File');
  const date = new Date();
  data.date = {};
  data.date.human = `${date.toUTCString()}`;
  data.date.iso = `${date.toISOString()}`;

  const opts = { data };
  const results = asHTML ? HTMLTable(opts) : new Table(opts);
  let totalLength = 0;

  Object.keys(processedFiles).forEach(filename => {
    const fileSizeKey = filter === 'gzip' ? 'gzip' : 'size';
    const fileSize = processedFiles[filename][fileSizeKey];
    const size = asHTML ?
      ` - <em>${fileSize} bytes</em>` :
      ` - ${fileSize} bytes`;
    totalLength += fileSize;

    const row = [filename + size];

    activeMinifiers.forEach(minifier => {
      row.push(formatRow(asHTML, minifier.results[filename], measureGzip, filter));
    });

    results.push(row);
  });

  if (showTotal) {
    const totalRow = [`${asHTML ?
      `<span class="text-uppercase font-weight-bold">Total</span> - <em>${totalLength} bytes</em>` :
      `TOTAL - ${totalLength} bytes`}`];
    activeMinifiers.forEach(minifier => {
      totalRow.push(formatRow(asHTML, minifier.total, measureGzip, filter));
    });

    results.push(totalRow);
  }

  process.stdout.write(results.toString());
  process.stdout.write(lineBreak);
};

module.exports.getOutput = (asHTML, measureGzip, total) => {
  return (files, results) => {
    write(files, results, asHTML, measureGzip, total, measureGzip ? 'gzip' : 'size');
  };
};
<commit_msg>Fix CLI table header.<commit_after>const Table = require('cli-table');
const HTMLTable = require('./html-table');
const formatRow = require('./format-row');

require('colors');

const lineBreak = '\n';

const write = (processedFiles, activeMinifiers, asHTML, measureGzip, showTotal, filter) => {
  process.stdout.write(lineBreak);

  const data = activeMinifiers.slice(0).map(minifier => {
    if (asHTML && minifier.url)
      return `<a href="${minifier.url}">${minifier.name} - ${minifier.version}</a>`;
    return `${minifier.name} - ${minifier.version}`;
  });

  const date = new Date();
  data.date = {};
  data.date.human = `${date.toUTCString()}`;
  data.date.iso = `${date.toISOString()}`;

  // this is needed for the table's first `th`
  if (asHTML) {
    data.unshift('File');
  } else {
    data.unshift(`Generated on ${data.date.iso.replace(/T.+$/g, '')}`);
  }

  const results = asHTML ? HTMLTable({ data }) : new Table({ head: data });
  let totalLength = 0;

  Object.keys(processedFiles).forEach(filename => {
    const fileSizeKey = filter === 'gzip' ? 'gzip' : 'size';
    const fileSize = processedFiles[filename][fileSizeKey];
    const size = asHTML ?
      ` - <em>${fileSize} bytes</em>` :
      ` - ${fileSize} bytes`;
    totalLength += fileSize;

    const row = [filename + size];

    activeMinifiers.forEach(minifier => {
      row.push(formatRow(asHTML, minifier.results[filename], measureGzip, filter));
    });

    results.push(row);
  });

  if (showTotal) {
    const totalRow = [`${asHTML ?
      `<span class="text-uppercase font-weight-bold">Total</span> - <em>${totalLength} bytes</em>` :
      `TOTAL - ${totalLength} bytes`}`];
    activeMinifiers.forEach(minifier => {
      totalRow.push(formatRow(asHTML, minifier.total, measureGzip, filter));
    });

    results.push(totalRow);
  }

  process.stdout.write(results.toString());
  process.stdout.write(lineBreak);
};

module.exports.getOutput = (asHTML, measureGzip, total) => {
  return (files, results) => {
    write(files, results, asHTML, measureGzip, total, measureGzip ? 'gzip' : 'size');
  };
};
<|endoftext|>


<commit_before>//deps state_view.js

var LEFTMOST_CHUNK_INDEX = 0;
var VISIBLE_CHUNK_INDEX = 1;

// ContentView draws a ViewProvider with y-axis labels.
function ContentView(attrs) {
  this._currentState = new State(new PositiveState({}), new NormativeState({}));
  StateView.call(this, this._currentState, attrs);

  this._registerDataSourceEvents();
  this._registerProviderEvents();
  this._registerButtonEvents();

  this._initializeState();
}

ContentView.prototype = Object.create(StateView.prototype);

ContentView.prototype.dispose = function() {
  StateView.prototype.dispose.call(this);

  this._dataSource.cancel(LEFTMOST_CHUNK_INDEX);
  this._dataSource.cancel(VISIBLE_CHUNK_INDEX);

  this._deregisterDataSourceEvents();
  this._deregisterProviderEvents();
};

ContentView.prototype.draw = function(viewportX, viewportWidth, height, barShowingHeight) {
  if (this._currentState.positive.viewportWidth !== viewportWidth) {
    this.element().style.width = viewportWidth + 'px';
  }
  if (this._currentState.positive.viewportHeight !== height) {
    this.element().style.height = height + 'px';
  }
  if (this.shouldUpdateRequestedViewportX()) {
    this._currentState.positive.requestedViewportX = viewportX;
  }
  this._currentState.positive.viewportX = viewportX;
  this._currentState.positive.viewportWidth = viewportWidth;
  this._currentState.positive.viewportHeight = height;
  this._currentState.positive.barShowingHeight = barShowingHeight;
  this._recomputeLeftmostLabelWidth(false);
  this._updateNormativeState();
  this.updateState(this._currentState);
};

ContentView.prototype._initializeState = function() {
  this._recomputeContentWidthAndLength();
  this._currentState.positive.dataSourceLength = this._dataSource.getLength();
  this.updateStateVisualStyleChange(this._currentState);
};

ContentView.prototype._registerDataSourceEvents = function() {
  this._boundDataSourceEvents = {};
  var eventNames = ['Load', 'Error', 'Delete', 'Insert', 'Modify', 'Invalidate'];
  for (var i = 0, len = eventNames.length; i < len; ++i) {
    var eventName = eventNames[i];
    var handler = this['_handleDataSource' + eventName].bind(this);
    this._boundDataSourceEvents[eventName.toLowerCase()] = handler;
    this._dataSource.on(eventName.toLowerCase(), handler)
  }
};

ContentView.prototype._deregisterDataSourceEvents = function() {
  var keys = Object.keys(this._boundDataSourceEvents);
  for (var i = 0, len = keys.length; i < len; ++i) {
    var key = keys[i];
    this._dataSource.removeListener(key, this._boundDataSourceEvents[key])
  }
};

ContentView.prototype._handleDataSourceLoad = function(chunkIndex) {
  if (chunkIndex === LEFTMOST_CHUNK_INDEX) {
    this._recomputeLeftmostLabelWidth(true);
    this._currentState.normative.needsLeftmostChunk = false;
    this._currentState.normative.loadingLeftmostChunk = false;
    var chunk = this._dataSource.getChunk(LEFTMOST_CHUNK_INDEX);
    this._currentState.positive.leftmostChunkLength = chunk.getLength();
  } else {
    this._currentState.normative.needsVisibleChunk = false;
    this._currentState.normative.loadingVisibleChunk = false;
    var chunk = this._dataSource.getChunk(VISIBLE_CHUNK_INDEX);
    this._currentState.positive.visibleChunkStart = chunk.getStartIndex();
    this._currentState.positive.visibleChunkLength = chunk.getLength();
  }

  this.updateState(this._currentState);
};

ContentView.prototype._handleDataSourceError = function(chunkIndex) {
  if (chunkIndex === LEFTMOST_CHUNK_INDEX) {
    this._currentState.normative.loadingLeftmostChunk = false;
  } else {
    this._currentState.normative.loadingVisibleChunk = false;
  }
  this.updateState(this._currentState);
};

ContentView.prototype._handleDataSourceDelete = function(oldIndex) {
  this._recomputeContentWidthAndLength();
  if (oldIndex < this.currentState.positive.leftmostChunkLength) {
    --this._currentState.positive.leftmostChunkLength;
    this._recomputeLeftmostLabelWidth(true);
  }
  if (oldIndex < this._currentState.visibleChunkStart) {
    --this._currentState.visibleChunkStart;
  } else if (oldIndex < this._currentState.visibleChunkStart +
             this._currentState.visibleChunkLength) {
    --this._currentState.visibleChunkLength;
  }
  this._updateNormativeState();
  this.updateStateDelete(this._currentState, oldIndex);
};

ContentView.prototype._handleDataSourceInsert = function(index) {
  this._recomputeContentWidthAndLength();
  if (index <= this._currentState.positive.leftmostChunkLength) {
    ++this._currentState.positive.leftmostChunkLength;
    this._recomputeLeftmostLabelWidth(true);
  }
  if (index < this._currentState.visibleChunkStart) {
    ++this._currentState.visibleChunkStart;
  } else if (index < this._currentState.visibleChunkStart + this._currentState.visibleChunkLength) {
    ++this._currentState.visibleChunkLength;
  }
  this._updateNormativeState();
  this.updateStateInsert(this._currentState, index);
};

ContentView.prototype._handleDataSourceModify = function(index) {
  this._recomputeContentWidthAndLength();
  if (index < this._currentState.positive.leftmostChunkLength) {
    this._recomputeLeftmostLabelWidth(true);
  }
  this._updateNormativeState();
  this.updateStateModify(this._currentState, index);
};

ContentView.prototype._handleDataSourceInvalidate = function() {
  this._currentState.positive.leftmostChunkLength = -1;
  this._currentState.positive.visibleChunkLength = -1;
  this._currentState.positive.visibleChunkStart = -1;
  this._recomputeContentWidthAndLength();
  this._recomputeLeftmostLabelWidth(true);
  this._updateNormativeState();
  this.updateStateInvalidate(this._currentState);
};

ContentView.prototype._registerProviderEvents = function() {
  this._boundProviderChange = this._handleProviderChange.bind(this);
  this._provider.on('change', this._boundProviderChange);
};

ContentView.prototype._deregisterProviderEvents = function() {
  this._provider.removeListener('change', this._boundProviderChange);
};

ContentView.prototype._handleProviderChange = function() {
  this._recomputeContentWidthAndLength();
  this._recomputeLeftmostLabelWidth(true);
  this._updateNormativeState();
  this.updateStateVisualStyleChange(this._currentState);
};

ContentView.prototype._registerButtonEvents = function() {
  var loaders = [this._loader1, this._loader2];
  for (var i = 0; i < 2; ++i) {
    var loader = loaders[i];
    loader.on('retry', function() {
      if (this._currentState.normative.needsVisibleChunk) {
        var oldState = new NormativeState(this._currentState.normative);
        this._currentState.normative.loadingVisibleChunk = true;
        this._handleNormativeChange(oldState);
        this.updateState(this._currentState);
      }
    }.bind(this));
  }
  this._splashScreen.on('retry', function() {
    var oldState = new NormativeState(this._currentState.normative);
    if (this._currentState.normative.needsVisibleChunk) {
      this._currentState.normative.loadingVisibleChunk = true;
    }
    if (this._currentState.normative.needsLeftmostChunk) {
      this._currentState.normative.loadingLeftmostChunk = true;
    }
    this._handleNormativeChange(oldState);
    this.updateState(this._currentState);
  }.bind(this));
};

ContentView.prototype._recomputeContentWidthAndLength = function() {
  this._currentState.positive.dataSourceLength = this._dataSource.getLength();
  var theoreticalChunk = {
    startIndex: 0,
    length: this._currentState.positive.dataSourceLength
  };
  this._currentState.positive.contentWidth = this._provider.computeRegion(theoreticalChunk,
    theoreticalChunk.length).width;
};

ContentView.prototype._recomputeLeftmostLabelWidth = function(force) {
  var region = {
    left: 0,
    width: this._currentState.positive.viewportWidth
  };
  var useChunk = this._provider.computeTheoreticalChunk(region, this._dataSource.getLength());

  assert(useChunk.startIndex === 0);
  if (!force && useChunk.length === this._currentState.positive.leftmostYLabelsPointCount) {
    return;
  }

  var leftmostChunk = this._dataSource.getChunk(LEFTMOST_CHUNK_INDEX);
  if (leftmostChunk === null || useChunk.length > leftmostChunk.length) {
    this._currentState.positive.leftmostChunkLength = -1;
    this._currentState.positive.leftmostYLabelsWidth = -1;
    this._currentState.positive.leftmostYLabelsPointCount = -1;
    return;
  }

  var maxPoint = 0;
  for (var i = 0, len = useChunk.length; i < len; ++i) {
    maxPoint = Math.max(maxPoint, leftmostChunk.getDataPoint(i).primary);
  }

  var usableHeight = this._currentState.positive.barShowingHeight - this._topMargin -
    this._bottomMargin;
  if (usableHeight < 0) {
    usableHeight = 0;
  }
  var labels = this._labelGenerator.createLabels(maxPoint, usableHeight);
  this._currentState.positive.leftmostYLabelsWidth = labels.width();
  this._currentState.positive.leftmostYLabelsPointCount = useChunk.length;
};

// _updateNormativeState recomputes the current normative state and then starts/cancels operations
// on the DataSource accordingly.
ContentView.prototype._updateNormativeState = function() {
  var oldState = new NormativeState(this._currentState.normative);
  this._currentState.normative.recompute(this._provider, this._currentState.positive);
  this._handleNormativeChange(oldState);
};

// _handleNormativeChange starts/cancels operations on the DataSource according to changes in the
// normative state.
ContentView.prototype._handleNormativeChange = function(oldState) {
  var newState = this._currentState.normative;
  if (newState.loadingLeftmostChunk !== oldState.loadingLeftmostChunk) {
    if (newState.loadingLeftmostChunk) {
      this._dataSource.fetchChunk(LEFTMOST_CHUNK_INDEX, 0, newState.leftmostChunkLength);
    } else {
      this._dataSource.cancel(LEFTMOST_CHUNK_INDEX);
    }
  } else if (newState.loadingLeftmostChunk &&
             newState.leftmostChunkLength !== oldState.leftmostChunkLength) {
    this._dataSource.fetchChunk(LEFTMOST_CHUNK_INDEX, 0, newState.leftmostChunkLength);
  }

  if (newState.loadingVisibleChunk !== oldState.loadingVisibleChunk) {
    if (newState.loadingVisibleChunk) {
      this._dataSource.fetchChunk(VISIBLE_CHUNK_INDEX, newState.visibleChunkStart,
        newState.visibleChunkLength);
    } else {
      this._dataSource.cancel(VISIBLE_CHUNK_INDEX);
    }
  } else if (newState.loadingVisibleChunk &&
             (newState.visibleChunkLength !== oldState.visibleChunkLength ||
              newState.visibleChunkStart !== oldState.visibleChunkStart)) {
    this._dataSource.fetchChunk(VISIBLE_CHUNK_INDEX, newState.visibleChunkStart,
      newState.visibleChunkLength);
  }
};

exports.ContentView = ContentView;
<commit_msg>fixed ContentView's positive state updating code<commit_after>//deps state_view.js

var LEFTMOST_CHUNK_INDEX = 0;
var VISIBLE_CHUNK_INDEX = 1;

// ContentView draws a ViewProvider with y-axis labels.
function ContentView(attrs) {
  this._currentState = new State(new PositiveState({}), new NormativeState({}));
  StateView.call(this, this._currentState, attrs);

  this._registerDataSourceEvents();
  this._registerProviderEvents();
  this._registerButtonEvents();

  this._initializeState();
}

ContentView.prototype = Object.create(StateView.prototype);

ContentView.prototype.dispose = function() {
  StateView.prototype.dispose.call(this);

  this._dataSource.cancel(LEFTMOST_CHUNK_INDEX);
  this._dataSource.cancel(VISIBLE_CHUNK_INDEX);

  this._deregisterDataSourceEvents();
  this._deregisterProviderEvents();
};

ContentView.prototype.draw = function(viewportX, viewportWidth, height, barShowingHeight) {
  if (this._currentState.positive.viewportWidth !== viewportWidth) {
    this.element().style.width = viewportWidth + 'px';
  }
  if (this._currentState.positive.viewportHeight !== height) {
    this.element().style.height = height + 'px';
  }
  if (this.shouldUpdateRequestedViewportX()) {
    this._currentState.positive.requestedViewportX = viewportX;
  }
  this._currentState.positive.viewportX = viewportX;
  this._currentState.positive.viewportWidth = viewportWidth;
  this._currentState.positive.viewportHeight = height;
  this._currentState.positive.barShowingHeight = barShowingHeight;
  this._recomputeLeftmostLabelWidth(false);
  this._updateNormativeState();
  this.updateState(this._currentState);
};

ContentView.prototype._initializeState = function() {
  this._recomputeContentWidthAndLength();
  this._currentState.positive.dataSourceLength = this._dataSource.getLength();
  this.updateStateVisualStyleChange(this._currentState);
};

ContentView.prototype._registerDataSourceEvents = function() {
  this._boundDataSourceEvents = {};
  var eventNames = ['Load', 'Error', 'Delete', 'Insert', 'Modify', 'Invalidate'];
  for (var i = 0, len = eventNames.length; i < len; ++i) {
    var eventName = eventNames[i];
    var handler = this['_handleDataSource' + eventName].bind(this);
    this._boundDataSourceEvents[eventName.toLowerCase()] = handler;
    this._dataSource.on(eventName.toLowerCase(), handler)
  }
};

ContentView.prototype._deregisterDataSourceEvents = function() {
  var keys = Object.keys(this._boundDataSourceEvents);
  for (var i = 0, len = keys.length; i < len; ++i) {
    var key = keys[i];
    this._dataSource.removeListener(key, this._boundDataSourceEvents[key])
  }
};

ContentView.prototype._handleDataSourceLoad = function(chunkIndex) {
  if (chunkIndex === LEFTMOST_CHUNK_INDEX) {
    this._recomputeLeftmostLabelWidth(true);
    this._currentState.normative.needsLeftmostChunk = false;
    this._currentState.normative.loadingLeftmostChunk = false;
    var chunk = this._dataSource.getChunk(LEFTMOST_CHUNK_INDEX);
    this._currentState.positive.leftmostChunkLength = chunk.getLength();
  } else {
    this._currentState.normative.needsVisibleChunk = false;
    this._currentState.normative.loadingVisibleChunk = false;
    var chunk = this._dataSource.getChunk(VISIBLE_CHUNK_INDEX);
    this._currentState.positive.visibleChunkStart = chunk.getStartIndex();
    this._currentState.positive.visibleChunkLength = chunk.getLength();
  }

  this.updateState(this._currentState);
};

ContentView.prototype._handleDataSourceError = function(chunkIndex) {
  if (chunkIndex === LEFTMOST_CHUNK_INDEX) {
    this._currentState.normative.loadingLeftmostChunk = false;
  } else {
    this._currentState.normative.loadingVisibleChunk = false;
  }
  this.updateState(this._currentState);
};

ContentView.prototype._handleDataSourceDelete = function(oldIndex) {
  this._recomputeContentWidthAndLength();
  if (oldIndex < this.currentState.positive.leftmostChunkLength) {
    --this._currentState.positive.leftmostChunkLength;
    this._recomputeLeftmostLabelWidth(true);
  }
  if (oldIndex < this._currentState.positive.visibleChunkStart) {
    --this._currentState.positive.visibleChunkStart;
  } else if (oldIndex < this._currentState.positive.visibleChunkStart +
             this._currentState.positive.visibleChunkLength) {
    --this._currentState.positive.visibleChunkLength;
  }
  this._updateNormativeState();
  this.updateStateDelete(this._currentState, oldIndex);
};

ContentView.prototype._handleDataSourceInsert = function(index) {
  this._recomputeContentWidthAndLength();
  if (index <= this._currentState.positive.leftmostChunkLength) {
    ++this._currentState.positive.leftmostChunkLength;
    this._recomputeLeftmostLabelWidth(true);
  }
  if (index < this._currentState.positive.visibleChunkStart) {
    ++this._currentState.positive.visibleChunkStart;
  } else if (index < this._currentState.positive.visibleChunkStart +
             this._currentState.positive.visibleChunkLength) {
    ++this._currentState.positive.visibleChunkLength;
  }
  this._updateNormativeState();
  this.updateStateInsert(this._currentState, index);
};

ContentView.prototype._handleDataSourceModify = function(index) {
  this._recomputeContentWidthAndLength();
  if (index < this._currentState.positive.leftmostChunkLength) {
    this._recomputeLeftmostLabelWidth(true);
  }
  this._updateNormativeState();
  this.updateStateModify(this._currentState, index);
};

ContentView.prototype._handleDataSourceInvalidate = function() {
  this._currentState.positive.leftmostChunkLength = -1;
  this._currentState.positive.visibleChunkLength = -1;
  this._currentState.positive.visibleChunkStart = -1;
  this._recomputeContentWidthAndLength();
  this._recomputeLeftmostLabelWidth(true);
  this._updateNormativeState();
  this.updateStateInvalidate(this._currentState);
};

ContentView.prototype._registerProviderEvents = function() {
  this._boundProviderChange = this._handleProviderChange.bind(this);
  this._provider.on('change', this._boundProviderChange);
};

ContentView.prototype._deregisterProviderEvents = function() {
  this._provider.removeListener('change', this._boundProviderChange);
};

ContentView.prototype._handleProviderChange = function() {
  this._recomputeContentWidthAndLength();
  this._recomputeLeftmostLabelWidth(true);
  this._updateNormativeState();
  this.updateStateVisualStyleChange(this._currentState);
};

ContentView.prototype._registerButtonEvents = function() {
  var loaders = [this._loader1, this._loader2];
  for (var i = 0; i < 2; ++i) {
    var loader = loaders[i];
    loader.on('retry', function() {
      if (this._currentState.normative.needsVisibleChunk) {
        var oldState = new NormativeState(this._currentState.normative);
        this._currentState.normative.loadingVisibleChunk = true;
        this._handleNormativeChange(oldState);
        this.updateState(this._currentState);
      }
    }.bind(this));
  }
  this._splashScreen.on('retry', function() {
    var oldState = new NormativeState(this._currentState.normative);
    if (this._currentState.normative.needsVisibleChunk) {
      this._currentState.normative.loadingVisibleChunk = true;
    }
    if (this._currentState.normative.needsLeftmostChunk) {
      this._currentState.normative.loadingLeftmostChunk = true;
    }
    this._handleNormativeChange(oldState);
    this.updateState(this._currentState);
  }.bind(this));
};

ContentView.prototype._recomputeContentWidthAndLength = function() {
  this._currentState.positive.dataSourceLength = this._dataSource.getLength();
  var theoreticalChunk = {
    startIndex: 0,
    length: this._currentState.positive.dataSourceLength
  };
  this._currentState.positive.contentWidth = this._provider.computeRegion(theoreticalChunk,
    theoreticalChunk.length).width;
};

ContentView.prototype._recomputeLeftmostLabelWidth = function(force) {
  var region = {
    left: 0,
    width: this._currentState.positive.viewportWidth
  };
  var useChunk = this._provider.computeTheoreticalChunk(region, this._dataSource.getLength());

  assert(useChunk.startIndex === 0);
  if (!force && useChunk.length === this._currentState.positive.leftmostYLabelsPointCount) {
    return;
  }

  var leftmostChunk = this._dataSource.getChunk(LEFTMOST_CHUNK_INDEX);
  if (leftmostChunk === null || useChunk.length > leftmostChunk.length) {
    this._currentState.positive.leftmostChunkLength = -1;
    this._currentState.positive.leftmostYLabelsWidth = -1;
    this._currentState.positive.leftmostYLabelsPointCount = -1;
    return;
  }

  var maxPoint = 0;
  for (var i = 0, len = useChunk.length; i < len; ++i) {
    maxPoint = Math.max(maxPoint, leftmostChunk.getDataPoint(i).primary);
  }

  var usableHeight = this._currentState.positive.barShowingHeight - this._topMargin -
    this._bottomMargin;
  if (usableHeight < 0) {
    usableHeight = 0;
  }
  var labels = this._labelGenerator.createLabels(maxPoint, usableHeight);
  this._currentState.positive.leftmostYLabelsWidth = labels.width();
  this._currentState.positive.leftmostYLabelsPointCount = useChunk.length;
};

// _updateNormativeState recomputes the current normative state and then starts/cancels operations
// on the DataSource accordingly.
ContentView.prototype._updateNormativeState = function() {
  var oldState = new NormativeState(this._currentState.normative);
  this._currentState.normative.recompute(this._provider, this._currentState.positive);
  this._handleNormativeChange(oldState);
};

// _handleNormativeChange starts/cancels operations on the DataSource according to changes in the
// normative state.
ContentView.prototype._handleNormativeChange = function(oldState) {
  var newState = this._currentState.normative;
  if (newState.loadingLeftmostChunk !== oldState.loadingLeftmostChunk) {
    if (newState.loadingLeftmostChunk) {
      this._dataSource.fetchChunk(LEFTMOST_CHUNK_INDEX, 0, newState.leftmostChunkLength);
    } else {
      this._dataSource.cancel(LEFTMOST_CHUNK_INDEX);
    }
  } else if (newState.loadingLeftmostChunk &&
             newState.leftmostChunkLength !== oldState.leftmostChunkLength) {
    this._dataSource.fetchChunk(LEFTMOST_CHUNK_INDEX, 0, newState.leftmostChunkLength);
  }

  if (newState.loadingVisibleChunk !== oldState.loadingVisibleChunk) {
    if (newState.loadingVisibleChunk) {
      this._dataSource.fetchChunk(VISIBLE_CHUNK_INDEX, newState.visibleChunkStart,
        newState.visibleChunkLength);
    } else {
      this._dataSource.cancel(VISIBLE_CHUNK_INDEX);
    }
  } else if (newState.loadingVisibleChunk &&
             (newState.visibleChunkLength !== oldState.visibleChunkLength ||
              newState.visibleChunkStart !== oldState.visibleChunkStart)) {
    this._dataSource.fetchChunk(VISIBLE_CHUNK_INDEX, newState.visibleChunkStart,
      newState.visibleChunkLength);
  }
};

exports.ContentView = ContentView;
<|endoftext|>


<commit_before>/**
 * User model definition.
 */
define([
    'common/toolbox'
], function (Toolbox) {
    "use strict";

    var User = Toolbox.BaseClass.extend({
        constructor: function(details) {
            this.username = '';
            this.first_name = '';
            this.last_name = '';
            this.email = '';
            this.authenticated = false;
            this.token = '';
        },

        isAuthenticated: function() {
            return this.authenticated;
        }
    });

    return User;
});
<commit_msg>Fix codestyle.<commit_after>/**
 * User model definition.
 */
define([
    'common/toolbox'
], function (Toolbox) {
    "use strict";

    var User = Toolbox.BaseClass.extend({
        constructor: function(details) {
            this.username = '';
            this.firstName = '';
            this.lastName = '';
            this.email = '';
            this.authenticated = false;
            this.token = '';
        },

        isAuthenticated: function() {
            return this.authenticated;
        }
    });

    return User;
});
<|endoftext|>


<commit_before>'use strict';

/**
 * TasksController
 * controller for the view of tasks
 */
tasksModule.controller('TasksController',
    ['$scope', '$rootScope', '$state', '$stateParams', '$timeout', '$filter', '$http', 'fileSystemService', 'tasksService', '$cookies', '$interval',
        function ($scope, $rootScope, $state, $stateParams, $timeout, $filter, $http, fileSystemService, tasksService, $cookies, $interval) {

            console.log("tasks!");
            console.log($scope);

            $scope.myMessages = [];
            $scope.validTasks = {"no": "...not loaded..."};
            $scope.availableContainers = undefined;

            $scope.newTaskDefinition = {
                "type": "",
                "container": "",
                "tenant": $cookies.get('MCM-TENANT'),
                "token": $cookies.get('XSRF-TOKEN')
            };
            $scope.credentials = {
                "tenant": $cookies.get('MCM-TENANT'),
                "token": $cookies.get('XSRF-TOKEN')
            };

            /**
             *
             * Get the list of valid tasks
             *
             * */
            tasksService.getValidTasks()
                .then(function (response) {
                        $scope.validTasks = response.data;
                        if (!response.data) {
                            $rootScope.$broadcast('FlashMessage', {
                                "type": "danger",
                                "text": "unable to retrieve task list..."
                            });
                        }
                    },
                    function errorCallback(response) {
                        console.log(JSON.stringify(response));
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "danger",
                            "text": "Error: "
                            + response.data
                        });
                    });

            /**
             *
             * Get the list of container from swift
             *
             * */

            fileSystemService.getContainers("", "", 10000)
                .then(function (response) {
                    $scope.availableContainers = response.containers;
                    //console.log($scope.availableContainers);
                })
                .catch(function (response) {
                    if (401 == response.status) {
                        $state.go('loginState', {noAuth: true});
                        return;
                    }
                    $rootScope.$broadcast('FlashMessage', {
                        "type": "warning",
                        "text": response.data
                    });
                });

            /**
             *
             * send a new message
             *
             * */

            $scope.sendMessage = function () {
                tasksService.postMessage($scope.newTaskDefinition)
                    .then(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "success",
                            "text": "message sent"
                        });
                        //console.log($scope.availableContainers);
                    })
                    .catch(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "warning",
                            "text": response.data
                        });
                    })
            };

            /**
             *
             * receive the messages
             *
             * */

            $scope.receive_from_beginning = function () {
                tasksService.retrieveMessages($scope.credentials, true)
                    .then(function (response) {
                        $scope.myMessages = $scope.myMessages.concat(response.data);
                    })
                    .catch(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "warning",
                            "text": response.data
                        });
                    })
            };

            var receive = function () {
                tasksService.retrieveMessages($scope.credentials, false)
                    .then(function (response) {
                        $scope.myMessages = $scope.myMessages.concat(response.data);
                        //console.log(response.data);
                        $interval(function () {
                            receive();
                        }, 2000, 1);
                    })
                    .catch(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "warning",
                            "text": response.data
                        });
                    })
            };
            receive();

            /**
             *
             * clear the existing messages
             *
             * */
            $scope.clear_all_messages = function () {
                $scope.myMessages = [];
            };

            /**
             *
             * helper for html styling
             * */
            $scope.ui_color_for_msg = function (msg) {
                try {
                    return '#' + msg.correlation.substring(0,6);
                }
                 catch(err)
                     {
                    return "black";
                }

            };

            /**
             *
             * helper for html styling
             * */
            $scope.ui_icon_for_msg = function (msg) {
                try {
                    if (msg.type in $scope.validTasks) {
                        return "flight_takeoff";
                    } else if (msg.type.startsWith("response")) {
                        return "flight_landing";
                    } else if (msg.type.startsWith("success")) {
                        return "done";
                    } else{
                        return "code";
                    }
                }
                 catch(err)
                     {
                    return "code";
                }

            };

        }]);
<commit_msg>remove debug<commit_after>'use strict';

/**
 * TasksController
 * controller for the view of tasks
 */
tasksModule.controller('TasksController',
    ['$scope', '$rootScope', '$state', '$stateParams', '$timeout', '$filter', '$http', 'fileSystemService', 'tasksService', '$cookies', '$interval',
        function ($scope, $rootScope, $state, $stateParams, $timeout, $filter, $http, fileSystemService, tasksService, $cookies, $interval) {

            console.log("tasks!");

            $scope.myMessages = [];
            $scope.validTasks = {"no": "...not loaded..."};
            $scope.availableContainers = undefined;

            $scope.newTaskDefinition = {
                "type": "",
                "container": "",
                "tenant": $cookies.get('MCM-TENANT'),
                "token": $cookies.get('XSRF-TOKEN')
            };
            $scope.credentials = {
                "tenant": $cookies.get('MCM-TENANT'),
                "token": $cookies.get('XSRF-TOKEN')
            };

            /**
             *
             * Get the list of valid tasks
             *
             * */
            tasksService.getValidTasks()
                .then(function (response) {
                        $scope.validTasks = response.data;
                        if (!response.data) {
                            $rootScope.$broadcast('FlashMessage', {
                                "type": "danger",
                                "text": "unable to retrieve task list..."
                            });
                        }
                    },
                    function errorCallback(response) {
                        console.log(JSON.stringify(response));
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "danger",
                            "text": "Error: "
                            + response.data
                        });
                    });

            /**
             *
             * Get the list of container from swift
             *
             * */

            fileSystemService.getContainers("", "", 10000)
                .then(function (response) {
                    $scope.availableContainers = response.containers;
                    //console.log($scope.availableContainers);
                })
                .catch(function (response) {
                    if (401 == response.status) {
                        $state.go('loginState', {noAuth: true});
                        return;
                    }
                    $rootScope.$broadcast('FlashMessage', {
                        "type": "warning",
                        "text": response.data
                    });
                });

            /**
             *
             * send a new message
             *
             * */

            $scope.sendMessage = function () {
                tasksService.postMessage($scope.newTaskDefinition)
                    .then(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "success",
                            "text": "message sent"
                        });
                        //console.log($scope.availableContainers);
                    })
                    .catch(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "warning",
                            "text": response.data
                        });
                    })
            };

            /**
             *
             * receive the messages
             *
             * */

            $scope.receive_from_beginning = function () {
                tasksService.retrieveMessages($scope.credentials, true)
                    .then(function (response) {
                        $scope.myMessages = $scope.myMessages.concat(response.data);
                    })
                    .catch(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "warning",
                            "text": response.data
                        });
                    })
            };

            var receive = function () {
                tasksService.retrieveMessages($scope.credentials, false)
                    .then(function (response) {
                        $scope.myMessages = $scope.myMessages.concat(response.data);
                        //console.log(response.data);
                        $interval(function () {
                            receive();
                        }, 2000, 1);
                    })
                    .catch(function (response) {
                        $rootScope.$broadcast('FlashMessage', {
                            "type": "warning",
                            "text": response.data
                        });
                    })
            };
            receive();

            /**
             *
             * clear the existing messages
             *
             * */
            $scope.clear_all_messages = function () {
                $scope.myMessages = [];
            };

            /**
             *
             * helper for html styling
             * */
            $scope.ui_color_for_msg = function (msg) {
                try {
                    return '#' + msg.correlation.substring(0,6);
                }
                 catch(err)
                     {
                    return "black";
                }

            };

            /**
             *
             * helper for html styling
             * */
            $scope.ui_icon_for_msg = function (msg) {
                try {
                    if (msg.type in $scope.validTasks) {
                        return "flight_takeoff";
                    } else if (msg.type.startsWith("response")) {
                        return "flight_landing";
                    } else if (msg.type.startsWith("success")) {
                        return "done";
                    } else{
                        return "code";
                    }
                }
                 catch(err)
                     {
                    return "code";
                }

            };

        }]);
<|endoftext|>


<commit_before>// simple-todos.js

// TODO: Add tasks from console to populate collection
// On Server:
// db.tasks.insert({ text: "Hello world!", createdAt: new Date() });
// On Client:
// Tasks.insert({ text: "Hello world!", createdAt: new Date() });
Tasks = new Mongo.Collection("tasks");

if (Meteor.isClient) {
  // This code only runs on the client
  Template.body.helpers({
    tasks: function () {
      return Tasks.find({});
    }
  });

  // Inside the if (Meteor.isClient) block, right after Template.body.helpers:
  Template.body.events({
    "submit .new-task": function (event) {
      // This function is called when the new task form is submitted

      var text = event.target.text.value;

      Tasks.insert({
        text: text,
        createdAt: new Date() // current time
      });

      // Clear form
      event.target.text.value = "";

      // Prevent default form submit
      return false;
    }
  });

}

<commit_msg>WebApp-4b: Sort tasks by createdAt timestamp<commit_after>// simple-todos.js

// TODO: Add tasks from console to populate collection
// On Server:
// db.tasks.insert({ text: "Hello world!", createdAt: new Date() });
// On Client:
// Tasks.insert({ text: "Hello world!", createdAt: new Date() });
Tasks = new Mongo.Collection("tasks");

if (Meteor.isClient) {
  // This code only runs on the client
  Template.body.helpers({
    tasks: function () {
      // Show newest tasks first
      return Tasks.find({}, {sort: {createdAt: -1}});
    }
  });

  // Inside the if (Meteor.isClient) block, right after Template.body.helpers:
  Template.body.events({
    "submit .new-task": function (event) {
      // This function is called when the new task form is submitted

      var text = event.target.text.value;

      Tasks.insert({
        text: text,
        createdAt: new Date() // current time
      });

      // Clear form
      event.target.text.value = "";

      // Prevent default form submit
      return false;
    }
  });

}

<|endoftext|>