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

    var app = angular.module('lesson.controllers', []);

    app.controller('MainCtrl', ['$scope', 'LessonData', 'Answer', 'Progress', '$location', 'youtubePlayerApi', 'resolveActivityTemplate',
        function ($scope, LessonData, Answer, Progress, $location, youtubePlayerApi, resolveActivityTemplate) {

            window.ga = window.ga || function(){};

            youtubePlayerApi.events.onStateChange = function(event){
                window.onPlayerStateChange.call($scope.currentUnit, event);
                if (event.data === YT.PlayerState.ENDED) {
                    $scope.nextStep();
                    if(!$scope.$$phase) {
                        $scope.$apply();
                    }
                }
            };

            $scope.section = $scope.section || 'video';

            $scope.selectUnit = function(unit) {
                $scope.currentUnit = unit;
                if(unit.video) {
                    $scope.section = 'video';
                    $scope.play(unit.video.youtube_id);
                } else {
                    $scope.section = 'activity';
                }
                $scope.selectActivity(0);
            };

            $scope.locationChange = function(unitIndex) {
                $location.path('/' + unitIndex);
            };

            $scope.nextUnit = function() {
                var index = $scope.lesson.units.indexOf($scope.currentUnit);
                index++;

                if(index < $scope.lesson.units.length) {
                    $location.path('/{0}'.format(index+1));
                } else {
                    // no next unit, so mark it as the end,
                    // and the template will show a next lesson
                    $scope.section = 'end';
                }
            };

            $scope.play = function() {
                if($scope.currentUnit.video){
                    var youtube_id = $scope.currentUnit.video.youtube_id;
                    $scope.section = 'video';

                    youtubePlayerApi.loadPlayer().then(function(player){
                            if(player.getVideoData() &&
                                player.getVideoData().video_id === youtube_id) return;
                            player.cueVideoById(youtube_id);
                    });
                } else {
                    $scope.section = 'activity';
                }

            };

            $scope.selectActivity = function(index) {

                if($scope.currentUnit.activities && $scope.currentUnit.activities.length) {
                    $scope.currentActivity = $scope.currentUnit.activities[index];
                    $scope.activityTemplateUrl = resolveActivityTemplate($scope.currentActivity.type);

                    ga("send", "event", "activity", "select", $scope.currentActivity.id);

                    $scope.answer = Answer.get({activityId: $scope.currentActivity.id}, function(answer) {
                        var exp = $scope.currentActivity.expected;
                        var giv = answer.given;
                        // FIXME why this name?
                        // TODO test if professor changes the activity (create a new alternative, the user lost his answer?
                        var shouldUseLastAnswer = (exp !== null && exp !== undefined) &&
                            (angular.isArray(exp) && angular.isArray(giv) && giv.length === exp.length);

                        console.log(exp, giv, shouldUseLastAnswer);
                        if (!shouldUseLastAnswer) {
                            // Initialize empty given answer
                            if(angular.isArray($scope.currentActivity.expected)) {
                                answer.given = $scope.currentActivity.expected.map(function(){});
                            }
                            delete answer.correct;
                        }
                    },
                    function (error) {
                        console.log('answer does not exists or other errors');
                        var answer = {};
                        if(angular.isArray($scope.currentActivity.expected)) {
                            answer.given = $scope.currentActivity.expected.map(function(){});
                        }
                        $scope.answer = new Answer(answer);
                    });
                } else {
                    $scope.currentActivity = null;
                    $scope.activityTemplateUrl = null;
                }
            };

            $scope.sendAnswer = function() {
                console.log('mandando resposta');
                $scope.answer.activity = $scope.currentActivity.id;
                $scope.answer.$update({activityId: $scope.answer.activity}).then(function(d){
                    console.log(d, d.correct);
                    ga('send', 'event', 'activity', 'result', '', d.correct);
                    $scope.currentUnit.progress = Progress.get({unit: $scope.currentUnit.id})
                });
                ga('send', 'event', 'activity', 'submit');
            };

            $scope.nextStep = function(skipComment) {
                var progress;
                if($scope.section === 'video') {
                    if(angular.isArray($scope.currentUnit.activities) &&
                        $scope.currentUnit.activities.length > 0) {
                        $scope.section = 'activity';
                    } else {
                        progress = Progress.complete($scope.currentUnit.id);
                        $scope.currentUnit.progress = progress;
                        $scope.nextUnit();
                    }
                } else {
                    if($scope.section === 'activity' && !skipComment && $scope.currentActivity.comment) {
                        $scope.section = 'comment';
                    } else {
                        var index = $scope.currentUnit.activities.indexOf($scope.currentActivity);
                        if(index+1 === $scope.currentUnit.activities.length) {
                            $scope.currentUnit.progress = Progress.get({unit: $scope.currentUnit.id})
                            $scope.nextUnit();
                        } else {
                            $scope.selectActivity(index + 1);
                            $scope.section = 'activity';
                        }
                    }
                }
            };

            var start;
            $scope.$watch('currentUnit', function(currentUnit, lastUnit) {
                if(!$scope.lesson) return;
                // Changing Unit means unit starting
                if (start && lastUnit) {
                    var end = new Date().getTime();
                    ga('send', 'event', 'unit', 'time in unit',
                       $scope.lesson.course + ' - "' + $scope.lesson.name + '" - ' + lastUnit.id,
                       end - start);
                }
                ga('send', 'event', 'unit', 'start', $scope.lesson.course + ' - ' + $scope.lesson.name, $scope.currentUnit.id);
                start = new Date().getTime();
            });

            LessonData.then(function(lesson){
                $scope.lesson = lesson;

                var index = /\/(\d+)/.extract($location.path(), 1);
                index = parseInt(index, 10) - 1 || 0;
                $scope.selectUnit(lesson.units[index]);
                $scope.play();

                $scope.$on('$locationChangeSuccess', function (event, newLoc, oldLoc){
                   index = /#\/(\d+)/.extract(document.location.hash, 1);
                   index = parseInt(index, 10) - 1 || 0;
                   $scope.selectUnit(lesson.units[index]);
                });
            });
        }
    ]);

})(angular);

