<commit_before>/* global d3, _ */
var url = hqImport('hqwebapp/js/initial_page_data').reverse;

function UnderweightChildrenReportController($scope, $routeParams, $location, $filter, maternalChildService,
    locationsService, dateHelperService, navigationService, userLocationId, storageService, genders, ages, haveAccessToAllLocations,
    baseControllersService, isAlertActive, isMobile) {
    baseControllersService.BaseController.call(this, $scope, $routeParams, $location, locationsService,
        dateHelperService, navigationService, userLocationId, storageService, haveAccessToAllLocations, isMobile);
    var vm = this;
    vm.sectionSlug = 'maternal_child';  // maps to the section of program summary this page lives on
    vm.isAlertActive = isAlertActive;

    var ageIndex = _.findIndex(ages, function (x) {
        return x.id === vm.filtersData.age;
    });
    if (ageIndex !== -1) {
        vm.ageLabel = ages[ageIndex].name;
    }

    var genderIndex = _.findIndex(genders, function (x) {
        return x.id === vm.filtersData.gender;
    });
    if (genderIndex !== -1) {
        vm.genderLabel = genders[genderIndex].name;
    }

    vm.label = "Prevalence of Underweight (Weight-for-Age)";
    vm.steps = {
        'map': {route: '/maternal_and_child/underweight_children/map', label: 'Map View'},
        'chart': {route: '/maternal_and_child/underweight_children/chart', label: 'Chart View'},
    };
    vm.data = {
        legendTitle: 'Percentage Children',
    };
    vm.filters = [];
    vm.rightLegend = {
        info: 'Of the total children enrolled for Anganwadi services and weighed, the percentage of children between 0-5 years who were moderately/severely underweight in the current month. \n' +
        '\n' +
        'Children who are moderately or severely underweight have a higher risk of mortality. ',
    };

    vm.chosenFilters = function() {
        var gender = genderIndex > 0 ? genders[genderIndex].name : '';
        var age = ageIndex > 0 ? ages[ageIndex].name : '0 - 5 years';
        var delimiter = gender && age ? ', ' : '';
        return gender || age ? '(' + gender + delimiter + age + ')' : '';
    };

    vm.templatePopup = function(loc, row) {
        var total = row ? $filter('indiaNumbers')(row.weighed) : 'N/A';
        var unweighed = row ? $filter('indiaNumbers')(row.total - row.weighed) : "N/A";
        var severelyUnderweight = row ? d3.format(".2%")(row.severely_underweight / (row.weighed || 1)) : 'N/A';
        var moderatelyUnderweight = row ? d3.format(".2%")(row.moderately_underweight / (row.weighed || 1)) : 'N/A';
        var normal = row ? d3.format(".2%")(row.normal / (row.weighed || 1)) : 'N/A';
        return vm.createTemplatePopup(
            loc.properties.name,
            [{
                indicator_name: 'Total Children ' + vm.chosenFilters() + ' weighed in given month: ',
                indicator_value: total,
            },
            {
                indicator_name: 'Number of children unweighed ' + vm.chosenFilters() + ': ',
                indicator_value: unweighed,
            },
            {
                indicator_name: '% Severely Underweight '+ vm.chosenFilters() +': ',
                indicator_value: severelyUnderweight,
            },
            {
                indicator_name: '% Moderately Underweight '+ vm.chosenFilters() +': ',
                indicator_value: moderatelyUnderweight,
            },
            {
                indicator_name: '% Normal '+ vm.chosenFilters() +': ',
                indicator_value: normal,
            }]
        );
    };

    vm.loadData = function () {
        vm.setStepsMapLabel();
        var usePercentage = true;
        var forceYAxisFromZero = false;
        // mobile dashboard requires all data on both pages, whereas web just requires the current step's data
        // note: it would be better to not load this data on both step pages but instead save it in the JS, but
        // doing that now would be a bit complicated and the server-side caching should make the switching
        // relatively painless
        var allSteps = isMobile ? ['map', 'chart'] : [vm.step];
        for (var i = 0; i < allSteps.length; i++) {
            var currentStep = allSteps[i];
            vm.myPromise = maternalChildService.getUnderweightChildrenData(currentStep, vm.filtersData).then(
                vm.loadDataFromResponse(usePercentage, forceYAxisFromZero, currentStep)
            );
        }
    };

    vm.init();

    vm.resetAdditionalFilter = function() {
        vm.filtersData.gender = '';
        vm.filtersData.age = '';
        $location.search('gender', null);
        $location.search('age', null);
    };

    vm.resetOnlyAgeAdditionalFilter = function() {
        vm.filtersData.age = '';
        $location.search('age', null);
    };

    var options = {
        'xAxisTickFormat': '%b %Y',
        'yAxisTickFormat': ".2%",
        'captionContent': ' Of the total children enrolled for Anganwadi services and weighed, the percentage of children between ' + vm.chosenFilters() + ' who were moderately/severely underweight in the current month. \n' +
        '\n' +
        'Children who are moderately or severely underweight have a higher risk of mortality. ',
    };
    vm.chartOptions = vm.getChartOptions(options);
    vm.chartOptions.chart.width = 1100;
    vm.chartOptions.chart.color = d3.scale.category10().range();
    vm.chartOptions.chart.callback = function(chart) {
        var tooltip = chart.interactiveLayer.tooltip;
        tooltip.contentGenerator(function (d) {

            var findValue = function(values, date) {
                return _.find(values, function(num) { return num['x'] === date; });
            };

            var normal = findValue(vm.chartData[0].values, d.value).y;
            var moderately = findValue(vm.chartData[1].values, d.value).y;
            var severely = findValue(vm.chartData[2].values, d.value).y;
            var unweighed = findValue(vm.chartData[0].values, d.value).unweighed;
            var weighed = findValue(vm.chartData[0].values, d.value).weighed;
            return vm.tooltipContent(d3.time.format('%b %Y')(new Date(d.value)), normal, moderately, severely, unweighed, weighed);
        });
        return chart;
    };

    vm.tooltipContent = function (monthName, normal, moderate, severe, unweighed, weighed) {
        return vm.createTooltipContent(
            monthName,
            [{
                indicator_name: 'Total Children ' + vm.chosenFilters() + ' weighed in given month: ',
                indicator_value: $filter('indiaNumbers')(weighed),
            },
            {
                indicator_name: 'Number of children unweighed ' + vm.chosenFilters() + ': ',
                indicator_value: $filter('indiaNumbers')(unweighed),
            },
            {
                indicator_name: '% children normal ' + vm.chosenFilters() + ': ',
                indicator_value: d3.format(".2%")(normal),
            },
            {
                indicator_name: '% children moderately underweight ' + vm.chosenFilters() + ': ',
                indicator_value: d3.format(".2%")(moderate),
            },
            {
                indicator_name: '% children severely underweight ' + vm.chosenFilters() + ': ',
                indicator_value: d3.format(".2%")(severe),
            }]
        );
    };
}

UnderweightChildrenReportController.$inject = [
    '$scope', '$routeParams', '$location', '$filter', 'maternalChildService', 'locationsService',
    'dateHelperService', 'navigationService', 'userLocationId', 'storageService', 'genders', 'ages', 'haveAccessToAllLocations',
    'baseControllersService', 'isAlertActive', 'isMobile',
];

window.angular.module('icdsApp').directive('underweightChildrenReport', ['templateProviderService', function (templateProviderService) {
    return {
        restrict: 'E',
        templateUrl: function () {
            return templateProviderService.getTemplate('map-chart');
        },
        bindToController: true,
        scope: {
            data: '=',
        },
        controller: UnderweightChildrenReportController,
        controllerAs: '$ctrl',
    };
}]);
<commit_msg>extract popup data from rendering<commit_after>/* global d3, _ */
var url = hqImport('hqwebapp/js/initial_page_data').reverse;