(function() {
    var _pauseFlag = false;
    var start, whole;

    var lastState = -1;

    function  onPlayerStateChange (event) {
        var video_id = event.target.getVideoData().video_id;

        if (event.data == YT.PlayerState.ENDED){
            if(! (lastState === YT.PlayerState.PAUSED ||   // workaround, YT in html5 mode will fire
                  lastState === YT.PlayerState.PLAYING)) { // event with ENDED state after cue video.
                event.data = lastState;
            } else {
                ga('send', 'event', 'videos', 'watch To end', video_id);
                if (whole === 'started') {
                    var stop = new Date().getTime();
                    var delta_s = (stop - start) / 1000;
                    ga('send', 'event', 'videos', 'time tO end', video_id, Math.round(delta_s));
                    whole = 'ended';
                }
            }
        }

        if (event.data == YT.PlayerState.PLAYING){
                ga('send', 'event', 'videos', 'play', video_id);
                _pauseFlag = false;
                if (whole !== 'ended' && whole !== 'started') {
                    start = new Date().getTime();
                    whole = 'started';
                }
        }

        if (event.data == YT.PlayerState.PAUSED && _pauseFlag === false){
            ga('send', 'event', 'videos', 'pause', video_id);
            _pauseFlag = true;
        }
        if (event.data == YT.PlayerState.BUFFERING){
            ga('send', 'event', 'videos', 'bufferIng', video_id);
        }
        if (event.data == YT.PlayerState.CUED){
            ga('send', 'event', 'videos', 'cueing', video_id);
        }

        lastState = event.data;
    }
    window.onPlayerStateChange = onPlayerStateChange;
})();
<commit_msg>jslint fix<commit_after>(function(angular){
    'use strict';

    var app = angular.module('lesson.controllers', []);

    app.controller('MainCtrl', ['$scope', 'LessonData', 'Answer', 'Progress', '$location', 'youtubePlayerApi', 'resolveActivityTemplate',
        function ($scope, LessonData, Answer, Progress, $location, youtubePlayerApi, resolveActivityTemplate) {

            window.ga = window.ga || function(){};

            youtubePlayerApi.events.onStateChange = function(event){
                window.onPlayerStateChange.call($scope.currentUnit, event);
                if (event.data === YT.PlayerState.ENDED) {
                    $scope.nextStep();
                    if(!$scope.$$phase) {
                        $scope.$apply();
                    }
                }
            };

            $scope.section = $scope.section || 'video';

            $scope.selectUnit = function(unit) {
                $scope.currentUnit = unit;
                if(unit.video) {
                    $scope.section = 'video';
                    $scope.play(unit.video.youtube_id);
                } else {
                    $scope.section = 'activity';
                }
                $scope.selectActivity(0);
            };

            $scope.locationChange = function(unitIndex) {
                $location.path('/' + unitIndex);
            };

            $scope.nextUnit = function() {
                var index = $scope.lesson.units.indexOf($scope.currentUnit);
                index++;

                if(index < $scope.lesson.units.length) {
                    $location.path('/{0}'.format(index+1));
                } else {
                    // no next unit, so mark it as the end,
                    // and the template will show a next lesson
                    $scope.section = 'end';
                }
            };

            $scope.play = function() {
                if($scope.currentUnit.video){
                    var youtube_id = $scope.currentUnit.video.youtube_id;
                    $scope.section = 'video';

                    youtubePlayerApi.loadPlayer().then(function(player){
                            if(player.getVideoData() &&
                                player.getVideoData().video_id === youtube_id) return;
                            player.cueVideoById(youtube_id);
                    });
                } else {
                    $scope.section = 'activity';
                }

            };

            $scope.selectActivity = function(index) {

                if($scope.currentUnit.activities && $scope.currentUnit.activities.length) {
                    $scope.currentActivity = $scope.currentUnit.activities[index];
                    $scope.activityTemplateUrl = resolveActivityTemplate($scope.currentActivity.type);

                    ga("send", "event", "activity", "select", $scope.currentActivity.id);

                    $scope.answer = Answer.get({activityId: $scope.currentActivity.id}, function(answer) {
                        var exp = $scope.currentActivity.expected;
                        var giv = answer.given;
                        // FIXME why this name?
                        // TODO test if professor changes the activity (create a new alternative, the user lost his answer?
                        var shouldUseLastAnswer = (exp !== null && exp !== undefined) &&
                            (angular.isArray(exp) && angular.isArray(giv) && giv.length === exp.length);

                        console.log(exp, giv, shouldUseLastAnswer);
                        if (!shouldUseLastAnswer) {
                            // Initialize empty given answer
                            if(angular.isArray($scope.currentActivity.expected)) {
                                answer.given = $scope.currentActivity.expected.map(function(){});
                            }
                            delete answer.correct;
                        }
                    },
                    function (error) {
                        console.log('answer does not exists or other errors');
                        var answer = {};
                        if(angular.isArray($scope.currentActivity.expected)) {
                            answer.given = $scope.currentActivity.expected.map(function(){});
                        }
                        $scope.answer = new Answer(answer);
                    });
                } else {
                    $scope.currentActivity = null;
                    $scope.activityTemplateUrl = null;
                }
            };

            $scope.sendAnswer = function() {
                console.log('mandando resposta');
                $scope.answer.activity = $scope.currentActivity.id;
                $scope.answer.$update({activityId: $scope.answer.activity}).then(function(d){
                    console.log(d, d.correct);
                    ga('send', 'event', 'activity', 'result', '', d.correct);
                    $scope.currentUnit.progress = Progress.get({unit: $scope.currentUnit.id});
                });
                ga('send', 'event', 'activity', 'submit');
            };

            $scope.nextStep = function(skipComment) {
                var progress;
                if($scope.section === 'video') {
                    if(angular.isArray($scope.currentUnit.activities) &&
                        $scope.currentUnit.activities.length > 0) {
                        $scope.section = 'activity';
                    } else {
                        progress = Progress.complete($scope.currentUnit.id);
                        $scope.currentUnit.progress = progress;
                        $scope.nextUnit();
                    }
                } else {
                    if($scope.section === 'activity' && !skipComment && $scope.currentActivity.comment) {
                        $scope.section = 'comment';
                    } else {
                        var index = $scope.currentUnit.activities.indexOf($scope.currentActivity);
                        if(index+1 === $scope.currentUnit.activities.length) {
                            $scope.currentUnit.progress = Progress.get({unit: $scope.currentUnit.id});
                            $scope.nextUnit();
                        } else {
                            $scope.selectActivity(index + 1);
                            $scope.section = 'activity';
                        }
                    }
                }
            };

            var start;
            $scope.$watch('currentUnit', function(currentUnit, lastUnit) {
                if(!$scope.lesson) return;
                // Changing Unit means unit starting
                if (start && lastUnit) {
                    var end = new Date().getTime();
                    ga('send', 'event', 'unit', 'time in unit',
                       $scope.lesson.course + ' - "' + $scope.lesson.name + '" - ' + lastUnit.id,
                       end - start);
                }
                ga('send', 'event', 'unit', 'start', $scope.lesson.course + ' - ' + $scope.lesson.name, $scope.currentUnit.id);
                start = new Date().getTime();
            });

            LessonData.then(function(lesson){
                $scope.lesson = lesson;

                var index = /\/(\d+)/.extract($location.path(), 1);
                index = parseInt(index, 10) - 1 || 0;
                $scope.selectUnit(lesson.units[index]);
                $scope.play();

                $scope.$on('$locationChangeSuccess', function (event, newLoc, oldLoc){
                   index = /#\/(\d+)/.extract(document.location.hash, 1);
                   index = parseInt(index, 10) - 1 || 0;
                   $scope.selectUnit(lesson.units[index]);
                });
            });
        }
    ]);

})(angular);

(function() {
    var _pauseFlag = false;
    var start, whole;

    var lastState = -1;

    function  onPlayerStateChange (event) {
        var video_id = event.target.getVideoData().video_id;

        if (event.data == YT.PlayerState.ENDED){
            if(! (lastState === YT.PlayerState.PAUSED ||   // workaround, YT in html5 mode will fire
                  lastState === YT.PlayerState.PLAYING)) { // event with ENDED state after cue video.
                event.data = lastState;
            } else {
                ga('send', 'event', 'videos', 'watch To end', video_id);
                if (whole === 'started') {
                    var stop = new Date().getTime();
                    var delta_s = (stop - start) / 1000;
                    ga('send', 'event', 'videos', 'time tO end', video_id, Math.round(delta_s));
                    whole = 'ended';
                }
            }
        }

        if (event.data == YT.PlayerState.PLAYING){
                ga('send', 'event', 'videos', 'play', video_id);
                _pauseFlag = false;
                if (whole !== 'ended' && whole !== 'started') {
                    start = new Date().getTime();
                    whole = 'started';
                }
        }

        if (event.data == YT.PlayerState.PAUSED && _pauseFlag === false){
            ga('send', 'event', 'videos', 'pause', video_id);
            _pauseFlag = true;
        }
        if (event.data == YT.PlayerState.BUFFERING){
            ga('send', 'event', 'videos', 'bufferIng', video_id);
        }
        if (event.data == YT.PlayerState.CUED){
            ga('send', 'event', 'videos', 'cueing', video_id);
        }

        lastState = event.data;
    }
    window.onPlayerStateChange = onPlayerStateChange;
})();
<|endoftext|>