function UnderweightChildrenReportController($scope, $routeParams, $location, $filter, maternalChildService,
    locationsService, dateHelperService, navigationService, userLocationId, storageService, genders, ages, haveAccessToAllLocations,
    baseControllersService, isAlertActive, isMobile) {
    baseControllersService.BaseController.call(this, $scope, $routeParams, $location, locationsService,
        dateHelperService, navigationService, userLocationId, storageService, haveAccessToAllLocations, isMobile);
    var vm = this;
    vm.sectionSlug = 'maternal_child';  // maps to the section of program summary this page lives on
    vm.isAlertActive = isAlertActive;

    var ageIndex = _.findIndex(ages, function (x) {
        return x.id === vm.filtersData.age;
    });
    if (ageIndex !== -1) {
        vm.ageLabel = ages[ageIndex].name;
    }

    var genderIndex = _.findIndex(genders, function (x) {
        return x.id === vm.filtersData.gender;
    });
    if (genderIndex !== -1) {
        vm.genderLabel = genders[genderIndex].name;
    }

    vm.label = "Prevalence of Underweight (Weight-for-Age)";
    vm.steps = {
        'map': {route: '/maternal_and_child/underweight_children/map', label: 'Map View'},
        'chart': {route: '/maternal_and_child/underweight_children/chart', label: 'Chart View'},
    };
    vm.data = {
        legendTitle: 'Percentage Children',
    };
    vm.filters = [];
    vm.rightLegend = {
        info: 'Of the total children enrolled for Anganwadi services and weighed, the percentage of children between 0-5 years who were moderately/severely underweight in the current month. \n' +
        '\n' +
        'Children who are moderately or severely underweight have a higher risk of mortality. ',
    };

    vm.chosenFilters = function() {
        var gender = genderIndex > 0 ? genders[genderIndex].name : '';
        var age = ageIndex > 0 ? ages[ageIndex].name : '0 - 5 years';
        var delimiter = gender && age ? ', ' : '';
        return gender || age ? '(' + gender + delimiter + age + ')' : '';
    };

    function getPopupData(row) {
        var total = row ? $filter('indiaNumbers')(row.weighed) : 'N/A';
        var unweighed = row ? $filter('indiaNumbers')(row.total - row.weighed) : "N/A";
        var severelyUnderweight = row ? d3.format(".2%")(row.severely_underweight / (row.weighed || 1)) : 'N/A';
        var moderatelyUnderweight = row ? d3.format(".2%")(row.moderately_underweight / (row.weighed || 1)) : 'N/A';
        var normal = row ? d3.format(".2%")(row.normal / (row.weighed || 1)) : 'N/A';
        return [
            {
                indicator_name: 'Total Children ' + vm.chosenFilters() + ' weighed in given month: ',
                indicator_value: total,
            },
            {
                indicator_name: 'Number of children unweighed ' + vm.chosenFilters() + ': ',
                indicator_value: unweighed,
            },
            {
                indicator_name: '% Severely Underweight '+ vm.chosenFilters() +': ',
                indicator_value: severelyUnderweight,
            },
            {
                indicator_name: '% Moderately Underweight '+ vm.chosenFilters() +': ',
                indicator_value: moderatelyUnderweight,
            },
            {
                indicator_name: '% Normal '+ vm.chosenFilters() +': ',
                indicator_value: normal,
            }
        ];
    };

    vm.templatePopup = function(loc, row) {
        var popupData = getPopupData(row);
        return vm.createTemplatePopup(
            loc.properties.name,
            popupData,
        );
    };

    vm.loadData = function () {
        vm.setStepsMapLabel();
        var usePercentage = true;
        var forceYAxisFromZero = false;
        // mobile dashboard requires all data on both pages, whereas web just requires the current step's data
        // note: it would be better to not load this data on both step pages but instead save it in the JS, but
        // doing that now would be a bit complicated and the server-side caching should make the switching
        // relatively painless
        var allSteps = isMobile ? ['map', 'chart'] : [vm.step];
        for (var i = 0; i < allSteps.length; i++) {
            var currentStep = allSteps[i];
            vm.myPromise = maternalChildService.getUnderweightChildrenData(currentStep, vm.filtersData).then(
                vm.loadDataFromResponse(usePercentage, forceYAxisFromZero, currentStep)
            );
        }
    };

    vm.init();

    vm.resetAdditionalFilter = function() {
        vm.filtersData.gender = '';
        vm.filtersData.age = '';
        $location.search('gender', null);
        $location.search('age', null);
    };

    vm.resetOnlyAgeAdditionalFilter = function() {
        vm.filtersData.age = '';
        $location.search('age', null);
    };

    var options = {
        'xAxisTickFormat': '%b %Y',
        'yAxisTickFormat': ".2%",
        'captionContent': ' Of the total children enrolled for Anganwadi services and weighed, the percentage of children between ' + vm.chosenFilters() + ' who were moderately/severely underweight in the current month. \n' +
        '\n' +
        'Children who are moderately or severely underweight have a higher risk of mortality. ',
    };
    vm.chartOptions = vm.getChartOptions(options);
    vm.chartOptions.chart.width = 1100;
    vm.chartOptions.chart.color = d3.scale.category10().range();
    vm.chartOptions.chart.callback = function(chart) {
        var tooltip = chart.interactiveLayer.tooltip;
        tooltip.contentGenerator(function (d) {

            var findValue = function(values, date) {
                return _.find(values, function(num) { return num['x'] === date; });
            };

            var normal = findValue(vm.chartData[0].values, d.value).y;
            var moderately = findValue(vm.chartData[1].values, d.value).y;
            var severely = findValue(vm.chartData[2].values, d.value).y;
            var unweighed = findValue(vm.chartData[0].values, d.value).unweighed;
            var weighed = findValue(vm.chartData[0].values, d.value).weighed;
            return vm.tooltipContent(d3.time.format('%b %Y')(new Date(d.value)), normal, moderately, severely, unweighed, weighed);
        });
        return chart;
    };

    vm.tooltipContent = function (monthName, normal, moderate, severe, unweighed, weighed) {
        return vm.createTooltipContent(
            monthName,
            [{
                indicator_name: 'Total Children ' + vm.chosenFilters() + ' weighed in given month: ',
                indicator_value: $filter('indiaNumbers')(weighed),
            },
            {
                indicator_name: 'Number of children unweighed ' + vm.chosenFilters() + ': ',
                indicator_value: $filter('indiaNumbers')(unweighed),
            },
            {
                indicator_name: '% children normal ' + vm.chosenFilters() + ': ',
                indicator_value: d3.format(".2%")(normal),
            },
            {
                indicator_name: '% children moderately underweight ' + vm.chosenFilters() + ': ',
                indicator_value: d3.format(".2%")(moderate),
            },
            {
                indicator_name: '% children severely underweight ' + vm.chosenFilters() + ': ',
                indicator_value: d3.format(".2%")(severe),
            }]
        );
    };

}

UnderweightChildrenReportController.$inject = [
    '$scope', '$routeParams', '$location', '$filter', 'maternalChildService', 'locationsService',
    'dateHelperService', 'navigationService', 'userLocationId', 'storageService', 'genders', 'ages', 'haveAccessToAllLocations',
    'baseControllersService', 'isAlertActive', 'isMobile',
];

window.angular.module('icdsApp').directive('underweightChildrenReport', ['templateProviderService', function (templateProviderService) {
    return {
        restrict: 'E',
        templateUrl: function () {
            return templateProviderService.getTemplate('map-chart');
        },
        bindToController: true,
        scope: {
            data: '=',
        },
        controller: UnderweightChildrenReportController,
        controllerAs: '$ctrl',
    };
}]);
<|endoftext|>


<commit_before>(function (window, angular, $, chrome, undefined) {
    'use strict';

    var CONTROLLER_ID = 'ConfigController';

    angular.module('powellDevTools').controller(CONTROLLER_ID,
        ['$scope', '$element', '$q', '$sce', '$timeout', '$interval', 'datacontextUtility',
            configControllerModule]);

    function configControllerModule($scope, $element, $q, $sce, $timeout, $interval, datacontextUtility) {
        // Check background scripts freshness
        var deferred = $q.defer();
            chrome.runtime.sendMessage({ 'action': 'checkScriptFreshness', 'globalMD5': window.GLOBAL },
                function(response){
                    if(!response && chrome.runtime.lastError != null) {
                        deferred.reject(chrome.runtime.lastError);
                    } else {
                        deferred.resolve(response);
                    }
                });
            deferred.promise.catch(function(response) {
                // Error while communicating with background scripts. Reloading plugin.
                chrome.runtime.reload();
            })

        return new ConfigController($scope, $element, $q, $sce, $timeout, $interval, datacontextUtility);
    }

    var ConfigController = function ($scope, $element, $q, $sce, $timeout, $interval, datacontextUtility) {
        var _this = this;

        /*****************
         * View variables
         *****************/
        $scope.configTemplateUrl = 'https://rawgit.com/Expertime/powell-developer-tools/master/resources/html/ConfigController.html';
        $scope.config = {
            repoJsURL: datacontextUtility.get_repoJsURL(),
            defaultJsRepoState: datacontextUtility.get_defaultJsRepoState(),
            repoCssURL: datacontextUtility.get_repoCssURL(),
            defaultCssRepoState: datacontextUtility.get_defaultCssRepoState(),
            //devJsID: datacontextUtility.get_devJsID(),
            devCssID: datacontextUtility.get_devCssID(),
            //tenantJsID: datacontextUtility.get_tenantJsID(),
            defaultJsTenantState: datacontextUtility.get_defaultJsTenantState(),
            tenantCssID: datacontextUtility.get_tenantCssID(),
            defaultCssTenantState: datacontextUtility.get_defaultCssTenantState(),
            envID: datacontextUtility.get_envID(),
            themeID: datacontextUtility.get_themeID(),
            useThemeState: datacontextUtility.get_useThemeState(),
            sourceMode : datacontextUtility.get_sourceMode(),
            cdnJsMode : datacontextUtility.get_cdnJsMode(),
            cdnCssMode : datacontextUtility.get_cdnCssMode()
        };

        $scope.enableJsEmulation = datacontextUtility.isEnabled('script');
        $scope.enableCssEmulation = datacontextUtility.isEnabled('stylesheet');
        $scope.environments = datacontextUtility.ENVIRONMENTS;
        $scope.sourceModes = datacontextUtility.SOURCEMODES;
        $scope.cdnModes = datacontextUtility.CDNMODES;

        $scope.$watchCollection('config', function(newValues) {
            for (var value in newValues) {
                datacontextUtility.setLocalStorageValue(value, newValues[value]);
            }
            $scope.emulationSources = {
                css: datacontextUtility.get_cssSourceUrl('*.css'),
                js: datacontextUtility.get_jsSourceUrl()
            };
        });

        $scope.isPaneActive = function (paneId) {
            return paneId == datacontextUtility.get_activePane() ? 'active' : '';
        };

        $scope.setActivePane = function (paneId) {
            datacontextUtility.set_activePane(paneId);
        };

        $scope.switchChanged = function (sourceKind) {
            var deferred = $q.defer();
            chrome.runtime.sendMessage({ 'action': 'setEnabled', 'enabled': !datacontextUtility.isEnabled(sourceKind), 'sourceKind': sourceKind },
                function(response){
                    if(!response && chrome.runtime.lastError != null) {
                        deferred.reject(chrome.runtime.lastError);
                    } else {
                        deferred.resolve(response);
                    }
                });
            deferred.promise.catch(function(response) {
                // Error while communicating with background scripts. Reloading plugin.
                chrome.runtime.reload();
            })
        };

        $scope.clearLocalStorage = function() {
            chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
                chrome.tabs.sendMessage(tabs[0].id, {method: "powDevTools.clearStorage"}, function(storageResponse) {
                    chrome.tabs.reload(tabs[0].id, {bypassCache: true}, function(refreshResponse) {
                        console.log(storageResponse, refreshResponse);
                        chrome.notifications.create(null, {
                            type: "basic",
                            iconUrl: "resources/img/icon128.png",
                            title: "Powell Dev Tools",
                            message: "Local storage, local session and browser cache cleared successfully"
                        });
                    });
                });
            });
        };
    };

})(window, window.angular, window.jQuery, window.chrome);<commit_msg>Fix too many plugin reload<commit_after>(function (window, angular, $, chrome, undefined) {
    'use strict';

    var CONTROLLER_ID = 'ConfigController';

    angular.module('powellDevTools').controller(CONTROLLER_ID,
        ['$scope', '$element', '$q', '$sce', '$timeout', '$interval', 'datacontextUtility',
            configControllerModule]);

    function configControllerModule($scope, $element, $q, $sce, $timeout, $interval, datacontextUtility) {
        // Check background scripts freshness
       /* var deferred = $q.defer();
        chrome.runtime.sendMessage({ 'action': 'checkScriptFreshness', 'globalMD5': window.GLOBAL },
            function(response){
                if(!response && chrome.runtime.lastError != null) {
                    deferred.reject(chrome.runtime.lastError);
                } else {
                    deferred.resolve(response);
                }
            });
        deferred.promise.catch(function(response) {
            // Error while communicating with background scripts. Reloading plugin.
            chrome.runtime.reload();
        });*/

        return new ConfigController($scope, $element, $q, $sce, $timeout, $interval, datacontextUtility);
    }

    var ConfigController = function ($scope, $element, $q, $sce, $timeout, $interval, datacontextUtility) {
        var _this = this;

        /*****************
         * View variables
         *****************/
        $scope.configTemplateUrl = 'https://rawgit.com/Expertime/powell-developer-tools/master/resources/html/ConfigController.html';
        $scope.config = {
            repoJsURL: datacontextUtility.get_repoJsURL(),
            defaultJsRepoState: datacontextUtility.get_defaultJsRepoState(),
            repoCssURL: datacontextUtility.get_repoCssURL(),
            defaultCssRepoState: datacontextUtility.get_defaultCssRepoState(),
            //devJsID: datacontextUtility.get_devJsID(),
            devCssID: datacontextUtility.get_devCssID(),
            //tenantJsID: datacontextUtility.get_tenantJsID(),
            defaultJsTenantState: datacontextUtility.get_defaultJsTenantState(),
            tenantCssID: datacontextUtility.get_tenantCssID(),
            defaultCssTenantState: datacontextUtility.get_defaultCssTenantState(),
            envID: datacontextUtility.get_envID(),
            themeID: datacontextUtility.get_themeID(),
            useThemeState: datacontextUtility.get_useThemeState(),
            sourceMode : datacontextUtility.get_sourceMode(),
            cdnJsMode : datacontextUtility.get_cdnJsMode(),
            cdnCssMode : datacontextUtility.get_cdnCssMode()
        };

        $scope.enableJsEmulation = datacontextUtility.isEnabled('script');
        $scope.enableCssEmulation = datacontextUtility.isEnabled('stylesheet');
        $scope.environments = datacontextUtility.ENVIRONMENTS;
        $scope.sourceModes = datacontextUtility.SOURCEMODES;
        $scope.cdnModes = datacontextUtility.CDNMODES;

        $scope.$watchCollection('config', function(newValues) {
            for (var value in newValues) {
                datacontextUtility.setLocalStorageValue(value, newValues[value]);
            }
            $scope.emulationSources = {
                css: datacontextUtility.get_cssSourceUrl('*.css'),
                js: datacontextUtility.get_jsSourceUrl()
            };
        });

        $scope.isPaneActive = function (paneId) {
            return paneId == datacontextUtility.get_activePane() ? 'active' : '';
        };

        $scope.setActivePane = function (paneId) {
            datacontextUtility.set_activePane(paneId);
        };

        $scope.switchChanged = function (sourceKind) {
            var deferred = $q.defer();
            chrome.runtime.sendMessage({ 'action': 'setEnabled', 'enabled': !datacontextUtility.isEnabled(sourceKind), 'sourceKind': sourceKind },
                function(response){
                    if(!response && chrome.runtime.lastError != null) {
                        deferred.reject(chrome.runtime.lastError);
                    } else {
                        deferred.resolve(response);
                    }
                });
            deferred.promise.catch(function(response) {
                // Error while communicating with background scripts. Reloading plugin.
                chrome.runtime.reload();
            })
        };

        $scope.clearLocalStorage = function() {
            chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
                chrome.tabs.sendMessage(tabs[0].id, {method: "powDevTools.clearStorage"}, function(storageResponse) {
                    chrome.tabs.reload(tabs[0].id, {bypassCache: true}, function(refreshResponse) {
                        console.log(storageResponse, refreshResponse);
                        chrome.notifications.create(null, {
                            type: "basic",
                            iconUrl: "resources/img/icon128.png",
                            title: "Powell Dev Tools",
                            message: "Local storage, local session and browser cache cleared successfully"
                        });
                    });
                });
            });
        };
    };

})(window, window.angular, window.jQuery, window.chrome);<|endoftext|>