<commit_before>$(function () {
    var metaKeyPressed = null;

    document.addEventListener("keydown", function (event) {
        if (event.metaKey || event.ctrlKey) {
            metaKeyPressed = event.keyCode;
        }
    });
    document.addEventListener("keyup", function (event) {
        if (event.keyCode === metaKeyPressed || event.metaKey || event.ctrlKey) {
            metaKeyPressed = null;
        }
    });

    /**
     * GLOBAL: Open transmitted url in main window or in new tab if meta key is pressed
     *
     * @param url   Url to visit
     */
    var openInNewTabOnMetaKey = function (url) {
        if (metaKeyPressed !== null || (window.event && (window.event.metaKey || window.event.ctrlKey))) {
            window.open(url, '_blank');
        } else {
            location.href = url;
        }
    };

    var tableEnableQueryParam = function (table, params) {
        var options = table.bootstrapTable('getOptions'),
            changes = false,
            newQueryParams = (options.queryParams && Object.keys(options.queryParams).length > 0) ? options.queryParams : {};

        if (!$.isArray(params) && $.isArray(options.queryParams)) {
            params = [params];
            $.each(params, function (index, param) {
                if (!newQueryParams[param]) {
                    newQueryParams[param] = 1;
                    changes = true;
                }
            });
        } else {
            if (options.queryParams !== params) {
                changes = true;
                newQueryParams = params;
            }
        }

        if (changes) {
            table.bootstrapTable('refreshOptions', {
                queryParams: newQueryParams
            });
        }
    };

    var handleFetchTable = function (table) {
            var tableToolbar = $('#bootstrap-table-toolbar'),
                id = table.attr('id'),
                useHead = table.data('use-head'),
                url = table.data('fetch-url');

            if (!url) {
                return; //this table does not support cached fetch
            }
            if (!useSecureCache()) {
                table.bootstrapTable('refreshOptions', {
                    url: url
                });
                return; //load the classic way
            }

            var appendIndicator = function (text, tooltip, glyph) {
                tableToolbar.find('.indicator-fetch').remove();
                tableToolbar.append('' +
                    ' ' + text + '...' +
                    '');
                tableToolbar.find('.indicator-fetch').tooltip();
            };

            var fetchDataAndCache = function (text, tooltip, showLoading, glyph) {
                if (!glyph) {
                    glyph = 'transfer';
                }
                if (showLoading) {
                    table.bootstrapTable('showLoading');
                }
                tableCache.remove(id, url);
                appendIndicator(text, tooltip, glyph);

                $.ajax({
                    type: "GET",
                    async: true,
                    url: url,
                    success: function (result, t, response) {
                        var etag = response.getResponseHeader('ETag');
                        if (etag) {
                            tableCache.set(id, url, {data: result, etag: etag});
                        }
                        table.bootstrapTable('load', result);
                        if (showLoading) {
                            table.bootstrapTable('hideLoading');
                        }
                        tableToolbar.find('.indicator-fetch').remove();
                    }
                });
            };

            if (tableCache.has(id, url)) {
                var tableCacheEntry = tableCache.get(id, url);
                table.bootstrapTable('load', tableCacheEntry.data);

                if (useHead) {
                    appendIndicator('Prüfe', 'Die Tabelle zeigt auf dem Computer zwischengespeicherte Daten. Es wird überprüft, ob auf dem Server aktuellere Daten vorhanden sind.', 'resize-horizontal');
                    $.ajax({
                        type: "HEAD",
                        async: true,
                        url: url,
                        success: function (c, t, response) {
                            tableToolbar.find('.indicator-fetch').remove();
                            if (tableCacheEntry.etag !== response.getResponseHeader('ETag')) {
                                tableCache.remove(id, url);
                                fetchDataAndCache('Lade', 'Die Tabelle zeigt veraltete Daten. Aktuellere Daten werden jetzt vom Server geladen...', false, 'warning-sign');
                            }
                        }
                    });
                } else {
                    fetchDataAndCache('Aktualisiere', 'Die Tabelle könnte veraltete Daten anzeigen. Die Daten werden mit denen vom Server abgeglichen und ggf. aktualisiert.', false, 'alert');
                }
            } else {
                fetchDataAndCache('Lade', 'Noch keine zwischengespeicherten Daten vorhanden. Aktuellere Daten werden jetzt vom Server geladen...', true);
            }
            table.on('refresh.bs.table', function (e) {
                fetchDataAndCache('Aktualisiere', 'Aktuellere Daten werden jetzt vom Server geladen...', false);
            });
        },
        tableSettingIdentifier = function (table, prefix, suffix) {
            var id = table.attr('id'),
                subId = table.data('sub-id');

            return prefix + '.' + id + '.' + (subId ? subId : '0') + '.' + suffix;
        },
        /**
         * GLOBAL: Bootstrap table on page which provides filters
         */
        handleTableFilters = function (table) {
            var tableFilterList = {},
                queryParams = [];

            $('#bootstrap-table-toolbar .dropup[data-property]').each(function () {
                var dropup = $(this),
                    options = dropup.find('ul li a'),
                    property = dropup.data('property'),
                    indexDefault = dropup.data('default'),
                    settingIdentifier = tableSettingIdentifier(table, 'tableFilter', property),
                    indexTarget = userSettings.get(settingIdentifier, indexDefault);

                if (!$.isNumeric(indexTarget) || options.length <= indexTarget) {
                    indexTarget = 0;
                }
                options.each(function (indexCurrent, option) {
                    if (indexCurrent === indexTarget) {
                        var optionEl = $(option),
                            text = optionEl.text(),
                            filter = optionEl.data('filter'),
                            requireParam = optionEl.data('require-query-param');

                        dropup.find('button .description').text(text);
                        tableFilterList[property] = filter;
                        if (requireParam) {
                            queryParams.push(requireParam);
                        }
                    }
                });
            });

            //apply filters
            if (queryParams.length) {
                tableEnableQueryParam(table, queryParams);
            }
            table.bootstrapTable('filterBy', tableFilterList);

            //add filter handler
            $('#bootstrap-table-toolbar li a').on('click', function (e) {
                e.preventDefault();
                var optionEl = $(this),
                    option = optionEl.get(0),
                    dropup = optionEl.parent().parent().parent(),
                    requireParam = optionEl.data('require-query-param'),
                    property = dropup.data('property'),
                    filter = optionEl.data('filter'),
                    text = optionEl.text(),
                    index;

                optionEl.parent().parent().find('li a').each(function (indexCurrent, optionCurrent) {
                    if (option === optionCurrent) {
                        index = indexCurrent;
                        return false;
                    }
                });
                if (index === undefined) {
                    return true;
                }

                //apply filters
                if (requireParam) {
                    tableEnableQueryParam(table, requireParam);
                }

                tableFilterList[property] = filter;
                dropup.find('button .description').text(text);
                table.bootstrapTable('filterBy', tableFilterList);
                userSettings.set(tableSettingIdentifier(table, 'tableFilter', property), index);
            });

        },
        /**
         * GLOBAL: Apply stored column setting for table
         */
        handleColumnSettings = function (table) {
            var tableSettingsIdentifier = tableSettingIdentifier(table, 'tableColumns', 'visible'),
                columns = table.bootstrapTable('getOptions').columns;

            if (!columns.length || columns.length !== 1) {
                return;
            }
            columns = columns[0];

            if (userSettings.has(tableSettingsIdentifier)) {
                var columnShow = userSettings.get(tableSettingsIdentifier, []);

                $.each(columns, function (index, column) {
                    if (!columnShow.includes(column.field)) {
                        table.bootstrapTable('hideColumn', column.field);
                    } else {
                        table.bootstrapTable('showColumn', column.field);
                    }
                });
            }

            table.on('column-switch.bs.table', function (e, dataIndex) {
                var columnConfiguration = table.bootstrapTable('getVisibleColumns'),
                    columns = [];

                $.each(columnConfiguration, function (index, column) {
                    columns.push(column.field);
                });

                userSettings.set(tableSettingsIdentifier, columns);
            });
        },

        handleRemoteTables = function () {
            $('.table-remote-content').each(function () {
                var table = $(this);
                handleTableFilters(table);
                handleFetchTable(table);
                handleColumnSettings(table);
            });
        }();

    /**
     * PARTICIPANT LIST: Unhide price/to pay column
     */
    var participantsTable = $('#participantsListTable');
    participantsTable.on('column-switch.bs.table', function (e, dataIndex) {
        if ((dataIndex !== 'payment_price' && dataIndex !== 'payment_to_pay')) {
            return;
        }
        tableEnableQueryParam(participantsTable, 'payment');
    });

    /**
     * EVENT: Admin event participants list table
     */
    participantsTable.on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('participation/' + row.pid);
    });

    /**
     * ACQUISITION: Admin acquisition list table
     */
    $('#acquisitionListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.bid);
    });

    /**
     * VARIABLES: Admin variable list table
     */
    $('#variableListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     * EVENT: Admin event list table
     */
    $('#eventListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.eid);
    });

    /**
     * USER: User list
     */
    $('#userListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.uid);
    });

    /**
     * USER: A users participants list table
     */
    $('#userParticipantsListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../event/' + row.eid + '/participation/' + row.pid);
    });

    /**
     * NEWSLETTER: subscriptions
     */
    $('#newsletterSubscriptionTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../subscription/' + row.rid);
    });

    /**
     * NEWSLETTER: newsletters
     */
    $('#newsletterNewsletterTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.lid + '/edit');
    });

    /**
     * NEWSLETTER: newsletters
     */
    $('#flashListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.fid);
    });

    /**
     * USER: A users participants list table
     */
    $('#eventAttendanceListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('attendance/' + row.tid);
    });

    /**
     * EMPLOYEE: A event's employee table
     */
    $('#employeeListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.gid);
    });

    /**
     * GROUP: List of an event's groups
     */
    $('#eventGroupsTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('groups/' + row.bid);
    });

    /**
     * GROUP: List of choices of an event's group
     */
    $('#eventGroupChoicesTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.bid + '/group/' + row.id);
    });

    /**
     * GROUP EMPLOYEE: List of employees assigned to a group option
     */
    $('#groupEmployeesTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../../../employee/' + row.gid);
    });

    /**
     * GROUP PARTICIPATION: List of participations assigned to a group option
     */
    $('#groupParticipationsTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../../../participation/' + row.pid);
    });

    /**
     * GROUP PARTICIPANT: List of participants assigned to a group option
     */
    $('#groupParticipantsTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../../../participation/' + row.pid);
    });

    /**
     *ATTENDANCE LIST COLUMN: Jump to column details
     */
    $('#attendanceColumnListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('columns/' + row.column_id);
    });

    /**
     *MEALS QUANTITY UNIT: Jump to quantity unit details
     */
    $('#quantityUnitList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     *MEALS RECIPES: Jump to recipe details
     */
    $('#recipesList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     *MEALS VIANDS: Jump to viand details
     */
    $('#viandList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     *MEALS FOOD PROPERTIES: Jump to property details
     */
    $('#foodPropertyList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     * MEALS FEEDBACK: Jump to feedback details
     */
    $('#recipeFeedbackList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('feedback/' + row.id);
    });

})
;
<commit_msg>Bootstrap table event 'column-switch.bs.table' seems not to be catched, therefore now listening on 'all.bs.table' and checking for respective event<commit_after>$(function () {
    var metaKeyPressed = null;

    document.addEventListener("keydown", function (event) {
        if (event.metaKey || event.ctrlKey) {
            metaKeyPressed = event.keyCode;
        }
    });
    document.addEventListener("keyup", function (event) {
        if (event.keyCode === metaKeyPressed || event.metaKey || event.ctrlKey) {
            metaKeyPressed = null;
        }
    });

    /**
     * GLOBAL: Open transmitted url in main window or in new tab if meta key is pressed
     *
     * @param url   Url to visit
     */
    var openInNewTabOnMetaKey = function (url) {
        if (metaKeyPressed !== null || (window.event && (window.event.metaKey || window.event.ctrlKey))) {
            window.open(url, '_blank');
        } else {
            location.href = url;
        }
    };

    var tableEnableQueryParam = function (table, params) {
        var options = table.bootstrapTable('getOptions'),
            changes = false,
            newQueryParams = (options.queryParams && Object.keys(options.queryParams).length > 0) ? options.queryParams : {};

        if (!$.isArray(params) && $.isArray(options.queryParams)) {
            params = [params];
            $.each(params, function (index, param) {
                if (!newQueryParams[param]) {
                    newQueryParams[param] = 1;
                    changes = true;
                }
            });
        } else {
            if (options.queryParams !== params) {
                changes = true;
                newQueryParams = params;
            }
        }

        if (changes) {
            table.bootstrapTable('refreshOptions', {
                queryParams: newQueryParams
            });
        }
    };

    var handleFetchTable = function (table) {
            var tableToolbar = $('#bootstrap-table-toolbar'),
                id = table.attr('id'),
                useHead = table.data('use-head'),
                url = table.data('fetch-url');

            if (!url) {
                return; //this table does not support cached fetch
            }
            if (!useSecureCache()) {
                table.bootstrapTable('refreshOptions', {
                    url: url
                });
                return; //load the classic way
            }

            var appendIndicator = function (text, tooltip, glyph) {
                tableToolbar.find('.indicator-fetch').remove();
                tableToolbar.append('' +
                    ' ' + text + '...' +
                    '');
                tableToolbar.find('.indicator-fetch').tooltip();
            };

            var fetchDataAndCache = function (text, tooltip, showLoading, glyph) {
                if (!glyph) {
                    glyph = 'transfer';
                }
                if (showLoading) {
                    table.bootstrapTable('showLoading');
                }
                tableCache.remove(id, url);
                appendIndicator(text, tooltip, glyph);

                $.ajax({
                    type: "GET",
                    async: true,
                    url: url,
                    success: function (result, t, response) {
                        var etag = response.getResponseHeader('ETag');
                        if (etag) {
                            tableCache.set(id, url, {data: result, etag: etag});
                        }
                        table.bootstrapTable('load', result);
                        if (showLoading) {
                            table.bootstrapTable('hideLoading');
                        }
                        tableToolbar.find('.indicator-fetch').remove();
                    }
                });
            };

            if (tableCache.has(id, url)) {
                var tableCacheEntry = tableCache.get(id, url);
                table.bootstrapTable('load', tableCacheEntry.data);

                if (useHead) {
                    appendIndicator('Prüfe', 'Die Tabelle zeigt auf dem Computer zwischengespeicherte Daten. Es wird überprüft, ob auf dem Server aktuellere Daten vorhanden sind.', 'resize-horizontal');
                    $.ajax({
                        type: "HEAD",
                        async: true,
                        url: url,
                        success: function (c, t, response) {
                            tableToolbar.find('.indicator-fetch').remove();
                            if (tableCacheEntry.etag !== response.getResponseHeader('ETag')) {
                                tableCache.remove(id, url);
                                fetchDataAndCache('Lade', 'Die Tabelle zeigt veraltete Daten. Aktuellere Daten werden jetzt vom Server geladen...', false, 'warning-sign');
                            }
                        }
                    });
                } else {
                    fetchDataAndCache('Aktualisiere', 'Die Tabelle könnte veraltete Daten anzeigen. Die Daten werden mit denen vom Server abgeglichen und ggf. aktualisiert.', false, 'alert');
                }
            } else {
                fetchDataAndCache('Lade', 'Noch keine zwischengespeicherten Daten vorhanden. Aktuellere Daten werden jetzt vom Server geladen...', true);
            }
            table.on('refresh.bs.table', function (e) {
                fetchDataAndCache('Aktualisiere', 'Aktuellere Daten werden jetzt vom Server geladen...', false);
            });
        },
        tableSettingIdentifier = function (table, prefix, suffix) {
            var id = table.attr('id'),
                subId = table.data('sub-id');

            return prefix + '.' + id + '.' + (subId ? subId : '0') + '.' + suffix;
        },
        /**
         * GLOBAL: Bootstrap table on page which provides filters
         */
        handleTableFilters = function (table) {
            var tableFilterList = {},
                queryParams = [];

            $('#bootstrap-table-toolbar .dropup[data-property]').each(function () {
                var dropup = $(this),
                    options = dropup.find('ul li a'),
                    property = dropup.data('property'),
                    indexDefault = dropup.data('default'),
                    settingIdentifier = tableSettingIdentifier(table, 'tableFilter', property),
                    indexTarget = userSettings.get(settingIdentifier, indexDefault);

                if (!$.isNumeric(indexTarget) || options.length <= indexTarget) {
                    indexTarget = 0;
                }
                options.each(function (indexCurrent, option) {
                    if (indexCurrent === indexTarget) {
                        var optionEl = $(option),
                            text = optionEl.text(),
                            filter = optionEl.data('filter'),
                            requireParam = optionEl.data('require-query-param');

                        dropup.find('button .description').text(text);
                        tableFilterList[property] = filter;
                        if (requireParam) {
                            queryParams.push(requireParam);
                        }
                    }
                });
            });

            //apply filters
            if (queryParams.length) {
                tableEnableQueryParam(table, queryParams);
            }
            table.bootstrapTable('filterBy', tableFilterList);

            //add filter handler
            $('#bootstrap-table-toolbar li a').on('click', function (e) {
                e.preventDefault();
                var optionEl = $(this),
                    option = optionEl.get(0),
                    dropup = optionEl.parent().parent().parent(),
                    requireParam = optionEl.data('require-query-param'),
                    property = dropup.data('property'),
                    filter = optionEl.data('filter'),
                    text = optionEl.text(),
                    index;

                optionEl.parent().parent().find('li a').each(function (indexCurrent, optionCurrent) {
                    if (option === optionCurrent) {
                        index = indexCurrent;
                        return false;
                    }
                });
                if (index === undefined) {
                    return true;
                }

                //apply filters
                if (requireParam) {
                    tableEnableQueryParam(table, requireParam);
                }

                tableFilterList[property] = filter;
                dropup.find('button .description').text(text);
                table.bootstrapTable('filterBy', tableFilterList);
                userSettings.set(tableSettingIdentifier(table, 'tableFilter', property), index);
            });

        },
        /**
         * GLOBAL: Apply stored column setting for table
         */
        handleColumnSettings = function (table) {
            var tableSettingsIdentifier = tableSettingIdentifier(table, 'tableColumns', 'visible'),
                columns = table.bootstrapTable('getOptions').columns;

            if (!columns.length || columns.length !== 1) {
                return;
            }
            columns = columns[0];

            if (userSettings.has(tableSettingsIdentifier)) {
                var columnShow = userSettings.get(tableSettingsIdentifier, []);

                $.each(columns, function (index, column) {
                    if (!columnShow.includes(column.field)) {
                        table.bootstrapTable('hideColumn', column.field);
                    } else {
                        table.bootstrapTable('showColumn', column.field);
                    }
                });
            }

            table.on('all.bs.table', function (e, eventName, args) {
                //direct listener on 'column-switch.bs.table' seem to be not working
                if (eventName === 'column-switch.bs.table') {
                    var columnConfiguration = table.bootstrapTable('getVisibleColumns'),
                        columns = [];

                    $.each(columnConfiguration, function (index, column) {
                        columns.push(column.field);
                    });

                    userSettings.set(tableSettingsIdentifier, columns);
                }
            });
        },

        handleRemoteTables = function () {
            $('.table-remote-content').each(function () {
                var table = $(this);
                handleTableFilters(table);
                handleFetchTable(table);
                handleColumnSettings(table);
            });
        };
    handleRemoteTables();

    /**
     * PARTICIPANT LIST: Unhide price/to pay column
     */
    var participantsTable = $('#participantsListTable');
    //direct listener on 'column-switch.bs.table' seem to be not working
    participantsTable.on('all.bs.table', function (e, eventName, args) {
        if (eventName === 'column-switch.bs.table') {
            var dataIndex = args[0];
            console.log(dataIndex);
            if ((dataIndex !== 'payment_price' && dataIndex !== 'payment_to_pay')) {
                return;
            }
            tableEnableQueryParam(participantsTable, 'payment');
        }
    });

    /**
     * EVENT: Admin event participants list table
     */
    participantsTable.on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('participation/' + row.pid);
    });

    /**
     * ACQUISITION: Admin acquisition list table
     */
    $('#acquisitionListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.bid);
    });

    /**
     * VARIABLES: Admin variable list table
     */
    $('#variableListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     * EVENT: Admin event list table
     */
    $('#eventListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.eid);
    });

    /**
     * USER: User list
     */
    $('#userListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.uid);
    });

    /**
     * USER: A users participants list table
     */
    $('#userParticipantsListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../event/' + row.eid + '/participation/' + row.pid);
    });

    /**
     * NEWSLETTER: subscriptions
     */
    $('#newsletterSubscriptionTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../subscription/' + row.rid);
    });

    /**
     * NEWSLETTER: newsletters
     */
    $('#newsletterNewsletterTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.lid + '/edit');
    });

    /**
     * NEWSLETTER: newsletters
     */
    $('#flashListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.fid);
    });

    /**
     * USER: A users participants list table
     */
    $('#eventAttendanceListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('attendance/' + row.tid);
    });

    /**
     * EMPLOYEE: A event's employee table
     */
    $('#employeeListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.gid);
    });

    /**
     * GROUP: List of an event's groups
     */
    $('#eventGroupsTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('groups/' + row.bid);
    });

    /**
     * GROUP: List of choices of an event's group
     */
    $('#eventGroupChoicesTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.bid + '/group/' + row.id);
    });

    /**
     * GROUP EMPLOYEE: List of employees assigned to a group option
     */
    $('#groupEmployeesTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../../../employee/' + row.gid);
    });

    /**
     * GROUP PARTICIPATION: List of participations assigned to a group option
     */
    $('#groupParticipationsTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../../../participation/' + row.pid);
    });

    /**
     * GROUP PARTICIPANT: List of participants assigned to a group option
     */
    $('#groupParticipantsTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('../../../participation/' + row.pid);
    });

    /**
     *ATTENDANCE LIST COLUMN: Jump to column details
     */
    $('#attendanceColumnListTable').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('columns/' + row.column_id);
    });

    /**
     *MEALS QUANTITY UNIT: Jump to quantity unit details
     */
    $('#quantityUnitList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     *MEALS RECIPES: Jump to recipe details
     */
    $('#recipesList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     *MEALS VIANDS: Jump to viand details
     */
    $('#viandList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     *MEALS FOOD PROPERTIES: Jump to property details
     */
    $('#foodPropertyList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey(row.id);
    });

    /**
     * MEALS FEEDBACK: Jump to feedback details
     */
    $('#recipeFeedbackList').on('click-row.bs.table', function (e, row, $element) {
        openInNewTabOnMetaKey('feedback/' + row.id);
    });

})
;
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import { UIDatabase } from '../../../database';
import { parsePositiveInteger, MODAL_KEYS } from '../../../utilities';
import { ACTIONS } from './constants';
import { openModal, closeModal } from './pageActions';

/**
 * Refreshes a row in the DataTable component.
 * Use case: editing a field of a realm object and ensuring the
 * UI is updated.
 *
 * @param {String} rowKey Key of the row to edit.
 */
export const refreshRow = rowKey => ({ type: ACTIONS.REFRESH_ROW, payload: { rowKey } });

/**
 * Edits a rows underlying `expiryDate` field.
 *
 * @param {Date}    newDate     The new date to set as the expiry.
 * @param {String}  rowKey      Key of the row to edit.
 * @param {String}  objectType  Type of object to edit i.e. 'TransactionBatch'
 */
export const editExpiryDate = (newDate, rowKey, objectType) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => {
    objectToEdit.expiryDate = newDate;
    UIDatabase.save(objectType, objectToEdit);
  });

  dispatch(refreshRow(rowKey));
};

/**
 * Wrapper around editExpiryDate.
 */
export const editTransactionBatchExpiryDate = (newDate, rowKey) =>
  editExpiryDate(newDate, rowKey, 'TransactionBatch');

/**
 * Edits the field `totalQuantity` of a rows underlying data object.
 *
 * @param {String|Number} value      The new value to set (parsed as a positive integer)
 * @param {String}        rowKey     The key of the row to edit.
 */
export const editTotalQuantity = (value, rowKey) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => {
    objectToEdit.setTotalQuantity(UIDatabase, parsePositiveInteger(value));
  });

  dispatch(refreshRow(rowKey));
};