<commit_before>
function TradeifyWidget(offers_selector, current_tags_selector) {
    var offers;
    var offers_render_fn;
    var current_tags;
    var offers_uri;

    var map;

    /*
    google.maps.Map.prototype.markers = new Array();

    google.maps.Map.prototype.getMarkers = function() {
        return this.markers
    };

    google.maps.Map.prototype.clearMarkers = function() {
        for (var i = 0; i < this.markers.length; i++) {
            this.markers[i].setMap(null);
        }
        this.markers = new Array();
    };

    google.maps.Marker.prototype._setMap = google.maps.Marker.prototype.setMap;

    google.maps.Marker.prototype.setMap = function(map) {
        if (map) {
            map.markers[map.markers.length] = this;
        }
        this._setMap(map);
    };
    */
    var offers_directives = {
        'div.offer': {
            'offer <- messages': {
                'a.username@href': 'offer.user.more_info_url',
                'a.avatar@href': 'offer.user.more_info_url',
                'a.username': 'offer.user.screen_name',
                '.avatar img@src': 'offer.user.profile_pic_url',
                '.msg .text': 'offer.offer_text',
                'span.tags': {
                    'tag <- offer.tags': {
                        'a': 'tag.tag',
                        '+a@class': 'tag.type'
                    }
                },
                '.when': 'offer.date'
            }
        }
    };
    var map_directives = {
        'div.map_offer': {
        'map_offer <- messages': {
        'a.map_username@href': 'map_offer.user.more_info_url',
        'a.map_username': 'map_offer.user.screen_name',
        '.map_avatar img@src': 'map_offer.user.profile_pic_url',
        '.map_msg .map_text': 'map_offer.offer_text',
        'span.map_tags': {
        'map_tag <- map_offer.tags': {
        'a': 'map_tag.tag',
        '+a@class': 'map_tag.type'
                    }
                },
                '.map_when': 'map_offer.date'
            }
        }
    };
    function updateMap() {
        var myLatlng = new google.maps.LatLng(-25.363882, 131.044922);
        var myOptions = {
            zoom: 2,
            center: myLatlng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        }
        map = new google.maps.Map(document.getElementById("offer_map"), myOptions);
        //map.clearMarkers();
        var latlng = new Array();
        $.each(offers, function() {
            var post = new google.maps.LatLng(this.offer_latitude, this.offer_longitude);
            latlng.push(post);
            var title = this.offer_address; //this.offer_text + " " + this.user.more_info_url;
            var tags = new Array();
            $.each(this.tags,function(){
                if(this.type=="loc")tags.push(this);
            });
            var marker = new google.maps.Marker({
                clickable: true,
                title: title,
                position: post,
                map: map,
                tags: tags
            });

            google.maps.event.addListener(marker, "click", function() {
                createPopup(map, marker);
            });
        });
        var latlngbounds = new GLatLngBounds();
        for (var i = 0; i < latlng.length; i++) {
            latlngbounds.extend(latlng[i]);
        }
        map.setCenter(latlngbounds.getCenter(), map.getBoundsZoomLevel(latlngbounds));
    }
    var map_popup = $("#map_popup" + ' .map_template').compile(map_directives);
    $("#map_popup" + ' .map_template').hide();
    function createPopup(map, marker) {
        var tags_backup = current_tags.tags.concat(marker.tags);
        /*
        current_tags.tags.slice();
        $.each(marker.tags,function{
        var tag = new Tag();
        tag.type = "loc";
        tag.text = marker.title;
        tags_backup.push(tag);
        });
        */
        var json_url = build_search_query(offers_uri, tags_backup);
        $.getJSON(json_url, function(raw_data) {
            $("#map_popup" + ' .map_template').render(raw_data, map_popup);

            //$("#map_offer_template").quickPager({ pageSize: 2},"#pager");
            var infowindow = new google.maps.InfoWindow(
            {
                content: $("#map_popup").html()
            });
            $("#map_popup" + ' .map_template').hide();
            infowindow.open(map, marker);
        });
    }
    var init = function() {
    $("#results").tabs({
        //event: 'mouseover'
        fx: { height: 'toggle', opacity: 'toggle' },
        show: function(event, ui) {
            if (ui.panel.id == "results-2") {
                $(ui.panel).css("height", "100%");
                updateMap();
                // map.checkResize();

            }
        }
    });
        offers_uri = container.offers_uri;

        //compile to a function as soon as possible (ie in 'constructor')
        offers_render_fn = $(offers_selector + ' .template').compile(offers_directives);

        current_tags = new Tags(current_tags_selector);
        current_tags.tag_click(function() {
            remove_filter($(this).text());
            return false;
        });
        //update_offers();
        }
    function offers_(onCompletion){
       var json_url = build_search_query(offers_uri);
       $.getJSON(json_url, function(data) {
           $(offers_selector + ' .template').render(data, offers_render_fn);

           $(offers_selector + ' .tags a').click(function() {
               //add a filter when tags under a message are clicked
               add_filter($(this).text(), $(this).css());
           });
           onCompletion(data);
       });
    }
    var update_offers = function() {
    offers_(function(data) {
            offers = data.messages;
            updateMap();
            $("#offer_template").quickPager({ pageSize: 4 }, "#pager");
        });
        //$("#results").tabs();
    };

    var add_filter = function(tag_text, tag_type) {
        current_tags.add_tag(tag_text, tag_type);
        update_offers();
    };

    var remove_filter = function(tag_text) {
        current_tags.remove_tag(tag_text);
        update_offers();
    };

    var add_fixed_filter = function(tag_text, tag_type) {
        current_tags.add_fixed_tag(tag_text, tag_type, false);
        update_offers();
    };

    var build_search_query = function(baseUrl) {
    var query = "";
    var current_tags_array = (arguments.length > 1) ? arguments[1] : current_tags.tags;
    for (tag in current_tags_array) {
            if (query != "")
                query = query + "&";
            query = query + "tag=" + current_tags_array[tag].tag;
        }
        return baseUrl + "?" + query + "&jsoncallback=?";
    };

    init();

    /* 'public' methods */
    this.update_offers = update_offers;
    this.add_filter = add_filter;
    this.add_fixed_filter = add_fixed_filter;
    this.get_fixed_tags = function(){
        return current_tags.get_fixed_tags();
    }
    this.get_offers = function() {
        return offers;
    }
}
<commit_msg>tryed to centre map zoom on markers 3<commit_after>
function TradeifyWidget(offers_selector, current_tags_selector) {
    var offers;
    var offers_render_fn;
    var current_tags;
    var offers_uri;

    var map;

    /*
    google.maps.Map.prototype.markers = new Array();

    google.maps.Map.prototype.getMarkers = function() {
        return this.markers
    };

    google.maps.Map.prototype.clearMarkers = function() {
        for (var i = 0; i < this.markers.length; i++) {
            this.markers[i].setMap(null);
        }
        this.markers = new Array();
    };

    google.maps.Marker.prototype._setMap = google.maps.Marker.prototype.setMap;

    google.maps.Marker.prototype.setMap = function(map) {
        if (map) {
            map.markers[map.markers.length] = this;
        }
        this._setMap(map);
    };
    */
    var offers_directives = {
        'div.offer': {
            'offer <- messages': {
                'a.username@href': 'offer.user.more_info_url',
                'a.avatar@href': 'offer.user.more_info_url',
                'a.username': 'offer.user.screen_name',
                '.avatar img@src': 'offer.user.profile_pic_url',
                '.msg .text': 'offer.offer_text',
                'span.tags': {
                    'tag <- offer.tags': {
                        'a': 'tag.tag',
                        '+a@class': 'tag.type'
                    }
                },
                '.when': 'offer.date'
            }
        }
    };
    var map_directives = {
        'div.map_offer': {
        'map_offer <- messages': {
        'a.map_username@href': 'map_offer.user.more_info_url',
        'a.map_username': 'map_offer.user.screen_name',
        '.map_avatar img@src': 'map_offer.user.profile_pic_url',
        '.map_msg .map_text': 'map_offer.offer_text',
        'span.map_tags': {
        'map_tag <- map_offer.tags': {
        'a': 'map_tag.tag',
        '+a@class': 'map_tag.type'
                    }
                },
                '.map_when': 'map_offer.date'
            }
        }
    };
    function updateMap() {
        var myLatlng = new google.maps.LatLng(-25.363882, 131.044922);
        var myOptions = {
            zoom: 2,
            center: myLatlng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        }
        map = new google.maps.Map(document.getElementById("offer_map"), myOptions);
        //map.clearMarkers();
        var latlng = new Array();
        $.each(offers, function() {
            var post = new google.maps.LatLng(this.offer_latitude, this.offer_longitude);
            latlng.push(post);
            var title = this.offer_address; //this.offer_text + " " + this.user.more_info_url;
            var tags = new Array();
            $.each(this.tags,function(){
                if(this.type=="loc")tags.push(this);
            });
            var marker = new google.maps.Marker({
                clickable: true,
                title: title,
                position: post,
                map: map,
                tags: tags
            });

            google.maps.event.addListener(marker, "click", function() {
                createPopup(map, marker);
            });
        });
        var latlngbounds = new google.maps.LatLng();
        for (var i = 0; i < latlng.length; i++) {
            latlngbounds.extend(latlng[i]);
        }
        map.setCenter(latlngbounds.getCenter(), map.getBoundsZoomLevel(latlngbounds));
    }
    var map_popup = $("#map_popup" + ' .map_template').compile(map_directives);
    $("#map_popup" + ' .map_template').hide();
    function createPopup(map, marker) {
        var tags_backup = current_tags.tags.concat(marker.tags);
        /*
        current_tags.tags.slice();
        $.each(marker.tags,function{
        var tag = new Tag();
        tag.type = "loc";
        tag.text = marker.title;
        tags_backup.push(tag);
        });
        */
        var json_url = build_search_query(offers_uri, tags_backup);
        $.getJSON(json_url, function(raw_data) {
            $("#map_popup" + ' .map_template').render(raw_data, map_popup);

            //$("#map_offer_template").quickPager({ pageSize: 2},"#pager");
            var infowindow = new google.maps.InfoWindow(
            {
                content: $("#map_popup").html()
            });
            $("#map_popup" + ' .map_template').hide();
            infowindow.open(map, marker);
        });
    }
    var init = function() {
    $("#results").tabs({
        //event: 'mouseover'
        fx: { height: 'toggle', opacity: 'toggle' },
        show: function(event, ui) {
            if (ui.panel.id == "results-2") {
                $(ui.panel).css("height", "100%");
                updateMap();
                // map.checkResize();

            }
        }
    });
        offers_uri = container.offers_uri;

        //compile to a function as soon as possible (ie in 'constructor')
        offers_render_fn = $(offers_selector + ' .template').compile(offers_directives);

        current_tags = new Tags(current_tags_selector);
        current_tags.tag_click(function() {
            remove_filter($(this).text());
            return false;
        });
        //update_offers();
        }
    function offers_(onCompletion){
       var json_url = build_search_query(offers_uri);
       $.getJSON(json_url, function(data) {
           $(offers_selector + ' .template').render(data, offers_render_fn);

           $(offers_selector + ' .tags a').click(function() {
               //add a filter when tags under a message are clicked
               add_filter($(this).text(), $(this).css());
           });
           onCompletion(data);
       });
    }
    var update_offers = function() {
    offers_(function(data) {
            offers = data.messages;
            updateMap();
            $("#offer_template").quickPager({ pageSize: 4 }, "#pager");
        });
        //$("#results").tabs();
    };

    var add_filter = function(tag_text, tag_type) {
        current_tags.add_tag(tag_text, tag_type);
        update_offers();
    };

    var remove_filter = function(tag_text) {
        current_tags.remove_tag(tag_text);
        update_offers();
    };

    var add_fixed_filter = function(tag_text, tag_type) {
        current_tags.add_fixed_tag(tag_text, tag_type, false);
        update_offers();
    };

    var build_search_query = function(baseUrl) {
    var query = "";
    var current_tags_array = (arguments.length > 1) ? arguments[1] : current_tags.tags;
    for (tag in current_tags_array) {
            if (query != "")
                query = query + "&";
            query = query + "tag=" + current_tags_array[tag].tag;
        }
        return baseUrl + "?" + query + "&jsoncallback=?";
    };

    init();

    /* 'public' methods */
    this.update_offers = update_offers;
    this.add_filter = add_filter;
    this.add_fixed_filter = add_fixed_filter;
    this.get_fixed_tags = function(){
        return current_tags.get_fixed_tags();
    }
    this.get_offers = function() {
        return offers;
    }
}
<|endoftext|>