/**
 * Edits a rows underlying `suggestedQuantity` field.
 *
 * @param {String|Number}   value       The new value to set as the required quantity.
 * @param {String}          rowKey      Key of the row to edit.
 * @param {String}          objectType  Type of object to edit i.e. 'RequisitionItem'
 */
export const editSuppliedQuantity = (value, rowKey) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => objectToEdit.setSuppliedQuantity(UIDatabase, parsePositiveInteger(value)));

  dispatch(refreshRow(rowKey));
};

/**
 * Edits a rows underlying `requiredQuantity` field.
 *
 * @param {String|Number}   value       The new value to set as the required quantity.
 * @param {String}          rowKey      Key of the row to edit.
 * @param {String}          objectType  Type of object to edit i.e. 'RequisitionItem'
 */
export const editRequiredQuantity = (value, rowKey, objectType) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => {
    objectToEdit.requiredQuantity = parsePositiveInteger(value);
    UIDatabase.save(objectType, objectToEdit);
  });

  dispatch(refreshRow(rowKey));
};

/**
 * Wrapper around editRequiredQuantity.
 */
export const editRequisitionItemRequiredQuantity = (value, rowKey) =>
  editRequiredQuantity(value, rowKey, 'RequisitionItem');

/**
 * Edits a rows underlying countedTotalQuantity field.
 *
 * @param {String|Number}   value   The new value to set as the ccounted total quantity.
 * @param {String}          rowKey  Key of the row to edit.
 */
export const editCountedQuantity = (value, rowKey) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  objectToEdit.setCountedTotalQuantity(UIDatabase, parsePositiveInteger(value));

  dispatch(refreshRow(rowKey));
};

/**
 * Removes a reason from a rows underlying data.
 *
 * @param {String} rowKey   Key for the row to edit.
 */
export const removeReason = rowKey => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  objectToEdit.applyReason(UIDatabase);

  dispatch(refreshRow(rowKey));
};

/**
 * Checks if a rows enforceReason field is true, if so, transforms
 * the action to open a fullScreen reasons modal, otherwise, remove
 * any reasons applied.
 *
 * @param {String} rowKey Key of the row to enforce a reason on
 */
export const enforceReasonChoice = rowKey => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  const { enforceReason } = objectToEdit;

  if (enforceReason) {
    dispatch(openModal(MODAL_KEYS.ENFORCE_STOCKTAKE_REASON, rowKey));
  } else {
    dispatch(removeReason(rowKey));
  }
};

/**
 * Applys a passed reason to the underlying row data. Can be a StocktakeItem
 * or StocktakeBatch.
 *
 * @param {Realm.Option} value Reason to apply to the underlying rorw.
 */
export const applyReason = value => (dispatch, getState) => {
  const { modalValue, keyExtractor } = getState();

  modalValue.applyReason(UIDatabase, value);

  const rowKey = keyExtractor(modalValue);

  dispatch(closeModal());
  dispatch(refreshRow(rowKey));
};

export const CellActionsLookup = {
  refreshRow,
  editExpiryDate,
  editTransactionBatchExpiryDate,
  editTotalQuantity,
  editSuppliedQuantity,
  editRequiredQuantity,
  editRequisitionItemRequiredQuantity,
  editCountedQuantity,
  removeReason,
  enforceReasonChoice,
  applyReason,
};

/**
 * =====================================================================
 *
 *                             Overrides
 *
 * Below are actions which are overrides of base actions.
 *
 * Example: editCountedQuantityWithReason overrides editCountedQuantity
 * for a stocktakeEditPage when reasons are defined.
 *
 * =====================================================================
 */

/**
 * Wrapper around `editCountedTotalQuantity`, splitting the action to enforce a
 * reason also.
 *
 * @param {String|Number}   value  New value for the underlying `countedTotalQuantity` field
 * @param {String}          rowKey Key of the row to edit.
 */
export const editCountedQuantityWithReason = (value, rowKey) => dispatch => {
  dispatch(editCountedQuantity(value, rowKey));
  dispatch(enforceReasonChoice(rowKey));
};
<commit_msg>Add editBatchName and editStocktakeBatchExpiryDate action creators<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import { UIDatabase } from '../../../database';
import { parsePositiveInteger, MODAL_KEYS } from '../../../utilities';
import { ACTIONS } from './constants';
import { openModal, closeModal } from './pageActions';

/**
 * Refreshes a row in the DataTable component.
 * Use case: editing a field of a realm object and ensuring the
 * UI is updated.
 *
 * @param {String} rowKey Key of the row to edit.
 */
export const refreshRow = rowKey => ({ type: ACTIONS.REFRESH_ROW, payload: { rowKey } });

/**
 * Edits a rows underlying `batch` field.
 *
 * @param {Date}    value       The new batch name value.
 * @param {String}  rowKey      Key of the row to edit.
 * @param {String}  objectType  Type of object to edit i.e. 'TransactionBatch'
 */
export const editBatchName = (value, rowKey, objectType) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  const { batch } = objectToEdit;

  if (value !== batch) {
    UIDatabase.write(() => UIDatabase.update(objectType, { ...objectToEdit, batch: value }));

    dispatch(refreshRow(rowKey));
  }
};

/**
 * Wrapper around editBatchName for StocktakeBatches
 */
export const editStocktakeBatchName = (value, rowKey) =>
  editBatchName(value, rowKey, 'StocktakeBatch');

/**
 * Edits a rows underlying `expiryDate` field.
 *
 * @param {Date}    newDate     The new date to set as the expiry.
 * @param {String}  rowKey      Key of the row to edit.
 * @param {String}  objectType  Type of object to edit i.e. 'TransactionBatch'
 */
export const editExpiryDate = (newDate, rowKey, objectType) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => {
    objectToEdit.expiryDate = newDate;
    UIDatabase.save(objectType, objectToEdit);
  });

  dispatch(refreshRow(rowKey));
};

/**
 * Wrapper around editExpiryDate.
 */
export const editTransactionBatchExpiryDate = (newDate, rowKey) =>
  editExpiryDate(newDate, rowKey, 'TransactionBatch');

export const editStocktakeBatchExpiryDate = (newDate, rowKey) =>
  editExpiryDate(newDate, rowKey, 'StocktakeBatch');

/**
 * Edits the field `totalQuantity` of a rows underlying data object.
 *
 * @param {String|Number} value      The new value to set (parsed as a positive integer)
 * @param {String}        rowKey     The key of the row to edit.
 */
export const editTotalQuantity = (value, rowKey) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => {
    objectToEdit.setTotalQuantity(UIDatabase, parsePositiveInteger(value));
  });

  dispatch(refreshRow(rowKey));
};

/**
 * Edits a rows underlying `suggestedQuantity` field.
 *
 * @param {String|Number}   value       The new value to set as the required quantity.
 * @param {String}          rowKey      Key of the row to edit.
 * @param {String}          objectType  Type of object to edit i.e. 'RequisitionItem'
 */
export const editSuppliedQuantity = (value, rowKey) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => objectToEdit.setSuppliedQuantity(UIDatabase, parsePositiveInteger(value)));

  dispatch(refreshRow(rowKey));
};

/**
 * Edits a rows underlying `requiredQuantity` field.
 *
 * @param {String|Number}   value       The new value to set as the required quantity.
 * @param {String}          rowKey      Key of the row to edit.
 * @param {String}          objectType  Type of object to edit i.e. 'RequisitionItem'
 */
export const editRequiredQuantity = (value, rowKey, objectType) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  UIDatabase.write(() => {
    objectToEdit.requiredQuantity = parsePositiveInteger(value);
    UIDatabase.save(objectType, objectToEdit);
  });

  dispatch(refreshRow(rowKey));
};

/**
 * Wrapper around editRequiredQuantity.
 */
export const editRequisitionItemRequiredQuantity = (value, rowKey) =>
  editRequiredQuantity(value, rowKey, 'RequisitionItem');

/**
 * Edits a rows underlying countedTotalQuantity field.
 *
 * @param {String|Number}   value   The new value to set as the ccounted total quantity.
 * @param {String}          rowKey  Key of the row to edit.
 */
export const editCountedQuantity = (value, rowKey) => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  objectToEdit.setCountedTotalQuantity(UIDatabase, parsePositiveInteger(value));

  dispatch(refreshRow(rowKey));
};

/**
 * Removes a reason from a rows underlying data.
 *
 * @param {String} rowKey   Key for the row to edit.
 */
export const removeReason = rowKey => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  objectToEdit.applyReason(UIDatabase);

  dispatch(refreshRow(rowKey));
};

/**
 * Checks if a rows enforceReason field is true, if so, transforms
 * the action to open a fullScreen reasons modal, otherwise, remove
 * any reasons applied.
 *
 * @param {String} rowKey Key of the row to enforce a reason on
 */
export const enforceReasonChoice = rowKey => (dispatch, getState) => {
  const { data, keyExtractor } = getState();

  const objectToEdit = data.find(row => keyExtractor(row) === rowKey);

  const { enforceReason } = objectToEdit;

  if (enforceReason) {
    dispatch(openModal(MODAL_KEYS.ENFORCE_STOCKTAKE_REASON, rowKey));
  } else {
    dispatch(removeReason(rowKey));
  }
};

/**
 * Applys a passed reason to the underlying row data. Can be a StocktakeItem
 * or StocktakeBatch.
 *
 * @param {Realm.Option} value Reason to apply to the underlying rorw.
 */
export const applyReason = value => (dispatch, getState) => {
  const { modalValue, keyExtractor } = getState();

  modalValue.applyReason(UIDatabase, value);

  const rowKey = keyExtractor(modalValue);

  dispatch(closeModal());
  dispatch(refreshRow(rowKey));
};

export const CellActionsLookup = {
  refreshRow,
  editExpiryDate,
  editTransactionBatchExpiryDate,
  editStocktakeBatchExpiryDate,
  editTotalQuantity,
  editSuppliedQuantity,
  editRequiredQuantity,
  editRequisitionItemRequiredQuantity,
  editCountedQuantity,
  removeReason,
  enforceReasonChoice,
  applyReason,
  editBatchName,
  editStocktakeBatchName,
};

/**
 * =====================================================================
 *
 *                             Overrides
 *
 * Below are actions which are overrides of base actions.
 *
 * Example: editCountedQuantityWithReason overrides editCountedQuantity
 * for a stocktakeEditPage when reasons are defined.
 *
 * =====================================================================
 */

/**
 * Wrapper around `editCountedTotalQuantity`, splitting the action to enforce a
 * reason also.
 *
 * @param {String|Number}   value  New value for the underlying `countedTotalQuantity` field
 * @param {String}          rowKey Key of the row to edit.
 */
export const editCountedQuantityWithReason = (value, rowKey) => dispatch => {
  dispatch(editCountedQuantity(value, rowKey));
  dispatch(enforceReasonChoice(rowKey));
};
<|endoftext|>


<commit_before>/*global Modernizr:true*/
(function() {
  var csrf_token;

  window.Discourse = Ember.Application.createWithMixins({
    rootElement: '#main',

    // Data we want to remember for a short period
    transient: Em.Object.create(),

    hasFocus: true,
    scrolling: false,

    // The highest seen post number by topic
    highestSeenByTopic: {},

    logoSmall: (function() {
      var logo;
      logo = Discourse.SiteSettings.logo_small_url;
      if (logo && logo.length > 1) {
        return "";
      } else {
        return "";
      }
    }).property(),

    titleChanged: (function() {
      var title;
      title = "";
      if (this.get('title')) {
        title += "" + (this.get('title')) + " - ";
      }
      title += Discourse.SiteSettings.title;
      jQuery('title').text(title);
      if (!this.get('hasFocus') && this.get('notify')) {
        title = "(*) " + title;
      }
      // chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome
      window.setTimeout((function() {
        document.title = ".";
        document.title = title;
      }), 200);
    }).observes('title', 'hasFocus', 'notify'),

    currentUserChanged: (function() {
      var bus, user;
      bus = Discourse.MessageBus;

      // We don't want to receive any previous user notifications
      bus.unsubscribe("/notification/*");
      bus.callbackInterval = Discourse.SiteSettings.anon_polling_interval;
      bus.enableLongPolling = false;
      user = this.get('currentUser');
      if (user) {
        bus.callbackInterval = Discourse.SiteSettings.polling_interval;
        bus.enableLongPolling = true;
        if (user.admin) {
          bus.subscribe("/flagged_counts", function(data) {
            return user.set('site_flagged_posts_count', data.total);
          });
        }
        return bus.subscribe("/notification/" + user.id, (function(data) {
          user.set('unread_notifications', data.unread_notifications);
          return user.set('unread_private_messages', data.unread_private_messages);
        }), user.notification_channel_position);
      }
    }).observes('currentUser'),
    notifyTitle: function() {
      return this.set('notify', true);
    },

    // Browser aware replaceState
    replaceState: function(path) {
      if (window.history &&
          window.history.pushState &&
          window.history.replaceState &&
          !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)) {
        if (window.location.pathname !== path) {
          return history.replaceState({
            path: path
          }, null, path);
        }
      }
    },

    openComposer: function(opts) {
      // TODO, remove container link
      var composer = Discourse.__container__.lookup('controller:composer');
      if (composer) composer.open(opts);
    },

    // Like router.route, but allow full urls rather than relative one
    // HERE BE HACKS - uses the ember container for now until we can do this nicer.
    routeTo: function(path) {
      var newMatches, newTopicId, oldMatches, oldTopicId, opts, router, topicController, topicRegexp;
      path = path.replace(/https?\:\/\/[^\/]+/, '');

      // If we're in the same topic, don't push the state
      topicRegexp = /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/;
      newMatches = topicRegexp.exec(path);
      newTopicId = newMatches ? newMatches[2] : null;
      if (newTopicId) {
        oldMatches = topicRegexp.exec(window.location.pathname);
        if ((oldTopicId = oldMatches ? oldMatches[2] : void 0) && (oldTopicId === newTopicId)) {
          Discourse.replaceState(path);
          topicController = Discourse.__container__.lookup('controller:topic');
          opts = {
            trackVisit: false
          };
          if (newMatches[3]) {
            opts.nearPost = newMatches[3];
          }
          topicController.get('content').loadPosts(opts);
          return;
        }
      }
      // Be wary of looking up the router. In this case, we have links in our
      // HTML, say form compiled markdown posts, that need to be routed.
      router = Discourse.__container__.lookup('router:main');
      router.router.updateURL(path);
      return router.handleURL(path);
    },

    // The classes of buttons to show on a post
    postButtons: (function() {
      return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
        return "" + (i.replace(/\+/, '').capitalize());
      });
    }).property('Discourse.SiteSettings.post_menu'),

    bindDOMEvents: function() {
      var $html, hasTouch,
        _this = this;
      $html = jQuery('html');

      /* Add the discourse touch event */
      hasTouch = false;
      if ($html.hasClass('touch')) {
        hasTouch = true;
      }
      if (Modernizr.prefixed("MaxTouchPoints", navigator) > 1) {
        hasTouch = true;
      }
      if (hasTouch) {
        $html.addClass('discourse-touch');
        this.touch = true;
        this.hasTouch = true;

        $LAB.script(assetPath('defer/fastclick'))
            .wait(function(){
                new FastClick(document.body);
            });

      } else {
        $html.addClass('discourse-no-touch');
        this.touch = false;
      }
      jQuery('#main').on('click.discourse', '[data-not-implemented=true]', function(e) {
        e.preventDefault();
        alert(Em.String.i18n('not_implemented'));
        return false;
      });
      jQuery('#main').on('click.discourse', 'a', function(e) {
        var $currentTarget, href;
        if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) {
          return;
        }
        $currentTarget = jQuery(e.currentTarget);
        href = $currentTarget.attr('href');
        if (href === void 0) {
          return;
        }
        if (href === '#') {
          return;
        }
        if ($currentTarget.attr('target')) {
          return;
        }
        if ($currentTarget.data('auto-route')) {
          return;
        }
        if ($currentTarget.hasClass('lightbox')) {
          return;
        }
        if (href.indexOf("mailto:") === 0) {
          return;
        }
        if (href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i"))) {
          return;
        }
        e.preventDefault();
        _this.routeTo(href);
        return false;
      });
      return jQuery(window).focus(function() {
        _this.set('hasFocus', true);
        return _this.set('notify', false);
      }).blur(function() {
        return _this.set('hasFocus', false);
      });
    },
    logout: function() {
      var username,
        _this = this;
      username = this.get('currentUser.username');
      Discourse.KeyValueStore.abandonLocal();
      return jQuery.ajax("/session/" + username, {
        type: 'DELETE',
        success: function(result) {
          /* To keep lots of our variables unbound, we can handle a redirect on logging out.
          */
          return window.location.reload();
        }
      });
    },
    /* fancy probes in ember
    */

    insertProbes: function() {
      var topLevel;
      if (typeof console === "undefined" || console === null) {
        return;
      }
      topLevel = function(fn, name) {
        return window.probes.measure(fn, {
          name: name,
          before: function(data, owner, args) {
            if (owner) {
              return window.probes.clear();
            }
          },
          after: function(data, owner, args) {
            var ary, f, n, v, _ref;
            if (owner && data.time > 10) {
              f = function(name, data) {
                if (data && data.count) {
                  return "" + name + " - " + data.count + " calls " + ((data.time + 0.0).toFixed(2)) + "ms";
                }
              };
              if (console && console.group) {
                console.group(f(name, data));
              } else {
                console.log("");
                console.log(f(name, data));
              }
              ary = [];
              _ref = window.probes;
              for (n in _ref) {
                v = _ref[n];
                if (n === name || v.time < 1) {
                  continue;
                }
                ary.push({
                  k: n,
                  v: v
                });
              }
              ary.sortBy(function(item) {
                if (item.v && item.v.time) {
                  return -item.v.time;
                } else {
                  return 0;
                }
              }).each(function(item) {
                var output = f("" + item.k, item.v);
                if (output) {
                  return console.log(output);
                }
              });
              if (typeof console !== "undefined" && console !== null) {
                if (typeof console.groupEnd === "function") {
                  console.groupEnd();
                }
              }
              return window.probes.clear();
            }
          }
        });
      };
      Ember.View.prototype.renderToBuffer = window.probes.measure(Ember.View.prototype.renderToBuffer, "renderToBuffer");
      Discourse.routeTo = topLevel(Discourse.routeTo, "Discourse.routeTo");
      Ember.run.end = topLevel(Ember.run.end, "Ember.run.end");
    },
    authenticationComplete: function(options) {
      // TODO, how to dispatch this to the view without the container?
      var loginView;
      loginView = Discourse.__container__.lookup('controller:modal').get('currentView');
      return loginView.authenticationComplete(options);
    },
    buildRoutes: function(builder) {
      var oldBuilder;
      oldBuilder = Discourse.routeBuilder;
      Discourse.routeBuilder = function() {
        if (oldBuilder) {
          oldBuilder.call(this);
        }
        return builder.call(this);
      };
    },
    start: function() {
      this.bindDOMEvents();
      Discourse.SiteSettings = PreloadStore.getStatic('siteSettings');
      Discourse.MessageBus.start();
      Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
      Discourse.insertProbes();

      // subscribe to any site customizations that are loaded
      jQuery('link.custom-css').each(function() {
        var id, split, stylesheet,
          _this = this;
        split = this.href.split("/");
        id = split[split.length - 1].split(".css")[0];
        stylesheet = this;
        return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
          var orig, sp;
          if (!jQuery(stylesheet).data('orig')) {
            jQuery(stylesheet).data('orig', stylesheet.href);
          }
          orig = jQuery(stylesheet).data('orig');
          sp = orig.split(".css?");
          stylesheet.href = sp[0] + ".css?" + data;
        });
      });
      jQuery('header.custom').each(function() {
        var header;
        header = jQuery(this);
        return Discourse.MessageBus.subscribe("/header-change/" + (jQuery(this).data('key')), function(data) {
          return header.html(data);
        });
      });

      // possibly move this to dev only
      return Discourse.MessageBus.subscribe("/file-change", function(data) {
        Ember.TEMPLATES.empty = Handlebars.compile("

");
        return data.each(function(me) {
          var js;
          if (me === "refresh") {
            return document.location.reload(true);
          } else if (me.name.substr(-10) === "handlebars") {
            js = me.name.replace(".handlebars", "").replace("app/assets/javascripts", "/assets");
            return $LAB.script(js + "?hash=" + me.hash).wait(function() {
              var templateName;
              templateName = js.replace(".js", "").replace("/assets/", "");
              return jQuery.each(Ember.View.views, function() {
                var _this = this;
                if (this.get('templateName') === templateName) {
                  this.set('templateName', 'empty');
                  this.rerender();
                  return Em.run.next(function() {
                    _this.set('templateName', templateName);
                    return _this.rerender();
                  });
                }
              });
            });
          } else {
            return jQuery('link').each(function() {
              if (this.href.match(me.name) && me.hash) {
                if (!jQuery(this).data('orig')) {
                  jQuery(this).data('orig', this.href);
                }
                this.href = jQuery(this).data('orig') + "&hash=" + me.hash;
              }
            });
          }
        });
      });
    }
  });

  window.Discourse.Router = Discourse.Router.reopen({
    location: 'discourse_location'
  });

  // since we have no jquery-rails these days, hook up csrf token
  csrf_token = jQuery('meta[name=csrf-token]').attr('content');

  jQuery.ajaxPrefilter(function(options, originalOptions, xhr) {
    if (!options.crossDomain) {
      xhr.setRequestHeader('X-CSRF-Token', csrf_token);
    }
  });

}).call(this);
<commit_msg>fix hinting<commit_after>/*global Modernizr:true*/
/*global assetPath:true*/
/*global FastClick:true*/