<commit_before>
// Calls this.resize on resize and orientationchange events
// --------------------------------------
// Remember to call this._super() if you override didInsertElement or willDestroyElement.
//

require('../mixins/responds-to-resize');

var RESIZE_EVENTS = 'resize orientationchange';
var onResize;

App.RespondsToResize = Ember.Mixin.create({

  init: function () {
    Ember.assert('RespondsToResize must be mixed in to a View', this instanceof Ember.View);
    this._super();
    var self = this;
    onResize = function (e) {
      window.requestAnimationFrame( self.resize.bind(self) );
    };
  },

  didInsertElement: function () {
    this._super();
    this.resize();
    $(window).on(RESIZE_EVENTS, this, onResize.bind(this));
  },

  willDestroyElement: function () {
    $(window).off(RESIZE_EVENTS, this, onResize.bind(this));
    this._super();
  },

  resize: function () {
    console.warn('[RespondsToResize] Please define a resize function in the view using this mixin.');
  }
});
<commit_msg>fixed resizing ApplicationView to be interval-based, not based on resize..<commit_after>
// Calls this.resize on resize and orientationchange events
// --------------------------------------
// Remember to call this._super() if you override didInsertElement or willDestroyElement.
//

require('../mixins/responds-to-resize');

var RESIZE_EVENTS = 'resize orientationchange';

App.RespondsToResize = Ember.Mixin.create({

  didInsertElement: function () {
    Ember.assert('RespondsToResize must be mixed in to a View', this instanceof Ember.View);
    $(window).on( RESIZE_EVENTS, this.debouncedResize.bind(this) );
  },

  willDestroyElement: function () {
    $(window).off( RESIZE_EVENTS, this.debouncedResize.bind(this) );
    this._super();
  },

  debouncedResize: function(e) {
    window.requestAnimationFrame( this.resize.bind(this, e) );
  },

  resize: function (e) {
    console.warn('[RespondsToResize] Please define a resize function in the view using this mixin.');
  }
});
<|endoftext|>


<commit_before>
/**
 * set the responseBody JSON here. each response is named with a transactionId.
 * i.e. when a user send a query string with transactionId=good the response
 * under "good" will be returned
 */

var responses = {

  good: function() {

    return {
      companyId: "ResaleWeekly",
      itemId: "259853",
      itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      transactionId: "random",
      currencyCode: "GBP",
      description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
      imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
      listPrice: 55000.00,
      minimumPrice: 0,
      terms: "",
      title: "CATERPILLAR 375L"
    }
  },
  bad : function() {

    return {
      companyId: null,
      //itemId: "259853",
      itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      transactionId: "random",
      //currencyCode: "GBP",
      description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
      imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
      listPrice: 55000.00,
      minimumPrice: 0,
      terms: "",
      title: "CATERPILLAR 375L"
    }
  }
};

module.exports = function(responseName){

  return responses[responseName]();
};<commit_msg>added default response as "good" response.<commit_after>
/**
 * set the responseBody JSON here. each response is named with a transactionId.
 * i.e. when a user send a query string with transactionId=good the response
 * under "good" will be returned
 */

var responses = {

  good: function() {

    return {
      companyId: "ResaleWeekly",
      itemId: "259853",
      itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      transactionId: "random",
      currencyCode: "GBP",
      description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
      imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
      listPrice: 55000.00,
      minimumPrice: 0,
      terms: "",
      title: "CATERPILLAR 375L"
    }
  },
  bad : function() {

    return {
      companyId: null,
      //itemId: "259853",
      itemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      mobileItemUrl: "http:\/\/www.resaleweekly.com\/catalog\/product\/view\/id\/259853",
      transactionId: "random",
      //currencyCode: "GBP",
      description: "IN VERY GOOD WORKING CONDITION NEW DASH MONITOR BEING FITTED NEW TRACK SPADS BEING FITTEDNEW IDLERS BEING FITTED FULLY SERVICED LARGE ROCK BUCKETTRACK CHAINS 80% SPROCKETS 80% NO CRACKS OR WELDING ON BOOM OR DIPPER FIXED FRAME UNDER CARRIAGE MACHINE WHEN WE ARE FINISHED WILL BE AS GOOD AS NEW AND READY FOR WORK ",
      imageUrl: "http:\/\/www.resaleweekly.com\/media\/catalog\/product\/1\/4\/14c146d681087b6_1408116116.jpg",
      listPrice: 55000.00,
      minimumPrice: 0,
      terms: "",
      title: "CATERPILLAR 375L"
    }
  }
};

module.exports = function(responseName){

  return responses[(responseName || "good")]();
};<|endoftext|>


<commit_before>export default ['$rootScope', '$http', '$q', function ($rootScope, $http, $q) {

  $rootScope.showLoginError = false

  $rootScope.showLogin = function showLogin (originalResponse) {

    jQuery('#login').fadeIn()

    let deferred = $q.defer()
    $rootScope.originalResponse = originalResponse
    $rootScope.promise = deferred

    return deferred.promise

  }

  $rootScope.attemptLogin = function attemptLogin () {

    let data = {
      email: $rootScope.loginFormEmail,
      password: $rootScope.loginFormPassword
    }

    $http.post('/login', data).then((response) => {

      $rootScope.promise.resolve($http($rootScope.originalResponse.config))
      jQuery('#login').hide()
      $rootScope.showLoginError = false

    }, () => {

      $rootScope.showLoginError = true

    })

  }

  $rootScope.logout = function logout () {
    $http.post('/logout').then(() => {
      $rootScope.showLogin()
    })
  }

}]
<commit_msg>Loading user details on successful login<commit_after>export default ['$rootScope', '$http', '$q', function ($rootScope, $http, $q) {

  $rootScope.showLoginError = false

  $rootScope.showLogin = function showLogin (originalResponse) {

    jQuery('#login').fadeIn()

    let deferred = $q.defer()
    $rootScope.originalResponse = originalResponse
    $rootScope.promise = deferred

    return deferred.promise

  }

  $rootScope.attemptLogin = function attemptLogin () {

    let data = {
      email: $rootScope.loginFormEmail,
      password: $rootScope.loginFormPassword
    }

    $http.post('/login', data).then((response) => {

      $rootScope.promise.resolve($http($rootScope.originalResponse.config))
      jQuery('#login').hide()
      $rootScope.showLoginError = false
      $rootScope.loadAuthenticatedUser()

    }, () => {

      $rootScope.showLoginError = true

    })

  }

  $rootScope.logout = function logout () {
    $http.post('/logout').then(() => {
      $rootScope.showLogin()
    })
  }

}]
<|endoftext|>


<commit_before>const remote = require('electron').remote;
const app = remote.app;

var users = remote.getGlobal("users");
var user_sprites = {}
var player = remote.getGlobal("player");
var level = remote.getGlobal("world");
var synced = remote.getGlobal("synced");