(function() {
  var csrf_token;

  window.Discourse = Ember.Application.createWithMixins({
    rootElement: '#main',

    // Data we want to remember for a short period
    transient: Em.Object.create(),

    hasFocus: true,
    scrolling: false,

    // The highest seen post number by topic
    highestSeenByTopic: {},

    logoSmall: (function() {
      var logo;
      logo = Discourse.SiteSettings.logo_small_url;
      if (logo && logo.length > 1) {
        return "";
      } else {
        return "";
      }
    }).property(),

    titleChanged: (function() {
      var title;
      title = "";
      if (this.get('title')) {
        title += "" + (this.get('title')) + " - ";
      }
      title += Discourse.SiteSettings.title;
      jQuery('title').text(title);
      if (!this.get('hasFocus') && this.get('notify')) {
        title = "(*) " + title;
      }
      // chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome
      window.setTimeout((function() {
        document.title = ".";
        document.title = title;
      }), 200);
    }).observes('title', 'hasFocus', 'notify'),

    currentUserChanged: (function() {
      var bus, user;
      bus = Discourse.MessageBus;

      // We don't want to receive any previous user notifications
      bus.unsubscribe("/notification/*");
      bus.callbackInterval = Discourse.SiteSettings.anon_polling_interval;
      bus.enableLongPolling = false;
      user = this.get('currentUser');
      if (user) {
        bus.callbackInterval = Discourse.SiteSettings.polling_interval;
        bus.enableLongPolling = true;
        if (user.admin) {
          bus.subscribe("/flagged_counts", function(data) {
            return user.set('site_flagged_posts_count', data.total);
          });
        }
        return bus.subscribe("/notification/" + user.id, (function(data) {
          user.set('unread_notifications', data.unread_notifications);
          return user.set('unread_private_messages', data.unread_private_messages);
        }), user.notification_channel_position);
      }
    }).observes('currentUser'),
    notifyTitle: function() {
      return this.set('notify', true);
    },

    // Browser aware replaceState
    replaceState: function(path) {
      if (window.history &&
          window.history.pushState &&
          window.history.replaceState &&
          !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)) {
        if (window.location.pathname !== path) {
          return history.replaceState({
            path: path
          }, null, path);
        }
      }
    },

    openComposer: function(opts) {
      // TODO, remove container link
      var composer = Discourse.__container__.lookup('controller:composer');
      if (composer) composer.open(opts);
    },

    // Like router.route, but allow full urls rather than relative one
    // HERE BE HACKS - uses the ember container for now until we can do this nicer.
    routeTo: function(path) {
      var newMatches, newTopicId, oldMatches, oldTopicId, opts, router, topicController, topicRegexp;
      path = path.replace(/https?\:\/\/[^\/]+/, '');

      // If we're in the same topic, don't push the state
      topicRegexp = /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/;
      newMatches = topicRegexp.exec(path);
      newTopicId = newMatches ? newMatches[2] : null;
      if (newTopicId) {
        oldMatches = topicRegexp.exec(window.location.pathname);
        if ((oldTopicId = oldMatches ? oldMatches[2] : void 0) && (oldTopicId === newTopicId)) {
          Discourse.replaceState(path);
          topicController = Discourse.__container__.lookup('controller:topic');
          opts = {
            trackVisit: false
          };
          if (newMatches[3]) {
            opts.nearPost = newMatches[3];
          }
          topicController.get('content').loadPosts(opts);
          return;
        }
      }
      // Be wary of looking up the router. In this case, we have links in our
      // HTML, say form compiled markdown posts, that need to be routed.
      router = Discourse.__container__.lookup('router:main');
      router.router.updateURL(path);
      return router.handleURL(path);
    },

    // The classes of buttons to show on a post
    postButtons: (function() {
      return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
        return "" + (i.replace(/\+/, '').capitalize());
      });
    }).property('Discourse.SiteSettings.post_menu'),

    bindDOMEvents: function() {
      var $html, hasTouch,
        _this = this;
      $html = jQuery('html');

      /* Add the discourse touch event */
      hasTouch = false;
      if ($html.hasClass('touch')) {
        hasTouch = true;
      }
      if (Modernizr.prefixed("MaxTouchPoints", navigator) > 1) {
        hasTouch = true;
      }
      if (hasTouch) {
        $html.addClass('discourse-touch');
        this.touch = true;
        this.hasTouch = true;

        $LAB.script(assetPath('defer/fastclick'))
            .wait(function(){
                // work around jshint hating side-effects
                //   its just the way the FastClick api is
                var ignore = new FastClick(document.body);
            });

      } else {
        $html.addClass('discourse-no-touch');
        this.touch = false;
      }
      jQuery('#main').on('click.discourse', '[data-not-implemented=true]', function(e) {
        e.preventDefault();
        alert(Em.String.i18n('not_implemented'));
        return false;
      });
      jQuery('#main').on('click.discourse', 'a', function(e) {
        var $currentTarget, href;
        if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) {
          return;
        }
        $currentTarget = jQuery(e.currentTarget);
        href = $currentTarget.attr('href');
        if (href === void 0) {
          return;
        }
        if (href === '#') {
          return;
        }
        if ($currentTarget.attr('target')) {
          return;
        }
        if ($currentTarget.data('auto-route')) {
          return;
        }
        if ($currentTarget.hasClass('lightbox')) {
          return;
        }
        if (href.indexOf("mailto:") === 0) {
          return;
        }
        if (href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i"))) {
          return;
        }
        e.preventDefault();
        _this.routeTo(href);
        return false;
      });
      return jQuery(window).focus(function() {
        _this.set('hasFocus', true);
        return _this.set('notify', false);
      }).blur(function() {
        return _this.set('hasFocus', false);
      });
    },
    logout: function() {
      var username,
        _this = this;
      username = this.get('currentUser.username');
      Discourse.KeyValueStore.abandonLocal();
      return jQuery.ajax("/session/" + username, {
        type: 'DELETE',
        success: function(result) {
          /* To keep lots of our variables unbound, we can handle a redirect on logging out.
          */
          return window.location.reload();
        }
      });
    },
    /* fancy probes in ember
    */

    insertProbes: function() {
      var topLevel;
      if (typeof console === "undefined" || console === null) {
        return;
      }
      topLevel = function(fn, name) {
        return window.probes.measure(fn, {
          name: name,
          before: function(data, owner, args) {
            if (owner) {
              return window.probes.clear();
            }
          },
          after: function(data, owner, args) {
            var ary, f, n, v, _ref;
            if (owner && data.time > 10) {
              f = function(name, data) {
                if (data && data.count) {
                  return "" + name + " - " + data.count + " calls " + ((data.time + 0.0).toFixed(2)) + "ms";
                }
              };
              if (console && console.group) {
                console.group(f(name, data));
              } else {
                console.log("");
                console.log(f(name, data));
              }
              ary = [];
              _ref = window.probes;
              for (n in _ref) {
                v = _ref[n];
                if (n === name || v.time < 1) {
                  continue;
                }
                ary.push({
                  k: n,
                  v: v
                });
              }
              ary.sortBy(function(item) {
                if (item.v && item.v.time) {
                  return -item.v.time;
                } else {
                  return 0;
                }
              }).each(function(item) {
                var output = f("" + item.k, item.v);
                if (output) {
                  return console.log(output);
                }
              });
              if (typeof console !== "undefined" && console !== null) {
                if (typeof console.groupEnd === "function") {
                  console.groupEnd();
                }
              }
              return window.probes.clear();
            }
          }
        });
      };
      Ember.View.prototype.renderToBuffer = window.probes.measure(Ember.View.prototype.renderToBuffer, "renderToBuffer");
      Discourse.routeTo = topLevel(Discourse.routeTo, "Discourse.routeTo");
      Ember.run.end = topLevel(Ember.run.end, "Ember.run.end");
    },
    authenticationComplete: function(options) {
      // TODO, how to dispatch this to the view without the container?
      var loginView;
      loginView = Discourse.__container__.lookup('controller:modal').get('currentView');
      return loginView.authenticationComplete(options);
    },
    buildRoutes: function(builder) {
      var oldBuilder;
      oldBuilder = Discourse.routeBuilder;
      Discourse.routeBuilder = function() {
        if (oldBuilder) {
          oldBuilder.call(this);
        }
        return builder.call(this);
      };
    },
    start: function() {
      this.bindDOMEvents();
      Discourse.SiteSettings = PreloadStore.getStatic('siteSettings');
      Discourse.MessageBus.start();
      Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
      Discourse.insertProbes();

      // subscribe to any site customizations that are loaded
      jQuery('link.custom-css').each(function() {
        var id, split, stylesheet,
          _this = this;
        split = this.href.split("/");
        id = split[split.length - 1].split(".css")[0];
        stylesheet = this;
        return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
          var orig, sp;
          if (!jQuery(stylesheet).data('orig')) {
            jQuery(stylesheet).data('orig', stylesheet.href);
          }
          orig = jQuery(stylesheet).data('orig');
          sp = orig.split(".css?");
          stylesheet.href = sp[0] + ".css?" + data;
        });
      });
      jQuery('header.custom').each(function() {
        var header;
        header = jQuery(this);
        return Discourse.MessageBus.subscribe("/header-change/" + (jQuery(this).data('key')), function(data) {
          return header.html(data);
        });
      });

      // possibly move this to dev only
      return Discourse.MessageBus.subscribe("/file-change", function(data) {
        Ember.TEMPLATES.empty = Handlebars.compile("

");
        return data.each(function(me) {
          var js;
          if (me === "refresh") {
            return document.location.reload(true);
          } else if (me.name.substr(-10) === "handlebars") {
            js = me.name.replace(".handlebars", "").replace("app/assets/javascripts", "/assets");
            return $LAB.script(js + "?hash=" + me.hash).wait(function() {
              var templateName;
              templateName = js.replace(".js", "").replace("/assets/", "");
              return jQuery.each(Ember.View.views, function() {
                var _this = this;
                if (this.get('templateName') === templateName) {
                  this.set('templateName', 'empty');
                  this.rerender();
                  return Em.run.next(function() {
                    _this.set('templateName', templateName);
                    return _this.rerender();
                  });
                }
              });
            });
          } else {
            return jQuery('link').each(function() {
              if (this.href.match(me.name) && me.hash) {
                if (!jQuery(this).data('orig')) {
                  jQuery(this).data('orig', this.href);
                }
                this.href = jQuery(this).data('orig') + "&hash=" + me.hash;
              }
            });
          }
        });
      });
    }
  });

  window.Discourse.Router = Discourse.Router.reopen({
    location: 'discourse_location'
  });

  // since we have no jquery-rails these days, hook up csrf token
  csrf_token = jQuery('meta[name=csrf-token]').attr('content');

  jQuery.ajaxPrefilter(function(options, originalOptions, xhr) {
    if (!options.crossDomain) {
      xhr.setRequestHeader('X-CSRF-Token', csrf_token);
    }
  });

}).call(this);
<|endoftext|>