var word = "phaser";
var correct = [];
var bmd;
var chat;

console.log("game.js is running.");

var ASPECT_RATIO = 16/9;
var GAME_ASPECT_RATIO = 13.5/9;
var CHAT_ASPECT_RATIO = ASPECT_RATIO - GAME_ASPECT_RATIO; // 2.5/9

var TILE_SIZE = 16;
var ZOOM_FACTOR = 5;
//console.log($(window).width());

var WINDOW_WIDTH = $(window).width();
var WINDOW_HEIGHT = WINDOW_WIDTH / ASPECT_RATIO;
var GAME_WIDTH = WINDOW_WIDTH / ASPECT_RATIO * GAME_ASPECT_RATIO;
var CHAT_WIDTH = WINDOW_WIDTH - GAME_WIDTH;

var ROTATIONS = ["left", "right", "up", "down"];
var player_sprite;

var game = new Phaser.Game(WINDOW_WIDTH, WINDOW_HEIGHT, Phaser.AUTO, 'content', {
  preload: preload,
  create: create,
  update: update,
  render: render
});

function coord_to_pixels(c) {
	return c * ZOOM_FACTOR * TILE_SIZE + (ZOOM_FACTOR*TILE_SIZE)/2;
}

function Sprite(name, url, x, y) {
	this.move = function(direction) {
		if((this.moveTime + this.moveThreshold) < game.time.now) {
			if(ROTATIONS[this.rotation] != direction) {
				var direction_int = ROTATIONS.indexOf(direction);
				this.rotation = direction_int >= 0 ? direction_int : this.rotation;
				this.moveTime = game.time.now;
			}
			else {
				var x_par = 0;
				var y_par = 0;
				if(direction == "left") {
					x_par = -1;
				} else if (direction == "right") {
					x_par = 1;
				} else if (direction == "up") {
					y_par = -1;
				} else if (direction == "down") {
					y_par = 1;
				} else {
					return;
				}
				if(!(tiles[this.y + y_par][this.x + x_par].collideable)){
					this.x += x_par;
					this.y += y_par;
					this.moveTime = game.time.now;
				}
				else {
					//COLLIDE
				}
			}
			this.updateLocation();
		}
	}
	this.updateLocation = function() {
		this.sprite.x = this.getX(); // ADD LERP
		this.sprite.y = this.getY(); // ADD LERP
		//console.log(this.sprite.scale.x);
		//this.sprite.scale.x = Math.abs(this.sprite.scale.x) - (this.rotation % 2) * 2 * Math.abs(this.sprite.scale.x);
		if(ROTATIONS[this.rotation] == "up") {
			this.sprite.angle = 90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(ROTATIONS[this.rotation] == "down"){
			this.sprite.angle = -90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(ROTATIONS[this.rotation] == "left") {
			this.sprite.angle = 0;
			this.sprite.scale.x = -Math.abs(this.sprite.scale.x);
		} else if(ROTATIONS[this.rotation] == "right") {
			this.sprite.angle = 0;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		}
	}
	this.getX = function() {
		return this.x * ZOOM_FACTOR * TILE_SIZE + TILE_SIZE/2;
	}
	this.getY = function() {
		return this.y * ZOOM_FACTOR * TILE_SIZE + TILE_SIZE/2;
	}
	this.setX = function(x) {
		this.x = x; // ADD LERP
	}
	this.setY = function(y) {
		this.y = y; // ADD LERP
	}
	this.setRotation = function(rotation) {
		if(rotation == "up") {
			this.sprite.angle = 90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(rotation == "down"){
			this.sprite.angle = -90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(rotation == "left") {
			this.sprite.angle = 0;
			this.sprite.scale.x = -Math.abs(this.sprite.scale.x);
		} else if(rotation == "right") {
			this.sprite.angle = 0;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		}
	}

	this.name = name;
	this.url = url;
	this.x = x;
	this.y = y;
	this.sprite = game.add.sprite(this.getX(), this.getY(), this.name);
	this.sprite.width = TILE_SIZE * ZOOM_FACTOR;
	this.sprite.height = TILE_SIZE * ZOOM_FACTOR;
	this.sprite.anchor.setTo(0.5, 0.5);
	this.moveTime = 0;
	this.moveThreshold = 150;
	this.rotation = 0;
}

function Tile(val, x, y) {
  this.url = tileset[val].url;
  this.x = x;
  this.y = y;
  this.collideable = tileset[val].collideable;
  var sprite = game.add.sprite(coord_to_pixels(x), coord_to_pixels(y), tileset[val].name);
  sprite.anchor.setTo(0.5, 0.5);
  sprite.width = ZOOM_FACTOR * TILE_SIZE;
  sprite.height = ZOOM_FACTOR * TILE_SIZE;
}

function World() {

}

function Chat() {
	this.width = CHAT_WIDTH;
	this.height = WINDOW_HEIGHT;
	var background = new Phaser.Rectangle(GAME_WIDTH, 0, CHAT_WIDTH, WINDOW_HEIGHT);
}

var tileset = [
	{
		name: "wall",
		url: "./assets/wall.png",
		collideable: true
	},
	{
		name: "floor",
		url: "./assets/floor.png",
		collideable: false
	}
];

var tiles = []

function loadImages() {
	for (i in tileset) {
		game.load.image(tileset[i].name, tileset[i].url);
	}
	game.load.image(tileset[i].name, tileset[i].url);
	game.load.spritesheet(player.name, "./assets/player.png", 32, 48);
}

function buildWorld() {
	//game.world.setBounds(0, 0, 1280, 600);
	var x, y;
	y = 0;
	for(i in level) {
		x = 0;
		var temp = [];
		for (j in level[i]) {
			console.log(level[i][j]);
			temp.push(new Tile(level[i][j], x, y));
			x++;
		}
		tiles.push(temp);
		y++;

	}
}

function keyPress(char) {
    //  Clear the BMD
    bmd.cls();
    //  Set the x value we'll start drawing the text from
    var x = 64;
	//  Now draw the word, letter by letter, changing colour as required
	bmd.context.fillStyle = '#00ff00';
	bmd.context.fillText(char, x, 64);
	console.log(char);
	x += bmd.context.measureText(char).width;
}

function loadBitmapData() {
	//  This is our BitmapData onto which we'll draw the word being entered
    bmd = game.make.bitmapData(800, 200);
    bmd.context.font = '64px Arial';
    bmd.context.fillStyle = '#ffffff';
    bmd.context.fillText(word, 64, 64);
    bmd.addToWorld();

    //  Capture all key presses
    game.input.keyboard.addCallbacks(this, null, null, keyPress);
}

function controls() {
	if (game.input.keyboard.isDown(Phaser.Keyboard.W)) {
		player_sprite.move("up");
	}
	else if (game.input.keyboard.isDown(Phaser.Keyboard.A)) {
		player_sprite.move("left");
	}
	else if (game.input.keyboard.isDown(Phaser.Keyboard.S)) {
		player_sprite.move("down");
	}
	else if (game.input.keyboard.isDown(Phaser.Keyboard.D)) {
		player_sprite.move("right");
	}
}

function playerSync() {
	player.x = player_sprite.x;
	player.y = player_sprite.y;
}

function renderConnectedUsers() {
	var users = remote.getGlobal("users");
	for (i in users) {
		console.log(users[i]);
		if(users[i].name != player_sprite.name) {
			if(user_sprites[users[i].name] == undefined) {
				console.log("Creating: \n" +
					"\tuser_sprites[" + users[i].name + "] = new Sprite(\"player_sprite\", \"./assets/player_sprite.png\", " + users[i].x + ", " + users[i].y + ");");
				user_sprites[users[i].name] = new Sprite(player.name, "./assets/player.png", users[i].x, users[i].y);
			} else {
				console.log("Updating: \n" +
					"\tuser_sprites[" + users[i].name + "].setX(" + users[i].x + ");\n" +
					"\tuser_sprites[" + users[i].name + "].setY(" + users[i].y + ");\n"
				);
				user_sprites[users[i].name].setX(users[i].x);
				user_sprites[users[i].name].setY(users[i].y);
				user_sprites[users[i].name].updateLocation();
			}
		}
	}
}

function preload() {
	loadImages();
}

function create() {

	cursors = game.input.keyboard.createCursorKeys();

	console.log("test");

	while(true) {
		synced = remote.getGlobal("synced");
		console.log(synced);
		if (synced) {
			level = remote.getGlobal("world");
			buildWorld()
			player_sprite = new Sprite(player.name, "./assets/player.png", 2, 2);
			playerSync();
			break;
		}
	}

	//chat = new Chat();
	//loadBitmapData();
	//game.camera.follow(player_sprite);
	//console.log(remote);

}

function update() {
	controls();
	playerSync();
}

function render() {
	renderConnectedUsers();
	//game.debug.geom(chat.background);
}
<commit_msg>Fix grid alignment<commit_after>const remote = require('electron').remote;
const app = remote.app;

var users = remote.getGlobal("users");
var user_sprites = {}
var player = remote.getGlobal("player");
var level = remote.getGlobal("world");
var synced = remote.getGlobal("synced");

var word = "phaser";
var correct = [];
var bmd;
var chat;

console.log("game.js is running.");

var ASPECT_RATIO = 16/9;
var GAME_ASPECT_RATIO = 13.5/9;
var CHAT_ASPECT_RATIO = ASPECT_RATIO - GAME_ASPECT_RATIO; // 2.5/9

var TILE_SIZE = 16;
var ZOOM_FACTOR = 5;
//console.log($(window).width());

var WINDOW_WIDTH = $(window).width();
var WINDOW_HEIGHT = WINDOW_WIDTH / ASPECT_RATIO;
var GAME_WIDTH = WINDOW_WIDTH / ASPECT_RATIO * GAME_ASPECT_RATIO;
var CHAT_WIDTH = WINDOW_WIDTH - GAME_WIDTH;

var ROTATIONS = ["left", "right", "up", "down"];
var player_sprite;

var game = new Phaser.Game(WINDOW_WIDTH, WINDOW_HEIGHT, Phaser.AUTO, 'content', {
  preload: preload,
  create: create,
  update: update,
  render: render
});

function coord_to_pixels(c) {
	return c * ZOOM_FACTOR * TILE_SIZE + (ZOOM_FACTOR*TILE_SIZE)/2;
}

function Sprite(name, url, x, y) {
	this.move = function(direction) {
		if((this.moveTime + this.moveThreshold) < game.time.now) {
			if(ROTATIONS[this.rotation] != direction) {
				var direction_int = ROTATIONS.indexOf(direction);
				this.rotation = direction_int >= 0 ? direction_int : this.rotation;
				this.moveTime = game.time.now;
			}
			else {
				var x_par = 0;
				var y_par = 0;
				if(direction == "left") {
					x_par = -1;
				} else if (direction == "right") {
					x_par = 1;
				} else if (direction == "up") {
					y_par = -1;
				} else if (direction == "down") {
					y_par = 1;
				} else {
					return;
				}
				if(!(tiles[this.y + y_par][this.x + x_par].collideable)){
					this.x += x_par;
					this.y += y_par;
					this.moveTime = game.time.now;
				}
				else {
					//COLLIDE
				}
			}
			this.updateLocation();
		}
	}
	this.updateLocation = function() {
		this.sprite.x = this.getX(); // ADD LERP
		this.sprite.y = this.getY(); // ADD LERP
		//console.log(this.sprite.scale.x);
		//this.sprite.scale.x = Math.abs(this.sprite.scale.x) - (this.rotation % 2) * 2 * Math.abs(this.sprite.scale.x);
		if(ROTATIONS[this.rotation] == "up") {
			this.sprite.angle = 90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(ROTATIONS[this.rotation] == "down"){
			this.sprite.angle = -90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(ROTATIONS[this.rotation] == "left") {
			this.sprite.angle = 0;
			this.sprite.scale.x = -Math.abs(this.sprite.scale.x);
		} else if(ROTATIONS[this.rotation] == "right") {
			this.sprite.angle = 0;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		}
	}
	this.getX = function() {
		return this.x * ZOOM_FACTOR * TILE_SIZE + (TILE_SIZE*ZOOM_FACTOR)/2;
	}
	this.getY = function() {
		return this.y * ZOOM_FACTOR * TILE_SIZE + (TILE_SIZE*ZOOM_FACTOR)/2;
	}
	this.setX = function(x) {
		this.x = x; // ADD LERP
	}
	this.setY = function(y) {
		this.y = y; // ADD LERP
	}
	this.setRotation = function(rotation) {
		if(rotation == "up") {
			this.sprite.angle = 90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(rotation == "down"){
			this.sprite.angle = -90;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		} else if(rotation == "left") {
			this.sprite.angle = 0;
			this.sprite.scale.x = -Math.abs(this.sprite.scale.x);
		} else if(rotation == "right") {
			this.sprite.angle = 0;
			this.sprite.scale.x = Math.abs(this.sprite.scale.x);
		}
	}

	this.name = name;
	this.url = url;
	this.x = x;
	this.y = y;
	this.sprite = game.add.sprite(this.getX(), this.getY(), this.name);
	this.sprite.width = TILE_SIZE * ZOOM_FACTOR;
	this.sprite.height = TILE_SIZE * ZOOM_FACTOR;
	this.sprite.anchor.setTo(0.5, 0.5);
	this.moveTime = 0;
	this.moveThreshold = 150;
	this.rotation = 0;
}

function Tile(val, x, y) {
  this.url = tileset[val].url;
  this.x = x;
  this.y = y;
  this.collideable = tileset[val].collideable;
  var sprite = game.add.sprite(coord_to_pixels(x), coord_to_pixels(y), tileset[val].name);
  sprite.anchor.setTo(0.5, 0.5);
  sprite.width = ZOOM_FACTOR * TILE_SIZE;
  sprite.height = ZOOM_FACTOR * TILE_SIZE;
}

function World() {

}

function Chat() {
	this.width = CHAT_WIDTH;
	this.height = WINDOW_HEIGHT;
	var background = new Phaser.Rectangle(GAME_WIDTH, 0, CHAT_WIDTH, WINDOW_HEIGHT);
}

var tileset = [
	{
		name: "wall",
		url: "./assets/wall.png",
		collideable: true
	},
	{
		name: "floor",
		url: "./assets/floor.png",
		collideable: false
	}
];

var tiles = []

function loadImages() {
	for (i in tileset) {
		game.load.image(tileset[i].name, tileset[i].url);
	}
	game.load.image(tileset[i].name, tileset[i].url);
	game.load.spritesheet(player.name, "./assets/player.png", 32, 48);
}

function buildWorld() {
	//game.world.setBounds(0, 0, 1280, 600);
	var x, y;
	y = 0;
	for(i in level) {
		x = 0;
		var temp = [];
		for (j in level[i]) {
			console.log(level[i][j]);
			temp.push(new Tile(level[i][j], x, y));
			x++;
		}
		tiles.push(temp);
		y++;

	}
}

function keyPress(char) {
    //  Clear the BMD
    bmd.cls();
    //  Set the x value we'll start drawing the text from
    var x = 64;
	//  Now draw the word, letter by letter, changing colour as required
	bmd.context.fillStyle = '#00ff00';
	bmd.context.fillText(char, x, 64);
	console.log(char);
	x += bmd.context.measureText(char).width;
}

function loadBitmapData() {
	//  This is our BitmapData onto which we'll draw the word being entered
    bmd = game.make.bitmapData(800, 200);
    bmd.context.font = '64px Arial';
    bmd.context.fillStyle = '#ffffff';
    bmd.context.fillText(word, 64, 64);
    bmd.addToWorld();

    //  Capture all key presses
    game.input.keyboard.addCallbacks(this, null, null, keyPress);
}

function controls() {
	if (game.input.keyboard.isDown(Phaser.Keyboard.W)) {
		player_sprite.move("up");
	}
	else if (game.input.keyboard.isDown(Phaser.Keyboard.A)) {
		player_sprite.move("left");
	}
	else if (game.input.keyboard.isDown(Phaser.Keyboard.S)) {
		player_sprite.move("down");
	}
	else if (game.input.keyboard.isDown(Phaser.Keyboard.D)) {
		player_sprite.move("right");
	}
}

function playerSync() {
	player.x = player_sprite.x;
	player.y = player_sprite.y;
}

function renderConnectedUsers() {
	var users = remote.getGlobal("users");
	for (i in users) {
		console.log(users[i]);
		if(users[i].name != player_sprite.name) {
			if(user_sprites[users[i].name] == undefined) {
				console.log("Creating: \n" +
					"\tuser_sprites[" + users[i].name + "] = new Sprite(\"player_sprite\", \"./assets/player_sprite.png\", " + users[i].x + ", " + users[i].y + ");");
				user_sprites[users[i].name] = new Sprite(player.name, "./assets/player.png", users[i].x, users[i].y);
			} else {
				console.log("Updating: \n" +
					"\tuser_sprites[" + users[i].name + "].setX(" + users[i].x + ");\n" +
					"\tuser_sprites[" + users[i].name + "].setY(" + users[i].y + ");\n"
				);
				user_sprites[users[i].name].setX(users[i].x);
				user_sprites[users[i].name].setY(users[i].y);
				user_sprites[users[i].name].updateLocation();
			}
		}
	}
}

function preload() {
	loadImages();
}

function create() {

	cursors = game.input.keyboard.createCursorKeys();

	console.log("test");

	while(true) {
		synced = remote.getGlobal("synced");
		console.log(synced);
		if (synced) {
			level = remote.getGlobal("world");
			buildWorld()
			player_sprite = new Sprite(player.name, "./assets/player.png", 2, 2);
			playerSync();
			break;
		}
	}

	//chat = new Chat();
	//loadBitmapData();
	//game.camera.follow(player_sprite);
	//console.log(remote);

}

function update() {
	controls();
	playerSync();
}

function render() {
	renderConnectedUsers();
	//game.debug.geom(chat.background);
}
<|endoftext|>


<commit_before>'use strict';

var globalMap = [];

function createMapSprite (id) {
  if (id === 0.1) {
    return new PIXI.Sprite(PIXI.loader.resources['img/terrain.json'].textures['wall.png']);
  } else if (id === 0.2) {
    return new PIXI.Sprite(PIXI.loader.resources['img/green_terrain.json'].textures['greentree.png']);
  } else if (id === 0.3) {
    return new PIXI.Sprite(PIXI.loader.resources['img/green_terrain.json'].textures['stump1.png']);
  } else if (id === 0.4) {
    return new PIXI.Sprite(PIXI.loader.resources['img/green_terrain.json'].textures['stump2.png']);
  } else if (id === 1.1) {
    return new PIXI.Sprite(PIXI.loader.resources['img/terrain.json'].textures['ground.png']);
  } else if (id === 1.2) {
    return new PIXI.Sprite(PIXI.loader.resources['img/green_terrain.json'].textures['grass.png']);
  } else if (id === 2.1) {
    return new PIXI.Sprite(PIXI.loader.resources['img/terrain.json'].textures['entrance.png']);
  } else if (id === 2.2) {
    return new PIXI.Sprite(PIXI.loader.resources['img/terrain.json'].textures['exit1.png']);
  }
}

function drawMap(labMap, mapContainer, spriteConf) {
  globalMap = [];

  const spriteFactory = new SpriteFactory(spriteConf);

  for (let i = 0; i < labMap.length; i++) {
    globalMap.push([]);

    let mapRow = labMap[i];

    for (let ii = 0; ii < mapRow.length; ii++) {
      var mapSprite = spriteFactory.getSprite(mapRow[ii]);

      if (mapSprite) {
        mapSprite.x = 32 * ii;
        mapSprite.y = 32 * i;

        mapContainer.addChild(mapSprite);

        globalMap[i].push(mapSprite);
      }
    }
  }
}

function changeMap(changeMap, mapContainer) {
  changeMap.forEach(function (item) {
    for (let i = 0; i < item.length; i++) {
      let mapSprite = createEmptySourceMap(item.id);

      let y = item.startY;
      let x = item.startX;

      if (item.type === 'vertical') {
        y += i;
      } else {
        x += i;
      }

      let oldMapSprite = globalMap[y][x];

      mapSprite.x = oldMapSprite.x;
      mapSprite.y = oldMapSprite.y;

      mapContainer.removeChild(oldMapSprite);
      mapContainer.addChild(mapSprite);

      globalMap[y][x] = mapSprite;

    }
  });
}

function setMapAroundPlayer(mapContainer, y, x) {
  mapContainer.y = $(document).height() / 2;
  mapContainer.x = $(document).width() / 2;
}

function moveMapAroundPlayer(mapContainer, direction) {
  if (direction === 'up') {
    mapContainer.y += 32;
  }

  if (direction === 'down') {
    mapContainer.y -= 32;
  }

  if (direction === 'left') {
    mapContainer.x += 32;
  }

  if (direction === 'right') {
    mapContainer.x -= 32;
  }
}
<commit_msg>remode old function<commit_after>'use strict';

var globalMap = [];

function drawMap(labMap, mapContainer, spriteConf) {
  globalMap = [];

  const spriteFactory = new SpriteFactory(spriteConf);

  for (let i = 0; i < labMap.length; i++) {
    globalMap.push([]);

    let mapRow = labMap[i];

    for (let ii = 0; ii < mapRow.length; ii++) {
      var mapSprite = spriteFactory.getSprite(mapRow[ii]);

      if (mapSprite) {
        mapSprite.x = 32 * ii;
        mapSprite.y = 32 * i;

        mapContainer.addChild(mapSprite);

        globalMap[i].push(mapSprite);
      }
    }
  }
}

function changeMap(changeMap, mapContainer) {
  changeMap.forEach(function (item) {
    for (let i = 0; i < item.length; i++) {
      let mapSprite = createEmptySourceMap(item.id);

      let y = item.startY;
      let x = item.startX;

      if (item.type === 'vertical') {
        y += i;
      } else {
        x += i;
      }

      let oldMapSprite = globalMap[y][x];

      mapSprite.x = oldMapSprite.x;
      mapSprite.y = oldMapSprite.y;

      mapContainer.removeChild(oldMapSprite);
      mapContainer.addChild(mapSprite);

      globalMap[y][x] = mapSprite;

    }
  });
}

function setMapAroundPlayer(mapContainer, y, x) {
  mapContainer.y = $(document).height() / 2;
  mapContainer.x = $(document).width() / 2;
}

function moveMapAroundPlayer(mapContainer, direction) {
  if (direction === 'up') {
    mapContainer.y += 32;
  }

  if (direction === 'down') {
    mapContainer.y -= 32;
  }

  if (direction === 'left') {
    mapContainer.x += 32;
  }

  if (direction === 'right') {
    mapContainer.x -= 32;
  }
}
<|endoftext|>


<commit_before>import { LitElement, html, css } from 'lit-element'
import { repeat } from 'lit-html/directives/repeat'

import createIdenticon from './identicon'
import localeTime from './locale-time'
import theme from './theme'
import { videoToGif } from './gif'

const MESSAGE_LIMIT = 30

class MessageElement extends LitElement {
  static get styles() {
    return css`
      :host {
        display: flex;
        background-color: var(--colorSurface);
        font-size: 20px;
        padding: 0px;
      }

      .video-container {
        width: 200px;
        height: 150px;
        position: relative;
        overflow: hidden;
        flex-shrink: 0;

        margin-bottom: -1px;
      }

      .video-container.first {
        border-top-left-radius: 2px;
      }

      .video-container.last {
        border-bottom-left-radius: 2px;
        margin-bottom: 0;
      }

      .video-container .message-video {
        width: 100%;
        height: 100%;
        display: block;
      }

      .video-container .save,
      .video-container .save:focus {
        position: absolute;
        display: block;
        padding: 4px 8px;
        bottom: 8px;
        left: 8px;
        border: 1px solid rgba(0, 0, 0, 0.54);
        outline: none;
        border-radius: 2px;
        background-color: #f06292;
        opacity: 0;
        visibility: hidden;

        transition: visibility 0.4s, opacity 0.4s, background-color 0.4s;
        transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
      }

      .video-container:hover .save {
        visibility: visible;
        opacity: 0.95;
      }

      .save:hover {
        background-color: #f86a9a;
        cursor: pointer;
      }

      .save:active {
        background-color: #ff71a1;
      }

      .save[disabled] {
        background-color: #e91e63;
      }

      .message-text {
        flex: 1 1;
        margin: 0;
        padding: 8px;

        word-wrap: break-word;
        overflow-wrap: break-word;
        overflow: hidden;
      }

      .message-meta {
        flex-shrink: 0;
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        justify-content: space-between;
        padding: 0 0 4px;
      }

      .message-overflow {
        display: inline-block;
      }

      .message-meta sc-dropdown .toggle {
        /* compensate for the icon being higher and not looking like it occupies the lower space */
        --colorIconPrimary: var(--colorTextSecondary);
        --colorButtonHover: transparent;
        --colorButtonActive: transparent;
      }

      .message-meta sc-dropdown .toggle:hover {
        --colorIconPrimary: var(--colorTextPrimary);
      }

      .message-overflow sc-svg-icon {
        margin-left: 8px;
        margin-top: -8px;
      }

      .message-meta sc-dropdown {
        margin-bottom: -24px;
      }

      .identicon {
        width: 38px;
        height: 38px;
        border: var(--colorBorder);
        border-radius: 2px;
        margin: 1px 8px 1px 2px;
        padding: 3px;
      }

      .identicon .block {
        float: left;
        width: 20%;
        height: 20%;
      }

      .message-meta time {
        color: var(colorTextSecondary);
        font-size: 16px;
        padding: 0;
        margin-right: 8px;
      }
    `
  }

  static get properties() {
    return {
      isFirst: { type: Boolean, attribute: 'is-first' },
      isLast: { type: Boolean, attribute: 'is-last' },
      key: { type: String },
      owner: { attribute: false },
      myId: { type: String, attribute: 'my-id' },
      sent: { type: Number },
      text: { type: String },
      userId: { type: String, attribute: 'user-id' },
      video: { attribute: false },
      videoMime: { type: String },
    }
  }

  constructor() {
    super()
    this.isFirst = false
    this.isLast = false
    this.key = ''
    this.owner = null
    this.sent = Date.now()
    this.text = ''
    this.userId = ''
    this.video = null
    this.videoMime = ''
  }

  _isVisible = false
  _playPauseRequest = null
  _srcUrlIsFor = null
  _srcUrl = null

  render() {
    if (this._srcUrl && this._srcUrlIsFor !== this.video) {
      window.URL.revokeObjectURL(this._srcUrl)
      this._srcUrl = null
    }
    if (!this._srcUrl) {
      const blob = new window.Blob([this.video], { type: this.videoMime })
      this._srcUrl = window.URL.createObjectURL(blob)
      this._srcUrlIsFor = this.video
    }

    const sentDate = new Date(this.sent)
    const isMe = this.userId === this.myId

    const videoClass =
      'video-container' + (this.isFirst ? ' first' : '') + (this.isLast ? ' last' : '')

    const dropdownActions = {
      mute: () => this.mute(),
    }

    return html`

          <video class="message-video" muted loop src="${this._srcUrl}"></video>
          <button class="save shadow-1" title="Save as GIF" @click="${this.saveGif}">
            <sc-svg-icon class="invert" icon="save"></ms-svg-icon>
          </button>

          <sc-dropdown .actions="${dropdownActions}">
            <button slot="toggle" class="toggle message-overflow"
                title="Message options"
                ?disabled="${isMe}">
              <sc-svg-icon ?disabled="${isMe}" icon="moreVert"></ms-svg-icon>
            </button>
            <button data-action="mute">Mute user</button>
          </sc-dropdown>

          <time datetime="${sentDate.toISOString()}">${localeTime(sentDate)}</time>

    `
  }

  updated() {
    // TODO: make these LitElements too
    const newIdenticon = createIdenticon(this.userId)
    const identiconElem = this.shadowRoot.querySelector('.identicon')
    identiconElem.parentElement.replaceChild(newIdenticon, identiconElem)
  }

  disconnectedCallback() {
    this.owner.messageDisconnected(this)
    if (this._srcUrl) {
      window.URL.revokeObjectURL(this._srcUrl)
      this._srcUrl = null
      this._srcUrlIsFor = null
    }
    if (this._playPauseRequest) {
      cancelAnimationFrame(this._playPauseRequest)
      this._playPauseRequest = null
    }
  }

  saveGif() {
    this._throwIfDisposed()
    this.saveButton.disabled = true
    this.owner.trackSaveGif()

    videoToGif({ videoElem: this.video, numFrames: 10 })
      .then(gifBlob => {
        this.saveButton.disabled = false
        const url = window.URL.createObjectURL(gifBlob)
        const link = document.createElement('a')
        const click = document.createEvent('MouseEvents')

        link.href = url
        link.download = Date.now() + '.gif'
        click.initMouseEvent(
          'click',
          true,
          true,
          window,
          0,
          0,
          0,
          0,
          0,
          false,
          false,
          false,
          false,
          0,
          null,
        )
        link.dispatchEvent(click)
        setTimeout(() => window.URL.revokeObjectURL(url), 100)
      })
      .catch(err => {
        this.saveButton.disabled = false
        // TODO(tec27): need a good way to display this error to users
        console.error('Error creating GIF:')
        console.dir(err)
        return
      })
  }

  mute() {
    this.owner.muteUser(this.userId)
  }

  updateVisibility(visible) {
    this._isVisible = visible

    if (!this._playPauseRequest) {
      this._playPauseRequest = requestAnimationFrame(() => {
        this._playPauseRequest = null
        const video = this.shadowRoot.querySelector('.message-video')
        if (this._isVisible) {
          video.play()
        } else {
          video.pause()
        }
      })
    }
  }
}

customElements.define('sc-message', MessageElement)

export class MessageListElement extends LitElement {
  static get styles() {
    return css`
      :host {
        display: block;

        margin: 56px auto 158px;
        padding: 0;

        border-radius: 2px;
      }

      sc-message {
        border-bottom: 1px solid var(--colorBorder);
      }

      sc-message:first-of-type {
        border-top-left-radius: 2px;
        border-top-right-radius: 2px;
      }

      sc-message:last-of-type {
        border-bottom-left-radius: 2px;
        border-bottom-right-radius: 2px;
        border-bottom: none;
      }
    `
  }

  static get properties() {
    return {
      myId: { type: String, attribute: 'my-id' },
      muteSet: { attribute: false },
      tracker: { attribute: false },
    }
  }

  myId = ''
  muteSet = new Set()
  tracker = null

  _intersectionObserver = new IntersectionObserver(entries => {
    for (const { target, isIntersecting } of entries) {
      target.updateVisibility(isIntersecting)
    }
  })
  _messages = []

  _isAutoScrolling = false

  render() {
    window.IOBS = this._intersectionObserver

    return html`

        ${repeat(
          this._messages,
          m => m.key,
          (m, index) =>
            html`
              <sc-message
                key="${m.key}"
                .owner="${this}"
                my-id="${this.myId}"
                sent="${m.sent}"
                text="${m.text}"
                user-id="${m.userId}"
                .video="${m.video}"
                videoMime="${m.videoMime}"
                ?is-first="${index === 0}"
                ?is-last="${index === this._messages.length - 1}"
              ></sc-message>
            `,
        )}

    `
  }

  updated() {
    for (const message of this.shadowRoot.querySelectorAll('sc-message')) {
      this._intersectionObserver.observe(message)
    }

    if (this._isAutoScrolling && this._messages.length) {
      requestAnimationFrame(() => {
        if (!this._messages.length) {
          return
        }

        const lastMessage = this._messages[this._messages.length - 1]
        this.shadowRoot.querySelector(`sc-message[key="${lastMessage.key}"]`).scrollIntoView()
      })
      this._isAutoScrolling = false
    }
  }

  hasMessages() {
    return this._messages.length > 0
  }

  addMessage(message, autoScrolling = true) {
    if (this.muteSet.has(message.userId)) {
      return false
    }
    if (this._messages.some(m => m.key === message.key)) {
      return false
    }

    this._isAutoScrolling = autoScrolling

    const newCount = this._messages.length + 1
    if (autoScrolling && newCount > MESSAGE_LIMIT) {
      this._messages = this._messages.slice(-MESSAGE_LIMIT)
    }

    this._messages.push(message)
    this.requestUpdate()
    return true
  }

  messageDisconnected(message) {
    this._intersectionObserver.unobserve(message)
  }

  muteUser(userId) {
    if (userId === this.clientId) {
      // don't mute me, me
      return
    }
    this.muteSet.add(userId)
    this.tracker.onUserMuted()

    this._messages = this._messages.filter(m => m.userId !== userId)
    this.requestUpdate()
  }

  trackSaveGif() {
    this.tracker.onSaveGif()
  }

  _onThemeChange(newTheme) {
    // TODO: fix this for LitElement
    /*
    // Re-render identicons based on the new theme to update any inline styles
    for (const message of this.messages) {
      message.refreshIdenticon()
    }
    */
  }
}

customElements.define('sc-message-list', MessageListElement)
<commit_msg>Fix gif saving with LitElement changes.<commit_after>import { LitElement, html, css } from 'lit-element'
import { repeat } from 'lit-html/directives/repeat'

import createIdenticon from './identicon'
import localeTime from './locale-time'
import theme from './theme'
import { videoToGif } from './gif'

const MESSAGE_LIMIT = 30

class MessageElement extends LitElement {
  static get styles() {
    return css`
      :host {
        display: flex;
        background-color: var(--colorSurface);
        font-size: 20px;
        padding: 0px;
      }

      .video-container {
        width: 200px;
        height: 150px;
        position: relative;
        overflow: hidden;
        flex-shrink: 0;

        margin-bottom: -1px;
      }

      .video-container.first {
        border-top-left-radius: 2px;
      }

      .video-container.last {
        border-bottom-left-radius: 2px;
        margin-bottom: 0;
      }

      .video-container .message-video {
        width: 100%;
        height: 100%;
        display: block;
      }

      .video-container .save,
      .video-container .save:focus {
        position: absolute;
        display: block;
        padding: 4px 8px;
        bottom: 8px;
        left: 8px;
        border: 1px solid rgba(0, 0, 0, 0.54);
        outline: none;
        border-radius: 2px;
        background-color: #f06292;
        opacity: 0;
        visibility: hidden;

        transition: visibility 0.4s, opacity 0.4s, background-color 0.4s;
        transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
      }

      .video-container:hover .save {
        visibility: visible;
        opacity: 0.95;
      }

      .save:hover {
        background-color: #f86a9a;
        cursor: pointer;
      }

      .save:active {
        background-color: #ff71a1;
      }

      .save[disabled] {
        background-color: #e91e63;
      }

      .message-text {
        flex: 1 1;
        margin: 0;
        padding: 8px;

        word-wrap: break-word;
        overflow-wrap: break-word;
        overflow: hidden;
      }

      .message-meta {
        flex-shrink: 0;
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        justify-content: space-between;
        padding: 0 0 4px;
      }

      .message-overflow {
        display: inline-block;
      }

      .message-meta sc-dropdown .toggle {
        /* compensate for the icon being higher and not looking like it occupies the lower space */
        --colorIconPrimary: var(--colorTextSecondary);
        --colorButtonHover: transparent;
        --colorButtonActive: transparent;
      }

      .message-meta sc-dropdown .toggle:hover {
        --colorIconPrimary: var(--colorTextPrimary);
      }

      .message-overflow sc-svg-icon {
        margin-left: 8px;
        margin-top: -8px;
      }

      .message-meta sc-dropdown {
        margin-bottom: -24px;
      }

      .identicon {
        width: 38px;
        height: 38px;
        border: var(--colorBorder);
        border-radius: 2px;
        margin: 1px 8px 1px 2px;
        padding: 3px;
      }

      .identicon .block {
        float: left;
        width: 20%;
        height: 20%;
      }

      .message-meta time {
        color: var(colorTextSecondary);
        font-size: 16px;
        padding: 0;
        margin-right: 8px;
      }
    `
  }

  static get properties() {
    return {
      isFirst: { type: Boolean, attribute: 'is-first' },
      isLast: { type: Boolean, attribute: 'is-last' },
      key: { type: String },
      owner: { attribute: false },
      myId: { type: String, attribute: 'my-id' },
      sent: { type: Number },
      text: { type: String },
      userId: { type: String, attribute: 'user-id' },
      video: { attribute: false },
      videoMime: { type: String },
    }
  }

  constructor() {
    super()
    this.isFirst = false
    this.isLast = false
    this.key = ''
    this.owner = null
    this.sent = Date.now()
    this.text = ''
    this.userId = ''
    this.video = null
    this.videoMime = ''
  }

  _isVisible = false
  _playPauseRequest = null
  _srcUrlIsFor = null
  _srcUrl = null

  render() {
    if (this._srcUrl && this._srcUrlIsFor !== this.video) {
      window.URL.revokeObjectURL(this._srcUrl)
      this._srcUrl = null
    }
    if (!this._srcUrl) {
      const blob = new window.Blob([this.video], { type: this.videoMime })
      this._srcUrl = window.URL.createObjectURL(blob)
      this._srcUrlIsFor = this.video
    }

    const sentDate = new Date(this.sent)
    const isMe = this.userId === this.myId

    const videoClass =
      'video-container' + (this.isFirst ? ' first' : '') + (this.isLast ? ' last' : '')

    const dropdownActions = {
      mute: () => this.mute(),
    }

    return html`

          <video class="message-video" muted loop src="${this._srcUrl}"></video>
          <button class="save shadow-1" title="Save as GIF" @click="${this.saveGif}">
            <sc-svg-icon class="invert" icon="save"></ms-svg-icon>
          </button>

          <sc-dropdown .actions="${dropdownActions}">
            <button slot="toggle" class="toggle message-overflow"
                title="Message options"
                ?disabled="${isMe}">
              <sc-svg-icon ?disabled="${isMe}" icon="moreVert"></ms-svg-icon>
            </button>
            <button data-action="mute">Mute user</button>
          </sc-dropdown>

          <time datetime="${sentDate.toISOString()}">${localeTime(sentDate)}</time>

    `
  }

  updated() {
    // TODO: make these LitElements too
    const newIdenticon = createIdenticon(this.userId)
    const identiconElem = this.shadowRoot.querySelector('.identicon')
    identiconElem.parentElement.replaceChild(newIdenticon, identiconElem)
  }

  disconnectedCallback() {
    this.owner.messageDisconnected(this)
    if (this._srcUrl) {
      window.URL.revokeObjectURL(this._srcUrl)
      this._srcUrl = null
      this._srcUrlIsFor = null
    }
    if (this._playPauseRequest) {
      cancelAnimationFrame(this._playPauseRequest)
      this._playPauseRequest = null
    }
  }

  saveGif() {
    this.shadowRoot.querySelector('.save').disabled = true
    this.owner.trackSaveGif()

    videoToGif({ videoElem: this.shadowRoot.querySelector('.message-video'), numFrames: 10 })
      .then(gifBlob => {
        this.shadowRoot.querySelector('.save').disabled = false
        const url = window.URL.createObjectURL(gifBlob)
        const link = document.createElement('a')
        const click = document.createEvent('MouseEvents')

        link.href = url
        link.download = Date.now() + '.gif'
        click.initMouseEvent(
          'click',
          true,
          true,
          window,
          0,
          0,
          0,
          0,
          0,
          false,
          false,
          false,
          false,
          0,
          null,
        )
        link.dispatchEvent(click)
        setTimeout(() => window.URL.revokeObjectURL(url), 100)
      })
      .catch(err => {
        this.shadowRoot.querySelector('.save').disabled = false
        // TODO(tec27): need a good way to display this error to users
        console.error('Error creating GIF:')
        console.dir(err)
        return
      })
  }

  mute() {
    this.owner.muteUser(this.userId)
  }

  updateVisibility(visible) {
    this._isVisible = visible

    if (!this._playPauseRequest) {
      this._playPauseRequest = requestAnimationFrame(() => {
        this._playPauseRequest = null
        const video = this.shadowRoot.querySelector('.message-video')
        if (this._isVisible) {
          video.play()
        } else {
          video.pause()
        }
      })
    }
  }
}

customElements.define('sc-message', MessageElement)

export class MessageListElement extends LitElement {
  static get styles() {
    return css`
      :host {
        display: block;

        margin: 56px auto 158px;
        padding: 0;

        border-radius: 2px;
      }

      sc-message {
        border-bottom: 1px solid var(--colorBorder);
      }

      sc-message:first-of-type {
        border-top-left-radius: 2px;
        border-top-right-radius: 2px;
      }

      sc-message:last-of-type {
        border-bottom-left-radius: 2px;
        border-bottom-right-radius: 2px;
        border-bottom: none;
      }
    `
  }

  static get properties() {
    return {
      myId: { type: String, attribute: 'my-id' },
      muteSet: { attribute: false },
      tracker: { attribute: false },
    }
  }

  myId = ''
  muteSet = new Set()
  tracker = null

  _intersectionObserver = new IntersectionObserver(entries => {
    for (const { target, isIntersecting } of entries) {
      target.updateVisibility(isIntersecting)
    }
  })
  _messages = []

  _isAutoScrolling = false

  render() {
    window.IOBS = this._intersectionObserver

    return html`

        ${repeat(
          this._messages,
          m => m.key,
          (m, index) =>
            html`
              <sc-message
                key="${m.key}"
                .owner="${this}"
                my-id="${this.myId}"
                sent="${m.sent}"
                text="${m.text}"
                user-id="${m.userId}"
                .video="${m.video}"
                videoMime="${m.videoMime}"
                ?is-first="${index === 0}"
                ?is-last="${index === this._messages.length - 1}"
              ></sc-message>
            `,
        )}

    `
  }

  updated() {
    for (const message of this.shadowRoot.querySelectorAll('sc-message')) {
      this._intersectionObserver.observe(message)
    }

    if (this._isAutoScrolling && this._messages.length) {
      requestAnimationFrame(() => {
        if (!this._messages.length) {
          return
        }

        const lastMessage = this._messages[this._messages.length - 1]
        this.shadowRoot.querySelector(`sc-message[key="${lastMessage.key}"]`).scrollIntoView()
      })
      this._isAutoScrolling = false
    }
  }

  hasMessages() {
    return this._messages.length > 0
  }

  addMessage(message, autoScrolling = true) {
    if (this.muteSet.has(message.userId)) {
      return false
    }
    if (this._messages.some(m => m.key === message.key)) {
      return false
    }

    this._isAutoScrolling = autoScrolling

    const newCount = this._messages.length + 1
    if (autoScrolling && newCount > MESSAGE_LIMIT) {
      this._messages = this._messages.slice(-MESSAGE_LIMIT)
    }

    this._messages.push(message)
    this.requestUpdate()
    return true
  }

  messageDisconnected(message) {
    this._intersectionObserver.unobserve(message)
  }

  muteUser(userId) {
    if (userId === this.clientId) {
      // don't mute me, me
      return
    }
    this.muteSet.add(userId)
    this.tracker.onUserMuted()

    this._messages = this._messages.filter(m => m.userId !== userId)
    this.requestUpdate()
  }

  trackSaveGif() {
    this.tracker.onSaveGif()
  }

  _onThemeChange(newTheme) {
    // TODO: fix this for LitElement
    /*
    // Re-render identicons based on the new theme to update any inline styles
    for (const message of this.messages) {
      message.refreshIdenticon()
    }
    */
  }
}

customElements.define('sc-message-list', MessageListElement)
<|endoftext|>