<commit_before>$(document).ready(function() {
    // Because some browsers don't support submit buttons outside of forms triggering form submits,
    // do it in javascript just to make sure it happens
    $('input[type=submit][form]').click(function(){
        if (form = document.getElementById(this.getAttribute('form'))){
            var tempCommit = $("<input type='submit' name='commit' style='display:none'>");
            tempCommit.attr('value', $(this).attr('value'));
            form.appendChild(tempCommit[0]);
            tempCommit.click();
            return false;
        }
    });
});<commit_msg>fix submit of form when cancel is pressed.<commit_after>$(document).ready(function() {
    // Because some browsers don't support submit buttons outside of forms triggering form submits,
    // do it in javascript just to make sure it happens
    $('input[type=submit][form]').live('click', function(){
        if (form = document.getElementById(this.getAttribute('form'))) {
            // If the form is already submitting, we want don't want to submit it again.
            if ($(form).hasClass('submitting')) {
              return false;
            }

            var tempCommit = $("<input type='submit' name='commit' style='display:none'>");
            tempCommit.attr('value', $(this).attr('value'));
            form.appendChild(tempCommit[0]);
            tempCommit.click();
            return false;
        }
    });
    // Used by the above click handler to determine if the browser already submitted the form.
    $('form').submit(function() {
      $(this).addClass('submitting');
    });
});<|endoftext|>


<commit_before>var Map = {
  dataInput: [],
  defaultView: function(topic, mapData, width) {
    var self = this,
        width = width;
    $('#map-container').highcharts('Map', {
      chart: {
        width: width,
        height: 800,
        backgroundColor: '#FFFFFF'
      },
      title: {
        text: topic,
        style: {
          color: '#0099CC',
          font: '44px "HelveticaNeue", Arial, sans-serif'
        }
      },
      mapNavigation: {
        enabled: true,
        buttonOptions: {
          align: 'right',
          verticalAlign: 'bottom'
        },
        enableMouseWheelZoom: false
      },
      colorAxis: {
        type: 'linear',
        endOnTick: false,
        startOnTick: false,
        min: -1,
        max: 1,
        stops: [
          [0, '#CC0033'],
          [0.5, '#FFFFFF'],
          [1, '#00CC33']
        ],
      },
      colors: ['#B4DA55'],
      tooltip: {
        animation: true,
        pointFormat: '{point.name}: {point.value}',
        shadow: false
      },
      legend: {
        align: 'center',
        itemWidth: 200,
        reversed: false,
      },
      plotOptions: {
        series: {
          joinBy: ['iso-a2', 'code'],
        },
        states: {
          hover: {
            enabled: true
          },
          select: {
            borderColor: 'black',
            dashStyle: 'shortdot',
            color: '#B4DA55'
          }
        }
      },
      series: [{
        data: self.dataInput,
        mapData: mapData,
        name: 'Sentiment Index',
      }]
    })
  }
};

var createMapView = {
  init: function(trend, tweetData) {
    var map = Highcharts.maps['custom/world'];
    var mapData = Highcharts.geojson(map);
    this.inputData(tweetData);
    this.layoutMap(trend, mapData);
  },
  inputData: function(data) {
    Map.dataInput = [];
    for (var i in data) {
      Map.dataInput.push(data[i]);
    }
  },
  layoutMap: function(topic, mapData) {
    var deviceWidth = this.setMapWidth();
    Map.defaultView(topic, mapData, deviceWidth);
  },
  setMapWidth: function() {
    $width = $(document).width();
    console.log($width);
    if ($width > 1280) {
      return 1200;
    } else if ($width > 1025) {
      return 850;
    } else if ($width > 960) {
      return 800;
    } else if ($width > 640) {
      return 640;
    } else if ($width > 480) {
      return 480;
    } else {
      return 300;
    };
  }
};

<commit_msg>remove console log from testing<commit_after>var Map = {
  dataInput: [],
  defaultView: function(topic, mapData, width) {
    var self = this,
        width = width;
    $('#map-container').highcharts('Map', {
      chart: {
        width: width,
        height: 800,
        backgroundColor: '#FFFFFF'
      },
      title: {
        text: topic,
        style: {
          color: '#0099CC',
          font: '44px "HelveticaNeue", Arial, sans-serif'
        }
      },
      mapNavigation: {
        enabled: true,
        buttonOptions: {
          align: 'right',
          verticalAlign: 'bottom'
        },
        enableMouseWheelZoom: false
      },
      colorAxis: {
        type: 'linear',
        endOnTick: false,
        startOnTick: false,
        min: -1,
        max: 1,
        stops: [
          [0, '#CC0033'],
          [0.5, '#FFFFFF'],
          [1, '#00CC33']
        ],
      },
      colors: ['#B4DA55'],
      tooltip: {
        animation: true,
        pointFormat: '{point.name}: {point.value}',
        shadow: false
      },
      legend: {
        align: 'center',
        itemWidth: 200,
        reversed: false,
      },
      plotOptions: {
        series: {
          joinBy: ['iso-a2', 'code'],
        },
        states: {
          hover: {
            enabled: true
          },
          select: {
            borderColor: 'black',
            dashStyle: 'shortdot',
            color: '#B4DA55'
          }
        }
      },
      series: [{
        data: self.dataInput,
        mapData: mapData,
        name: 'Sentiment Index',
      }]
    })
  }
};

var createMapView = {
  init: function(trend, tweetData) {
    var map = Highcharts.maps['custom/world'];
    var mapData = Highcharts.geojson(map);
    this.inputData(tweetData);
    this.layoutMap(trend, mapData);
  },
  inputData: function(data) {
    Map.dataInput = [];
    for (var i in data) {
      Map.dataInput.push(data[i]);
    }
  },
  layoutMap: function(topic, mapData) {
    var deviceWidth = this.setMapWidth();
    Map.defaultView(topic, mapData, deviceWidth);
  },
  setMapWidth: function() {
    $width = $(document).width();
    if ($width > 1280) {
      return 1200;
    } else if ($width > 1025) {
      return 850;
    } else if ($width > 960) {
      return 800;
    } else if ($width > 640) {
      return 640;
    } else if ($width > 480) {
      return 480;
    } else {
      return 300;
    };
  }
};

<|endoftext|>