<commit_before>/*!
 * Copyright 2015 mifort.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

angular.module('mifortTimesheet.report', ['ngRoute'])

    .config(['$routeProvider', function($routeProvider) {
        $routeProvider.when('/report', {
            templateUrl: 'report/reportView.html',
            controller: 'reportController'
        });
    }])

    .controller('reportController', ['$scope', 'reportService', 'preferences', 'uiGridConstants', 'topPanelService', '$timeout', '$location',
        function($scope, reportService, preferences, uiGridConstants, topPanelService, $timeout, $location) {
            var companyId = preferences.get('user').companyId,
                userRole = preferences.get('user').role.toLowerCase(),
                headerHeight = 38,
                maxVisiblePages = 5,
                columns = reportService.columns;

            $scope.introSteps = reportService.introSteps;

            if(userRole == 'owner' || userRole == 'manager'){
                $scope.userIsManager = true;
            }
            else{
                $scope.userIsManager = false;
            }

            $scope.getAggregatedComments = function(comments) {
                if(comments && comments.length){
                    //remove empty comments
                    var cleanComments = comments.filter(function(e) {
                        return e ? e.replace(/(\r\n|\n|\r)/gm, "") : ""
                    });

                    return cleanComments.join(", ")
                }
            };

            $scope.ranges = {
                'Today': [moment(), moment()],
                //'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
                'Last 7 days': [moment().subtract(7, 'days'), moment()],
                'Last 30 days': [moment().subtract(30, 'days'), moment()],
                'This month': [moment().startOf('month'), moment().endOf('month')]
            };

            //default settings, field: "date" value must match the dateRangePicker default value
            $scope.reportSettings = {
                companyId: companyId,
                sort: {
                    field: 'date',
                    asc: false
                },
                filters: [],
                pageSize: 10,
                page: 1
            };

            if(!$scope.userIsManager){
                $scope.reportSettings.filters.push({
                    field: "userName",
                    value: [preferences.get('user').displayName]
                });
            }

            $scope.reports = [
                {
                    title: 'Log',
                    active: true,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = [];
                        $scope.reportSettings.isCommentNeeded = false;
                    },
                    columnsOrder: ['date', 'userName', 'projectName', 'time', 'comment']
                },
                {
                    title: 'Project',
                    active: false,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = ['projectName'];
                        $scope.reportSettings.isCommentNeeded = false;
                    },
                    columnsOrder: ['projectName', 'time']
                },
                {
                    title: 'Employee',
                    active: false,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = ['userName'];
                        $scope.reportSettings.isCommentNeeded = true;
                    },
                    columnsOrder: ['userName', 'time', 'comments']
                },
                {
                    title: 'Project & Employee',
                    active: false,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = ['userName', 'projectName'];
                        $scope.reportSettings.isCommentNeeded = true;
                    },
                    columnsOrder: ['projectName', 'userName', 'time', 'comments']
                }
            ];

            $scope.changeActiveReport = function(activeIndex) {
                $scope.reportSettings.page = 1;

                $scope.reports.map(function(report) {
                    report.active = false;

                    return report;
                });

                $scope.reports[activeIndex].active = true;
                $scope.reports[activeIndex].setSettings();
                $scope.getReport();
            };

            $scope.reportColumns = ['Data', 'User', 'Project', 'Assignment', 'Time', 'Action'];
            $scope.perPage = [10, 20, 50, 100];
            $scope.totalCount = 0;
            $scope.projects = [];

            $scope.timesheetGridOptions = {
                ranges: $scope.ranges,
                paginationPageSizes: [25, 50, 75],
                paginationPageSize: 25,
                enableFiltering: true,
                enableHorizontalScrollbar: 0,
                enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
                rowHeight: 30,
                columnDefs: [],
                data: 'reportData',
                reportFilters: [],

                onRegisterApi: function(gridApi) {
                    $scope.gridApi = gridApi;
                    $scope.gridApi.core.on.sortChanged($scope, $scope.sortChanged);
                    $scope.getReport();
                }
            };

            $scope.sortChanged = function(grid, sortColumns) {
                $scope.reportSettings.page = 1;

                if(sortColumns.length === 0 || (sortColumns[0] && !sortColumns[0].sort)){
                    $scope.reportSettings.sort = {
                        field: 'date',
                        asc: false
                    };

                    $scope.getReport();
                }else{
                    switch(sortColumns[0].sort.direction){
                        case uiGridConstants.ASC:
                            $scope.reportSettings.sort = {
                                field: sortColumns[0].field,
                                asc: true
                            };
                            break;

                        case uiGridConstants.DESC:
                            $scope.reportSettings.sort = {
                                field: sortColumns[0].field,
                                asc: false
                            };
                            break;
                        default:
                            $scope.reportSettings.sort = {};
                    }

                    $scope.getReport();
                }
            };

            reportService.getFilters(companyId).success(function(data) {
                $scope.timesheetGridOptions.reportFilters = $scope.timesheetGridOptions.reportFilters.concat(data);
            });

            $scope.$watch('timesheetGridOptions.reportFilters', function(newValue, oldValue) {
                if(oldValue && newValue && newValue != oldValue){
                    //$scope.reportSettings.filters = [];
                    var dateFilter = _.where(newValue, {field: 'date'})[0],
                        usedFilters = $scope.reportSettings.filters,
                        dateFilterIndex = _.findIndex(usedFilters, {field: 'date'});

                    if(dateFilter && dateFilterIndex != -1){
                        usedFilters[dateFilterIndex] = dateFilter;
                    }
                    else if(dateFilter){
                        usedFilters.push(dateFilter)
                    }

                    newValue.forEach(function(filter) {
                        var filterToPush = {
                            field: filter.field
                        };

                        //proper names for backend
                        switch(filterToPush.field){
                            case 'projects':
                                filterToPush.field = 'projectName';
                                break;
                            case 'users':
                                filterToPush.field = 'userId';
                                break;
                        }

                        var checkedFilters = _.where(filter.value, {isChecked: true}),
                            usedFilterIndex = _.findIndex(usedFilters, {field: filterToPush.field});

                        filterToPush.value = checkedFilters.map(function(checkedFilter) {
                            return checkedFilter.name._id || checkedFilter.name;
                        });

                        if(filterToPush.value.length && usedFilterIndex == -1){
                            usedFilters.push(filterToPush);
                        }
                        else if(filterToPush.value.length && usedFilterIndex !== -1){
                            usedFilters[usedFilterIndex] = filterToPush;
                        }
                        else if(usedFilterIndex !== -1 && filterToPush.field != 'date'){
                            usedFilters.splice(usedFilterIndex, 1);
                        }
                    });

                    $scope.getReport();
                }
            }, true);

            $scope.getReport = function() {
                var dateFilterIndex = _.findIndex($scope.reportSettings.filters, function(reportFilter) {
                    return reportFilter.field == 'date';
                });

                if(dateFilterIndex >= 0){
                    reportService.getReport($scope.reportSettings).success(function(data, status, headers) {
                        var columnsOrder = $scope.reports[_.findIndex($scope.reports, {active: true})].columnsOrder;

                        $scope.reportData = data;

                        //add columns to grid
                        if(data.length){
                            $scope.timesheetGridOptions.columnDefs = [];
                            $scope.timesheetGridOptions.columnDefs.length = columnsOrder.length;

                            for(var column in data[0]){
                                if(columns[column]){
                                    var indexToPush = _.indexOf(columnsOrder, column);

                                    $scope.timesheetGridOptions.columnDefs[indexToPush] = columns[column];
                                }
                            }
                        }

                        $scope.gridHeight = {
                            height: ((data.length) * ($scope.timesheetGridOptions.rowHeight + 1)) + headerHeight + "px"
                        };

                        if(headers()['x-total-count']){
                            $scope.totalCount = headers()['x-total-count'];
                            $scope.totalPages = Math.ceil($scope.totalCount / $scope.reportSettings.pageSize);
                        }
                    }).finally(function() {
                        //call the directive 'cuttedComment' to reRender comments
                        $timeout(function() {
                            $scope.$broadcast('activeReportChanged');
                        });
                    });
                }
            };

            $scope.openPage = function(pageIndex) {
                $scope.reportSettings.page = pageIndex;
                $scope.getReport();
            };

            $scope.nextPage = function() {
                if($scope.reportSettings.page < $scope.totalPages){
                    $scope.reportSettings.page++;
                    $scope.getReport();
                }
            };

            $scope.prevPage = function() {
                if($scope.reportSettings.page > 1){
                    $scope.reportSettings.page--;
                    $scope.getReport();
                }
            };

            $scope.range = function(n) {
                return new Array(n);
            };

            $scope.downloadCsv = function() {
                if($scope.reportSettings.groupBy && $scope.reportSettings.groupBy.length){
                    reportService.downloadAggregationCsv($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
                else{
                    reportService.downloadCsv($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
            };

            $scope.downloadPdf = function(id) {
                if($scope.reportSettings.groupBy && $scope.reportSettings.groupBy.length){
                    reportService.downloadAggregationPdf($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
                else{
                    $scope.reportSettings.projectId = id;
                    reportService.downloadPdf($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
            };

            $scope.perPageChanged = function(perPage) {
                $scope.reportSettings.pageSize = perPage;
                $scope.reportSettings.page = 1;
                $scope.getReport();
            };

            $scope.$on('handleBroadcast', function() {
                if(topPanelService.linkName == 'csv'){
                    $scope.downloadCsv();
                } else if (topPanelService.linkName == 'pdf') {
                    $scope.downloadPdf(topPanelService.projectId);
                }
            });

            $scope.showOriginalPage = function(pageNumber) {
                if($scope.reportSettings.page + 2 >= pageNumber &&
                    $scope.reportSettings.page - 2 <= pageNumber){
                    return true;
                }
                else if(($scope.reportSettings.page < 3 && pageNumber <= maxVisiblePages) ||
                    ($scope.reportSettings.page + 1 >= $scope.totalPages && pageNumber + 4 >= $scope.totalPages)){
                    return true;
                }
            };

            $scope.showFirstPage = function() {
                if($scope.totalPages > maxVisiblePages &&
                    ($scope.reportSettings.page > 4 || $scope.reportSettings.page - 3 > 0)){
                    return true;
                }
            };

            $scope.showFirstDots = function() {
                if($scope.totalPages > maxVisiblePages &&
                    ($scope.reportSettings.page > 4)){
                    return true;
                }
            };

            $scope.showLastPage = function() {
                if($scope.totalPages > maxVisiblePages && $scope.reportSettings.page + 3 <= $scope.totalPages){
                    return true;
                }
            };

            $scope.showLastDots = function() {
                if($scope.reportSettings.page + 4 <= $scope.totalPages){
                    return true;
                }
            };

            $scope.editEmployeeTimesheet = function(userName) {
                var usersFilter = _.findWhere($scope.timesheetGridOptions.reportFilters, {field: 'users'}),
                    user = _.find(usersFilter.value, function(filterValue) {
                        return filterValue.name.displayName == userName;
                    });

                $location.path('timesheet/' + user.name._id);
            }
        }]);<commit_msg>add window reload when click Report name<commit_after>/*!
 * Copyright 2015 mifort.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

angular.module('mifortTimesheet.report', ['ngRoute'])

    .config(['$routeProvider', function($routeProvider) {
        $routeProvider.when('/report', {
            templateUrl: 'report/reportView.html',
            controller: 'reportController'
        });
    }])

    .controller('reportController', ['$scope', 'reportService', 'preferences', 'uiGridConstants', 'topPanelService', '$timeout', '$location',
        function($scope, reportService, preferences, uiGridConstants, topPanelService, $timeout, $location) {
            var companyId = preferences.get('user').companyId,
                userRole = preferences.get('user').role.toLowerCase(),
                headerHeight = 38,
                maxVisiblePages = 5,
                columns = reportService.columns;

            $scope.introSteps = reportService.introSteps;

            if(userRole == 'owner' || userRole == 'manager'){
                $scope.userIsManager = true;
            }
            else{
                $scope.userIsManager = false;
            }

            $scope.getAggregatedComments = function(comments) {
                if(comments && comments.length){
                    //remove empty comments
                    var cleanComments = comments.filter(function(e) {
                        return e ? e.replace(/(\r\n|\n|\r)/gm, "") : ""
                    });

                    return cleanComments.join(", ")
                }
            };

            $scope.ranges = {
                'Today': [moment(), moment()],
                //'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
                'Last 7 days': [moment().subtract(7, 'days'), moment()],
                'Last 30 days': [moment().subtract(30, 'days'), moment()],
                'This month': [moment().startOf('month'), moment().endOf('month')]
            };

            //default settings, field: "date" value must match the dateRangePicker default value
            $scope.reportSettings = {
                companyId: companyId,
                sort: {
                    field: 'date',
                    asc: false
                },
                filters: [],
                pageSize: 10,
                page: 1
            };

            if(!$scope.userIsManager){
                $scope.reportSettings.filters.push({
                    field: "userName",
                    value: [preferences.get('user').displayName]
                });
            }

            $scope.reports = [
                {
                    title: 'Log',
                    active: true,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = [];
                        $scope.reportSettings.isCommentNeeded = false;
                    },
                    columnsOrder: ['date', 'userName', 'projectName', 'time', 'comment']
                },
                {
                    title: 'Project',
                    active: false,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = ['projectName'];
                        $scope.reportSettings.isCommentNeeded = false;
                    },
                    columnsOrder: ['projectName', 'time']
                },
                {
                    title: 'Employee',
                    active: false,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = ['userName'];
                        $scope.reportSettings.isCommentNeeded = true;
                    },
                    columnsOrder: ['userName', 'time', 'comments']
                },
                {
                    title: 'Project & Employee',
                    active: false,
                    setSettings: function() {
                        $scope.reportSettings.groupBy = ['userName', 'projectName'];
                        $scope.reportSettings.isCommentNeeded = true;
                    },
                    columnsOrder: ['projectName', 'userName', 'time', 'comments']
                }
            ];

            $scope.changeActiveReport = function(activeIndex) {
                $scope.reportSettings.page = 1;

                $scope.reports.map(function(report) {
                    report.active = false;

                    return report;
                });

                $scope.reports[activeIndex].active = true;
                $scope.reports[activeIndex].setSettings();
                $scope.getReport();
            };

            $scope.reportColumns = ['Data', 'User', 'Project', 'Assignment', 'Time', 'Action'];
            $scope.perPage = [10, 20, 50, 100];
            $scope.totalCount = 0;
            $scope.projects = [];

            $scope.timesheetGridOptions = {
                ranges: $scope.ranges,
                paginationPageSizes: [25, 50, 75],
                paginationPageSize: 25,
                enableFiltering: true,
                enableHorizontalScrollbar: 0,
                enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
                rowHeight: 30,
                columnDefs: [],
                data: 'reportData',
                reportFilters: [],

                onRegisterApi: function(gridApi) {
                    $scope.gridApi = gridApi;
                    $scope.gridApi.core.on.sortChanged($scope, $scope.sortChanged);
                    $scope.getReport();
                }
            };

            $scope.sortChanged = function(grid, sortColumns) {
                $scope.reportSettings.page = 1;

                if(sortColumns.length === 0 || (sortColumns[0] && !sortColumns[0].sort)){
                    $scope.reportSettings.sort = {
                        field: 'date',
                        asc: false
                    };

                    $scope.getReport();
                }else{
                    switch(sortColumns[0].sort.direction){
                        case uiGridConstants.ASC:
                            $scope.reportSettings.sort = {
                                field: sortColumns[0].field,
                                asc: true
                            };
                            break;

                        case uiGridConstants.DESC:
                            $scope.reportSettings.sort = {
                                field: sortColumns[0].field,
                                asc: false
                            };
                            break;
                        default:
                            $scope.reportSettings.sort = {};
                    }

                    $scope.getReport();
                }
            };

            reportService.getFilters(companyId).success(function(data) {
                $scope.timesheetGridOptions.reportFilters = $scope.timesheetGridOptions.reportFilters.concat(data);
            });

            $scope.$watch('timesheetGridOptions.reportFilters', function(newValue, oldValue) {
                if(oldValue && newValue && newValue != oldValue){
                    //$scope.reportSettings.filters = [];
                    var dateFilter = _.where(newValue, {field: 'date'})[0],
                        usedFilters = $scope.reportSettings.filters,
                        dateFilterIndex = _.findIndex(usedFilters, {field: 'date'});

                    if(dateFilter && dateFilterIndex != -1){
                        usedFilters[dateFilterIndex] = dateFilter;
                    }
                    else if(dateFilter){
                        usedFilters.push(dateFilter)
                    }

                    newValue.forEach(function(filter) {
                        var filterToPush = {
                            field: filter.field
                        };

                        //proper names for backend
                        switch(filterToPush.field){
                            case 'projects':
                                filterToPush.field = 'projectName';
                                break;
                            case 'users':
                                filterToPush.field = 'userId';
                                break;
                        }

                        var checkedFilters = _.where(filter.value, {isChecked: true}),
                            usedFilterIndex = _.findIndex(usedFilters, {field: filterToPush.field});

                        filterToPush.value = checkedFilters.map(function(checkedFilter) {
                            return checkedFilter.name._id || checkedFilter.name;
                        });

                        if(filterToPush.value.length && usedFilterIndex == -1){
                            usedFilters.push(filterToPush);
                        }
                        else if(filterToPush.value.length && usedFilterIndex !== -1){
                            usedFilters[usedFilterIndex] = filterToPush;
                        }
                        else if(usedFilterIndex !== -1 && filterToPush.field != 'date'){
                            usedFilters.splice(usedFilterIndex, 1);
                        }
                    });

                    $scope.getReport();
                }
            }, true);

            $scope.getReport = function() {
                var dateFilterIndex = _.findIndex($scope.reportSettings.filters, function(reportFilter) {
                    return reportFilter.field == 'date';
                });

                if(dateFilterIndex >= 0){
                    reportService.getReport($scope.reportSettings).success(function(data, status, headers) {
                        var columnsOrder = $scope.reports[_.findIndex($scope.reports, {active: true})].columnsOrder;

                        $scope.reportData = data;

                        //add columns to grid
                        if(data.length){
                            $scope.timesheetGridOptions.columnDefs = [];
                            $scope.timesheetGridOptions.columnDefs.length = columnsOrder.length;

                            for(var column in data[0]){
                                if(columns[column]){
                                    var indexToPush = _.indexOf(columnsOrder, column);

                                    $scope.timesheetGridOptions.columnDefs[indexToPush] = columns[column];
                                }
                            }
                        }

                        $scope.gridHeight = {
                            height: ((data.length) * ($scope.timesheetGridOptions.rowHeight + 1)) + headerHeight + "px"
                        };

                        if(headers()['x-total-count']){
                            $scope.totalCount = headers()['x-total-count'];
                            $scope.totalPages = Math.ceil($scope.totalCount / $scope.reportSettings.pageSize);
                        }
                    }).finally(function() {
                        //call the directive 'cuttedComment' to reRender comments
                        $timeout(function() {
                            $scope.$broadcast('activeReportChanged');
                        });
                    });
                }
            };

            $scope.openPage = function(pageIndex) {
                $scope.reportSettings.page = pageIndex;
                $scope.getReport();
            };

            $scope.nextPage = function() {
                if($scope.reportSettings.page < $scope.totalPages){
                    $scope.reportSettings.page++;
                    $scope.getReport();
                }
            };

            $scope.prevPage = function() {
                if($scope.reportSettings.page > 1){
                    $scope.reportSettings.page--;
                    $scope.getReport();
                }
            };

            $scope.range = function(n) {
                return new Array(n);
            };

            $scope.downloadCsv = function() {
                if($scope.reportSettings.groupBy && $scope.reportSettings.groupBy.length){
                    reportService.downloadAggregationCsv($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
                else{
                    reportService.downloadCsv($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
            };

            $scope.downloadPdf = function(id) {
                if($scope.reportSettings.groupBy && $scope.reportSettings.groupBy.length){
                    reportService.downloadAggregationPdf($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
                else{
                    $scope.reportSettings.projectId = id;
                    reportService.downloadPdf($scope.reportSettings).success(function(data) {
                        window.location = data.url;
                    });
                }
            };

            $scope.perPageChanged = function(perPage) {
                $scope.reportSettings.pageSize = perPage;
                $scope.reportSettings.page = 1;
                $scope.getReport();
            };

            $scope.$on('handleBroadcast', function() {
                if(topPanelService.linkName == 'csv'){
                    $scope.downloadCsv();
                } else if (topPanelService.linkName == 'pdf') {
                    $scope.downloadPdf(topPanelService.projectId);
                }
            });

            $scope.showOriginalPage = function(pageNumber) {
                if($scope.reportSettings.page + 2 >= pageNumber &&
                    $scope.reportSettings.page - 2 <= pageNumber){
                    return true;
                }
                else if(($scope.reportSettings.page < 3 && pageNumber <= maxVisiblePages) ||
                    ($scope.reportSettings.page + 1 >= $scope.totalPages && pageNumber + 4 >= $scope.totalPages)){
                    return true;
                }
            };

            $scope.showFirstPage = function() {
                if($scope.totalPages > maxVisiblePages &&
                    ($scope.reportSettings.page > 4 || $scope.reportSettings.page - 3 > 0)){
                    return true;
                }
            };

            $scope.showFirstDots = function() {
                if($scope.totalPages > maxVisiblePages &&
                    ($scope.reportSettings.page > 4)){
                    return true;
                }
            };

            $scope.showLastPage = function() {
                if($scope.totalPages > maxVisiblePages && $scope.reportSettings.page + 3 <= $scope.totalPages){
                    return true;
                }
            };

            $scope.showLastDots = function() {
                if($scope.reportSettings.page + 4 <= $scope.totalPages){
                    return true;
                }
            };

            $scope.editEmployeeTimesheet = function(userName) {
                var usersFilter = _.findWhere($scope.timesheetGridOptions.reportFilters, {field: 'users'}),
                    user = _.find(usersFilter.value, function(filterValue) {
                        return filterValue.name.displayName == userName;
                    });

                $location.path('timesheet/' + user.name._id);
                window.location.reload();
            }
        }]);<|endoftext|>


<commit_before>import async from 'async';
import Logdown from 'logdown';
import request from 'superagent';
import last from 'lodash.last';
import takeRight from 'lodash.takeright';
import PromiseMaker from './PromiseMaker';
import {expandResponse} from './Utilities';
import {AvailableTransports} from './transports';
import {CLIENT_EVENTS, CLIENT_STATES} from './Constants';
import ConnectingMessageBuffer from './ConnectingMessageBuffer';

export const CONNECTION_CONFIG_DEFAULTS = {
  logger: new Logdown({prefix: 'SignalR Connection'}),
  KeepAliveTimeout: 0
};

export default class Connection {
  constructor(client, config) {
    config = Object.assign({}, CONNECTION_CONFIG_DEFAULTS, config);
    this._client = client;
    this._url = config.Url;
    this._logger = config.logger;
    this._connectionToken = config.ConnectionToken;
    this._connectionId = config.ConnectionId;
    this._keepAliveData = {
      activated: !!config.KeepAliveTimeout,
      timeout: config.KeepAliveTimeout * 1000,
      timeoutWarning: (config.KeepAliveTimeout * 1000) * (2 / 3)
    };
    this._disconnectTimeout = config.DisconnectTimeout * 1000;
    this._connectionTimeout = config.ConnectionTimeout;
    this._tryWebSockets = config.TryWebSockets;
    this._protocolVersion = config.ProtocolVersion;
    this._transportConnectTimeout = config.TransportConnectTimeout;
    this._longPollDelay = config.LongPollDelay;
    this._pollTimeout = config.ConnectionTimeout * 1000 + 10000;
    this._reconnectWindow = (config.KeepAliveTimeout + config.DisconnectTimeout) * 1000;
    this._connectingMessageBuffer = new ConnectingMessageBuffer(client, client.emit.bind(client, CLIENT_EVENTS.onReceived));
    this._beatInterval = (this._keepAliveData.timeout - this._keepAliveData.timeoutWarning) / 3;
    this._lastActiveAt = new Date().getTime();
    this._lastMessages = [];
  }

  _supportsKeepAlive() {
    return this._keepAliveData.activated && this._client.transport.supportsKeepAlive;
  }

  _connect() {
    this._client._setState(CLIENT_STATES.connecting);

    return this._findTransport()
      .then(transport => {
        this._logger.info(`Using the *${transport.constructor.name}*.`);
        this.transport = transport;
        this._client._setState(CLIENT_STATES.connected);
        this._connectingMessageBuffer.drain();
      })
  }

  _findTransport() {
    return new Promise((resolve, reject) => {
        const availableTransports = AvailableTransports();
        if(this._client.config.transport && this._client.config.transport !== 'auto') {
          if(availableTransports[this._client.config.transport]) {
            // If the transport specified in the config is found in the available transports, use it
            resolve(new availableTransports[this._client.config.transport](this));
          } else {
            reject(new Error(`The transport specified (${this._client.config.transport}) was not found among the available transports [${availableTransports.map(x => `'${x.name}'`).join(' ')}].`))
          }
        } else {
          // Otherwise, Auto Negotiate the transport
          this._logger.info(`Negotiating the transport...`);
          async.detectSeries(availableTransports.map(x => new x(this)),
            (t, c) => t.start().then(() => c(t)).catch(() => c()),
              transport => transport ? resolve(transport) : reject('No suitable transport was found.'));
        }
      }
    );
  }

  _processMessages(compressedResponse) {
    const expandedResponse = expandResponse(compressedResponse);
    this._client.emit(CLIENT_EVENTS.onReceiving);
    this._lastMessages.push(expandedResponse);
    this._lastMessages = takeRight(this._lastMessages, 5);
    this._client.emit(CLIENT_EVENTS.onReceived, expandedResponse.messages);
  }

  _lastMessage() {
    return last(this._lastMessages);
  }
}
<commit_msg>Began implementing keepalive functionality<commit_after>import async from 'async';
import Logdown from 'logdown';
import request from 'superagent';
import last from 'lodash.last';
import takeRight from 'lodash.takeright';
import PromiseMaker from './PromiseMaker';
import {expandResponse} from './Utilities';
import {AvailableTransports} from './transports';
import {CLIENT_EVENTS, CLIENT_STATES} from './Constants';
import ConnectingMessageBuffer from './ConnectingMessageBuffer';

export const CONNECTION_CONFIG_DEFAULTS = {
  logger: new Logdown({prefix: 'SignalR Connection'}),
  KeepAliveTimeout: 0
};

export default class Connection {
  constructor(client, config) {
    config = Object.assign({}, CONNECTION_CONFIG_DEFAULTS, config);
    this._client = client;
    this._url = config.Url;
    this._logger = config.logger;
    this._connectionToken = config.ConnectionToken;
    this._connectionId = config.ConnectionId;
    this._keepAliveData = {
      activated: !!config.KeepAliveTimeout,
      timeout: config.KeepAliveTimeout * 1000,
      timeoutWarning: (config.KeepAliveTimeout * 1000) * (2 / 3)
    };
    this._disconnectTimeout = config.DisconnectTimeout * 1000;
    this._connectionTimeout = config.ConnectionTimeout;
    this._tryWebSockets = config.TryWebSockets;
    this._protocolVersion = config.ProtocolVersion;
    this._transportConnectTimeout = config.TransportConnectTimeout;
    this._longPollDelay = config.LongPollDelay;
    this._pollTimeout = config.ConnectionTimeout * 1000 + 10000;
    this._reconnectWindow = (config.KeepAliveTimeout + config.DisconnectTimeout) * 1000;
    this._connectingMessageBuffer = new ConnectingMessageBuffer(client, client.emit.bind(client, CLIENT_EVENTS.onReceived));
    this._beatInterval = (this._keepAliveData.timeout - this._keepAliveData.timeoutWarning) / 3;
    this._lastActiveAt = new Date().getTime();
    this._lastMessages = [];
  }

  _supportsKeepAlive() {
    return this._keepAliveData.activated && this._client.transport.supportsKeepAlive;
  }

  _connect() {
    this._client._setState(CLIENT_STATES.connecting);

    return this._findTransport()
      .then(transport => {
        this._logger.info(`Using the *${transport.constructor.name}*.`);
        this.transport = transport;
        this._client._setState(CLIENT_STATES.connected);
        this._connectingMessageBuffer.drain();
      })
  }

  _timestampLatestMessage()
  {
    this._lastMessageAt = new Date().getTime();
  }

  _beat(){

  }

  _checkKeepAlive(){
    let currentKeepAliveData =  this._keepAliveData, timeElapsed;

    if(this._client.state === CLIENT_STATES.connected){
      timeElapsed = new Date().getTime() - this._lastMessageAt;
      if(timeElapsed >= this._keepAliveData.timeout){
        this.info('Current keep alive has timed out. Notifying the current transport that the connection has been lost.');
        this._client.state = CLIENT_STATES.disconnected;
      }

    }
  }

  _startHeartBeat(){
    this._lastActiveAt = new Date().getTime();
    _beat();
  }

  _findTransport() {
    return new Promise((resolve, reject) => {
        const availableTransports = AvailableTransports();
        if(this._client.config.transport && this._client.config.transport !== 'auto') {
          if(availableTransports[this._client.config.transport]) {
            // If the transport specified in the config is found in the available transports, use it
            resolve(new availableTransports[this._client.config.transport](this));
          } else {
            reject(new Error(`The transport specified (${this._client.config.transport}) was not found among the available transports [${availableTransports.map(x => `'${x.name}'`).join(' ')}].`))
          }
        } else {
          // Otherwise, Auto Negotiate the transport
          this._logger.info(`Negotiating the transport...`);
          async.detectSeries(availableTransports.map(x => new x(this)),
            (t, c) => t.start().then(() => c(t)).catch(() => c()),
              transport => transport ? resolve(transport) : reject('No suitable transport was found.'));
        }
      }
    );
  }

  _processMessages(compressedResponse) {
    const expandedResponse = expandResponse(compressedResponse);
    this._client.emit(CLIENT_EVENTS.onReceiving);
    this._lastMessages.push(expandedResponse);
    this._timestampLatestMessage();
    this._lastMessages = takeRight(this._lastMessages, 5);
    this._client.emit(CLIENT_EVENTS.onReceived, expandedResponse.messages);
  }

  _lastMessage() {
    return last(this._lastMessages);
  }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Control.js
 * @requires OpenLayers/Handler/Drag.js
 * @requires OpenLayers/Handler/Feature.js
 */

/**
 * Class: OpenLayers.Control.DragFeature
 * The DragFeature control moves a feature with a drag of the mouse. Create a
 * new control with the <OpenLayers.Control.DragFeature> constructor.
 *
 * Inherits From:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, {

    /**
     * APIProperty: geometryTypes
     * {Array(String)} To restrict dragging to a limited set of geometry types,
     *     send a list of strings corresponding to the geometry class names.
     */
    geometryTypes: null,

    /**
     * APIProperty: onStart
     * {Function} Define this function if you want to know when a drag starts.
     *     The function should expect to receive two arguments: the feature
     *     that is about to be dragged and the pixel location of the mouse.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be
     *     dragged.
     * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse.
     */
    onStart: function(feature, pixel) {},

    /**
     * APIProperty: onDrag
     * {Function} Define this function if you want to know about each move of a
     *     feature. The function should expect to receive two arguments: the
     *     feature that is being dragged and the pixel location of the mouse.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged.
     * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse.
     */
    onDrag: function(feature, pixel) {},

    /**
     * APIProperty: onComplete
     * {Function} Define this function if you want to know when a feature is
     *     done dragging. The function should expect to receive two arguments:
     *     the feature that is being dragged and the pixel location of the
     *     mouse.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged.
     * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse.
     */
    onComplete: function(feature, pixel) {},

    /**
     * APIProperty: onEnter
     * {Function} Define this function if you want to know when the mouse
     *     goes over a feature and thereby makes this feature a candidate
     *     for dragging.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that is ready
     *     to be dragged.
     */
    onEnter: function(feature) {},

    /**
     * APIProperty: onLeave
     * {Function} Define this function if you want to know when the mouse
     *     goes out of the feature that was dragged.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged.
     */
    onLeave: function(feature) {},

    /**
     * APIProperty: documentDrag
     * {Boolean} If set to true, mouse dragging will continue even if the
     *     mouse cursor leaves the map viewport. Default is false.
     */
    documentDrag: false,

    /**
     * Property: layer
     * {<OpenLayers.Layer.Vector>}
     */
    layer: null,

    /**
     * Property: feature
     * {<OpenLayers.Feature.Vector>}
     */
    feature: null,

    /**
     * Property: dragCallbacks
     * {Object} The functions that are sent to the drag handler for callback.
     */
    dragCallbacks: {},

    /**
     * Property: featureCallbacks
     * {Object} The functions that are sent to the feature handler for callback.
     */
    featureCallbacks: {},

    /**
     * Property: lastPixel
     * {<OpenLayers.Pixel>}
     */
    lastPixel: null,

    /**
     * Constructor: OpenLayers.Control.DragFeature
     * Create a new control to drag features.
     *
     * Parameters:
     * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be
     *     dragged.
     * options - {Object} Optional object whose properties will be set on the
     *     control.
     */
    initialize: function(layer, options) {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.layer = layer;
        this.handlers = {
            drag: new OpenLayers.Handler.Drag(
                this, OpenLayers.Util.extend({
                    down: this.downFeature,
                    move: this.moveFeature,
                    up: this.upFeature,
                    out: this.cancel,
                    done: this.doneDragging
                }, this.dragCallbacks), {
                    documentDrag: this.documentDrag
                }
            ),
            feature: new OpenLayers.Handler.Feature(
                this, this.layer, OpenLayers.Util.extend({
                    // 'click' and 'clickout' callback are for the mobile
                    // support: no 'over' or 'out' in touch based browsers.
                    click: this.clickFeature,
                    clickout: this.clickoutFeature,
                    over: this.overFeature,
                    out: this.outFeature
                }, this.featureCallbacks),
                {geometryTypes: this.geometryTypes}
            )
        };
    },

    /**
     * Method: clickFeature
     * Called when the feature handler detects a click-in on a feature.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>}
     */
    clickFeature: function(feature) {
        if (!this.over && this.overFeature(feature)) {
            this.handlers.drag.dragstart(this.handlers.feature.evt);
            // to let the events propagate to the feature handler (click callback)
            this.handlers.drag.stopDown = false;
        }
    },

    /**
     * Method: clickoutFeature
     * Called when the feature handler detects a click-out on a feature.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>}
     */
    clickoutFeature: function(feature) {
        if (this.over) {
            this.outFeature(feature);
            this.handlers.drag.stopDown = true;
        }
    },

    /**
     * APIMethod: destroy
     * Take care of things that are not handled in superclass
     */
    destroy: function() {
        this.layer = null;
        OpenLayers.Control.prototype.destroy.apply(this, []);
    },

    /**
     * APIMethod: activate
     * Activate the control and the feature handler.
     *
     * Returns:
     * {Boolean} Successfully activated the control and feature handler.
     */
    activate: function() {
        return (this.handlers.feature.activate() &&
                OpenLayers.Control.prototype.activate.apply(this, arguments));
    },

    /**
     * APIMethod: deactivate
     * Deactivate the control and all handlers.
     *
     * Returns:
     * {Boolean} Successfully deactivated the control.
     */
    deactivate: function() {
        // the return from the handlers is unimportant in this case
        this.handlers.drag.deactivate();
        this.handlers.feature.deactivate();
        this.feature = null;
        this.dragging = false;
        this.lastPixel = null;
        OpenLayers.Element.removeClass(
            this.map.viewPortDiv, this.displayClass + "Over"
        );
        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
    },

    /**
     * Method: overFeature
     * Called when the feature handler detects a mouse-over on a feature.
     *     This activates the drag handler.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The selected feature.
     *
     * Returns:
     * {Boolean} Successfully activated the drag handler.
     */
    overFeature: function(feature) {
        var activated = false;
        if(!this.handlers.drag.dragging) {
            this.feature = feature;
            this.handlers.drag.activate();
            activated = true;
            this.over = true;
            OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over");
            this.onEnter(feature);
        } else {
            if(this.feature.id == feature.id) {
                this.over = true;
            } else {
                this.over = false;
            }
        }
        return activated;
    },

    /**
     * Method: downFeature
     * Called when the drag handler detects a mouse-down.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
     */
    downFeature: function(pixel) {
        this.lastPixel = pixel;
        this.onStart(this.feature, pixel);
    },

    /**
     * Method: moveFeature
     * Called when the drag handler detects a mouse-move.  Also calls the
     *     optional onDrag method.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
     */
    moveFeature: function(pixel) {
        var res = this.map.getResolution();
        this.feature.geometry.move(res * (pixel.x - this.lastPixel.x),
                                   res * (this.lastPixel.y - pixel.y));
        this.layer.drawFeature(this.feature);
        this.lastPixel = pixel;
        this.onDrag(this.feature, pixel);
    },

    /**
     * Method: upFeature
     * Called when the drag handler detects a mouse-up.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
     */
    upFeature: function(pixel) {
        if(!this.over) {
            this.handlers.drag.deactivate();
        }
    },

    /**
     * Method: doneDragging
     * Called when the drag handler is done dragging.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The last event pixel location.  If this event
     *     came from a mouseout, this may not be in the map viewport.
     */
    doneDragging: function(pixel) {
        this.onComplete(this.feature, pixel);
    },

    /**
     * Method: outFeature
     * Called when the feature handler detects a mouse-out on a feature.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left.
     */
    outFeature: function(feature) {
        if(!this.handlers.drag.dragging) {
            this.over = false;
            this.handlers.drag.deactivate();
            OpenLayers.Element.removeClass(
                this.map.viewPortDiv, this.displayClass + "Over"
            );
            this.onLeave(feature);
            this.feature = null;
        } else {
            if(this.feature.id == feature.id) {
                this.over = false;
            }
        }
    },

    /**
     * Method: cancel
     * Called when the drag handler detects a mouse-out (from the map viewport).
     */
    cancel: function() {
        this.handlers.drag.deactivate();
        this.over = false;
    },

    /**
     * Method: setMap
     * Set the map property for the control and all handlers.
     *
     * Parameters:
     * map - {<OpenLayers.Map>} The control's map.
     */
    setMap: function(map) {
        this.handlers.drag.setMap(map);
        this.handlers.feature.setMap(map);
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
    },

    CLASS_NAME: "OpenLayers.Control.DragFeature"
});
<commit_msg>click handling in the DragFeature control only for touch devices. p=jorix, r=me (closes #3428)<commit_after>/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Control.js
 * @requires OpenLayers/Handler/Drag.js
 * @requires OpenLayers/Handler/Feature.js
 */

/**
 * Class: OpenLayers.Control.DragFeature
 * The DragFeature control moves a feature with a drag of the mouse. Create a
 * new control with the <OpenLayers.Control.DragFeature> constructor.
 *
 * Inherits From:
 *  - <OpenLayers.Control>
 */
OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, {

    /**
     * APIProperty: geometryTypes
     * {Array(String)} To restrict dragging to a limited set of geometry types,
     *     send a list of strings corresponding to the geometry class names.
     */
    geometryTypes: null,

    /**
     * APIProperty: onStart
     * {Function} Define this function if you want to know when a drag starts.
     *     The function should expect to receive two arguments: the feature
     *     that is about to be dragged and the pixel location of the mouse.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that is about to be
     *     dragged.
     * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse.
     */
    onStart: function(feature, pixel) {},

    /**
     * APIProperty: onDrag
     * {Function} Define this function if you want to know about each move of a
     *     feature. The function should expect to receive two arguments: the
     *     feature that is being dragged and the pixel location of the mouse.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged.
     * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse.
     */
    onDrag: function(feature, pixel) {},

    /**
     * APIProperty: onComplete
     * {Function} Define this function if you want to know when a feature is
     *     done dragging. The function should expect to receive two arguments:
     *     the feature that is being dragged and the pixel location of the
     *     mouse.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged.
     * pixel - {<OpenLayers.Pixel>} The pixel location of the mouse.
     */
    onComplete: function(feature, pixel) {},

    /**
     * APIProperty: onEnter
     * {Function} Define this function if you want to know when the mouse
     *     goes over a feature and thereby makes this feature a candidate
     *     for dragging.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that is ready
     *     to be dragged.
     */
    onEnter: function(feature) {},

    /**
     * APIProperty: onLeave
     * {Function} Define this function if you want to know when the mouse
     *     goes out of the feature that was dragged.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that was dragged.
     */
    onLeave: function(feature) {},

    /**
     * APIProperty: documentDrag
     * {Boolean} If set to true, mouse dragging will continue even if the
     *     mouse cursor leaves the map viewport. Default is false.
     */
    documentDrag: false,

    /**
     * Property: layer
     * {<OpenLayers.Layer.Vector>}
     */
    layer: null,

    /**
     * Property: feature
     * {<OpenLayers.Feature.Vector>}
     */
    feature: null,

    /**
     * Property: dragCallbacks
     * {Object} The functions that are sent to the drag handler for callback.
     */
    dragCallbacks: {},

    /**
     * Property: featureCallbacks
     * {Object} The functions that are sent to the feature handler for callback.
     */
    featureCallbacks: {},

    /**
     * Property: lastPixel
     * {<OpenLayers.Pixel>}
     */
    lastPixel: null,

    /**
     * Constructor: OpenLayers.Control.DragFeature
     * Create a new control to drag features.
     *
     * Parameters:
     * layer - {<OpenLayers.Layer.Vector>} The layer containing features to be
     *     dragged.
     * options - {Object} Optional object whose properties will be set on the
     *     control.
     */
    initialize: function(layer, options) {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.layer = layer;
        this.handlers = {
            drag: new OpenLayers.Handler.Drag(
                this, OpenLayers.Util.extend({
                    down: this.downFeature,
                    move: this.moveFeature,
                    up: this.upFeature,
                    out: this.cancel,
                    done: this.doneDragging
                }, this.dragCallbacks), {
                    documentDrag: this.documentDrag
                }
            ),
            feature: new OpenLayers.Handler.Feature(
                this, this.layer, OpenLayers.Util.extend({
                    // 'click' and 'clickout' callback are for the mobile
                    // support: no 'over' or 'out' in touch based browsers.
                    click: this.clickFeature,
                    clickout: this.clickoutFeature,
                    over: this.overFeature,
                    out: this.outFeature
                }, this.featureCallbacks),
                {geometryTypes: this.geometryTypes}
            )
        };
    },

    /**
     * Method: clickFeature
     * Called when the feature handler detects a click-in on a feature.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>}
     */
    clickFeature: function(feature) {
        if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) {
            this.handlers.drag.dragstart(this.handlers.feature.evt);
            // to let the events propagate to the feature handler (click callback)
            this.handlers.drag.stopDown = false;
        }
    },

    /**
     * Method: clickoutFeature
     * Called when the feature handler detects a click-out on a feature.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>}
     */
    clickoutFeature: function(feature) {
        if (this.handlers.feature.touch && this.over) {
            this.outFeature(feature);
            this.handlers.drag.stopDown = true;
        }
    },

    /**
     * APIMethod: destroy
     * Take care of things that are not handled in superclass
     */
    destroy: function() {
        this.layer = null;
        OpenLayers.Control.prototype.destroy.apply(this, []);
    },

    /**
     * APIMethod: activate
     * Activate the control and the feature handler.
     *
     * Returns:
     * {Boolean} Successfully activated the control and feature handler.
     */
    activate: function() {
        return (this.handlers.feature.activate() &&
                OpenLayers.Control.prototype.activate.apply(this, arguments));
    },

    /**
     * APIMethod: deactivate
     * Deactivate the control and all handlers.
     *
     * Returns:
     * {Boolean} Successfully deactivated the control.
     */
    deactivate: function() {
        // the return from the handlers is unimportant in this case
        this.handlers.drag.deactivate();
        this.handlers.feature.deactivate();
        this.feature = null;
        this.dragging = false;
        this.lastPixel = null;
        OpenLayers.Element.removeClass(
            this.map.viewPortDiv, this.displayClass + "Over"
        );
        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
    },

    /**
     * Method: overFeature
     * Called when the feature handler detects a mouse-over on a feature.
     *     This activates the drag handler.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The selected feature.
     *
     * Returns:
     * {Boolean} Successfully activated the drag handler.
     */
    overFeature: function(feature) {
        var activated = false;
        if(!this.handlers.drag.dragging) {
            this.feature = feature;
            this.handlers.drag.activate();
            activated = true;
            this.over = true;
            OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over");
            this.onEnter(feature);
        } else {
            if(this.feature.id == feature.id) {
                this.over = true;
            } else {
                this.over = false;
            }
        }
        return activated;
    },

    /**
     * Method: downFeature
     * Called when the drag handler detects a mouse-down.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
     */
    downFeature: function(pixel) {
        this.lastPixel = pixel;
        this.onStart(this.feature, pixel);
    },

    /**
     * Method: moveFeature
     * Called when the drag handler detects a mouse-move.  Also calls the
     *     optional onDrag method.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
     */
    moveFeature: function(pixel) {
        var res = this.map.getResolution();
        this.feature.geometry.move(res * (pixel.x - this.lastPixel.x),
                                   res * (this.lastPixel.y - pixel.y));
        this.layer.drawFeature(this.feature);
        this.lastPixel = pixel;
        this.onDrag(this.feature, pixel);
    },

    /**
     * Method: upFeature
     * Called when the drag handler detects a mouse-up.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} Location of the mouse event.
     */
    upFeature: function(pixel) {
        if(!this.over) {
            this.handlers.drag.deactivate();
        }
    },

    /**
     * Method: doneDragging
     * Called when the drag handler is done dragging.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} The last event pixel location.  If this event
     *     came from a mouseout, this may not be in the map viewport.
     */
    doneDragging: function(pixel) {
        this.onComplete(this.feature, pixel);
    },

    /**
     * Method: outFeature
     * Called when the feature handler detects a mouse-out on a feature.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature.Vector>} The feature that the mouse left.
     */
    outFeature: function(feature) {
        if(!this.handlers.drag.dragging) {
            this.over = false;
            this.handlers.drag.deactivate();
            OpenLayers.Element.removeClass(
                this.map.viewPortDiv, this.displayClass + "Over"
            );
            this.onLeave(feature);
            this.feature = null;
        } else {
            if(this.feature.id == feature.id) {
                this.over = false;
            }
        }
    },

    /**
     * Method: cancel
     * Called when the drag handler detects a mouse-out (from the map viewport).
     */
    cancel: function() {
        this.handlers.drag.deactivate();
        this.over = false;
    },

    /**
     * Method: setMap
     * Set the map property for the control and all handlers.
     *
     * Parameters:
     * map - {<OpenLayers.Map>} The control's map.
     */
    setMap: function(map) {
        this.handlers.drag.setMap(map);
        this.handlers.feature.setMap(map);
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
    },

    CLASS_NAME: "OpenLayers.Control.DragFeature"
});
<|endoftext|>


<commit_before>QUnit.test("parse basic", function( assert ) {
  var obj = parseHocon('x : 5');
  assert.ok( obj.x === 5);
});

QUnit.test("parse basic in braces", function( assert ) {
  var obj = parseHocon('{ x : 5 }');
  assert.ok( obj.x === 5);
});

QUnit.test("parse two fields by comma", function( assert ) {
  var obj = parseHocon('{ x : 5, y : 6 }');
  assert.ok( obj.x === 5);
  assert.ok( obj.y === 6);
});

QUnit.test("parse two fields by newline", function( assert ) {
  var obj = parseHocon('{ x : 5\r\n y : 6 }');
  assert.ok( obj.x === 5);
  assert.ok( obj.y === 6);
});

QUnit.test("parse object inside another object", function( assert ) {
  var obj = parseHocon('{ x { y : 6 }}');
  assert.ok( obj.x.y === 6);
});

QUnit.test("parse float", function( assert ) {
  var obj = parseHocon('x : 2.1');
  assert.ok( obj.x === 2.1);
});

QUnit.test("parse string", function( assert ) {
  var obj = parseHocon('x : a2.1');
  assert.ok( obj.x === 'a2.1');
});

QUnit.test("parse deep key", function( assert ) {
  var obj = parseHocon('x.y.z : 300');
  assert.ok( obj.x.y.z === 300);
});

QUnit.test("parse deep key with object val", function( assert ) {
  var obj = parseHocon('x.y.z { a: \'hello\' , b: \'it\\\'s me\' }');
  assert.ok( obj.x.y.z.a === 'hello');
  assert.ok( obj.x.y.z.b === 'it\'s me');
});

QUnit.test("parse basic array", function( assert ) {
  var obj = parseHocon('[2,5]');
  assert.ok( obj.length === 2);
  assert.ok( obj[0] === 2);
  assert.ok( obj[1] === 5);
});

QUnit.test("parse array in field", function( assert ) {
  var obj = parseHocon('x: [2,5]');
  assert.ok( obj.x.length === 2);
  assert.ok( obj.x[0] === 2);
  assert.ok( obj.x[1] === 5);
});
// { x {  } }
QUnit.test("parse objects in array", function( assert ) {
  var obj = parseHocon('{x:[\'a\',\'b\',{c:3},5]}');
  assert.ok( obj.x.length === 4);
  assert.ok( obj.x[0] === 'a');
  assert.ok( obj.x[1] === 'b');
  assert.ok( obj.x[2].c === 3);
  assert.ok( obj.x[3] === 5);
});

QUnit.test("parse objects in arrayx", function( assert ) {
  var obj = parseHocon(`{x : [
  {
    c:3
  }
]}`);
  assert.ok( obj.x.length === 1);
  assert.ok( obj.x[0].c === 3);
});

QUnit.test('parse basic subtitutions', function( assert ) {
  var obj = parseHocon('{ x: 5, y: ${x}}');
  assert.ok(obj.x === 5);
  assert.ok(obj.y === 5);
  console.log(obj);
});

QUnit.test('ignore comment', function( assert ) {
  var obj = parseHocon(`{
      # this isn\'t a field
      x : 10
    }`);
  assert.ok(obj.x === 10);
  assert.ok(typeof obj['#'] === 'undefined');
});

QUnit.test('ignore comment same line', function( assert ) {
  var obj = parseHocon(`{
      x : 10# this isn\'t a field
      y : 10 # this isn\'t a field
    }`);
  assert.ok(obj.x === 10);
  assert.ok(obj.y === 10);
  assert.ok(typeof obj['#'] === 'undefined');
});
<commit_msg>Use assert.equal instead of assert.ok in all tests<commit_after>QUnit.test("parse basic", function(assert) {
  var obj = parseHocon('x : 5');
  assert.equal(obj.x, 5);;
});

QUnit.test("parse basic in braces", function(assert) {
  var obj = parseHocon('{ x : 5 }');
  assert.equal(obj.x, 5);;
});

QUnit.test("parse two fields by comma", function(assert) {
  var obj = parseHocon('{ x : 5, y : 6 }');
  assert.equal(obj.x, 5);;
  assert.equal(obj.y, 6);;
});

QUnit.test("parse two fields by newline", function(assert) {
  var obj = parseHocon('{ x : 5\r\n y : 6 }');
  assert.equal(obj.x, 5);;
  assert.equal(obj.y, 6);;
});

QUnit.test("parse object inside another object", function(assert) {
  var obj = parseHocon('{ x { y : 6 }}');
  assert.equal(obj.x.y, 6);;
});

QUnit.test("parse float", function(assert) {
  var obj = parseHocon('x : 2.1');
  assert.equal(obj.x, 2.1);;
});

QUnit.test("parse string", function(assert) {
  var obj = parseHocon('x : a2.1');
  assert.equal(obj.x, 'a2.1');;
});

QUnit.test("parse deep key", function(assert) {
  var obj = parseHocon('x.y.z : 300');
  assert.equal(obj.x.y.z, 300);;
});

QUnit.test("parse deep key with object val", function(assert) {
  var obj = parseHocon('x.y.z { a: \'hello\' , b: \'it\\\'s me\' }');
  assert.equal(obj.x.y.z.a, 'hello');;
  assert.equal(obj.x.y.z.b, 'it\'s me');;
});

QUnit.test("parse basic array", function(assert) {
  var obj = parseHocon('[2,5]');
  assert.equal(obj.length, 2);;
  assert.equal(obj[0], 2);;
  assert.equal(obj[1], 5);;
});

QUnit.test("parse array in field", function(assert) {
  var obj = parseHocon('x: [2,5]');
  assert.equal(obj.x.length, 2);;
  assert.equal(obj.x[0], 2);;
  assert.equal(obj.x[1], 5);;
});
// { x {  } }
QUnit.test("parse objects in array", function(assert) {
  var obj = parseHocon('{x:[\'a\',\'b\',{c:3},5]}');
  assert.equal(obj.x.length, 4);;
  assert.equal(obj.x[0], 'a');;
  assert.equal(obj.x[1], 'b');;
  assert.equal(obj.x[2].c, 3);;
  assert.equal(obj.x[3], 5);;
});

QUnit.test("parse objects in arrayx", function(assert) {
  var obj = parseHocon(`{x : [
  {
    c:3
  }
]}`);
  assert.equal(obj.x.length, 1);;
  assert.equal(obj.x[0].c, 3);;
});

QUnit.test('parse basic subtitutions', function(assert) {
  var obj = parseHocon('{ x: 5, y: ${x}}');
  assert.equal(obj.x, 5);;
  assert.equal(obj.y, 5);;
  console.log(obj);
});

QUnit.test('ignore comment', function(assert) {
  var obj = parseHocon(`{
      # this isn\'t a field
      x : 10
    }`);
  assert.equal(obj.x, 10);;
  assert.equal(typeof obj['#'], 'undefined');;
});

QUnit.test('ignore comment same line', function(assert) {
  var obj = parseHocon(
    `{
      x : 10# this isn\'t a field
      y : 10 # this isn\'t a field
    }`
  );
  assert.equal(obj.x, 10);;
  assert.equal(obj.y, 10);;
  assert.equal(typeof obj['#'], 'undefined');;
});
<|endoftext|>


<commit_before>test("hello test", function() {
    ok(1 == "1", "Passed!");
});

test("Factorial function", function() {
    ok(factorial(5) == 120, "120 is not equal to " + factorial(5));
});

test("Currying function", function() {
    var babyKoala = babyAnimals('koalas');
    ok(babyKoala('elephants') == 'i love koalas and elephants', 'It went wrong')
});<commit_msg>added test for splices vs slides<commit_after>// Test for testing array "recursive"
function arraysEqual(arr1, arr2) {
    if(arr1.length !== arr2.length)
        return false;
    for(var i = arr1.length; i--;) {
        if(arr1[i] !== arr2[i])
            return false;
    }
    return true;
}

test("hello test", function() {
    ok(1 == "1", "Passed!");
});

test("Factorial function", function() {
    ok(factorial(5) == 120, "120 is not equal to " + factorial(5));
});

test("Currying function", function() {
    var babyKoala = babyAnimals('koalas');
    ok(babyKoala('elephants') == 'i love koalas and elephants', 'It went wrong')
});

// Splice vs Slice
test("Slice test", function() {
    ok('abc'.slice(1, 2) === 'b');
    ok(arraysEqual([14, 3, 77].slice(1, 2), [3]));
});

// Splices mutates the arrays
test("Splice test", function() {
    ok(arraysEqual([14, 3, 77].splice(1, 2), [3, 77]));

    var originalArray = [14, 3, 77];
    var newArray = originalArray.splice(1, 2);

    ok(arraysEqual(originalArray, [3, 77]), originalArray);
});<|endoftext|>


<commit_before>module.exports = {
    "rules": {
        "padded-blocks": 0, // mocha blocks tend to be more readable with padding
        "max-nested-callbacks": 0, // mocha blocks are nested all the way down
        "no-undefined": 0,// sometimes it's necessary to check for undefined explicitly
        "brace-style": [2, "1tbs", { "allowSingleLine": true }] // in order to make mocks more condensed, single line blocks are allowed in tests
    }
};
<commit_msg>Add mocha env to tests config<commit_after>module.exports = {
    "env": {
        "mocha": true
    },
    "rules": {
        "padded-blocks": 0, // mocha blocks tend to be more readable with padding
        "max-nested-callbacks": 0, // mocha blocks are nested all the way down
        "no-undefined": 0,// sometimes it's necessary to check for undefined explicitly
        "brace-style": [2, "1tbs", { "allowSingleLine": true }] // in order to make mocks more condensed, single line blocks are allowed in tests
    }
};
<|endoftext|>


<commit_before>/* @flow */
import React, {Component} from 'react';
import RichTextEditor from './RichTextEditor';
import {convertToRaw} from 'draft-js';
import autobind from 'class-autobind';

import type {EditorValue} from './RichTextEditor';

type Props = {};
type State = {
  value: EditorValue;
  format: string;
};

export default class EditorDemo extends Component<Props, State> {
  props: Props;
  state: State;

  constructor() {
    super(...arguments);
    autobind(this);
    this.state = {
      value: RichTextEditor.createEmptyValue(),
      format: 'html',
    };
  }

  render(): React.Element {
    let {value, format} = this.state;
    return (

This is a demo of the react-rte editor.

          <RichTextEditor
            value={value}
            onChange={this._onChange}
          />

            <input
              type="radio"
              name="format"
              value="html"
              checked={format === 'html'}
              onChange={this._onChangeFormat}
            />
            HTML

            <input
              type="radio"
              name="format"
              value="markdown"
              checked={format === 'markdown'}
              onChange={this._onChangeFormat}
            />
            Markdown

          <textarea
            className="source"
            placeholder="Editor Source"
            value={value.toString(format)}
            onChange={this._onChangeSource}
          />

          Debugging:
          <button className="btn" onClick={this._logState}>Log Content State</button>
          <button className="btn" onClick={this._logStateRaw}>Log Raw</button>

    );
  }

  _logState() {
    let editorState = this.state.value.getEditorState();
    let contentState = window.contentState = editorState.getCurrentContent().toJS();
    console.log(contentState);
  }

  _logStateRaw() {
    let editorState = this.state.value.getEditorState();
    let contentState = editorState.getCurrentContent();
    let rawContentState = window.rawContentState = convertToRaw(contentState);
    console.log(JSON.stringify(rawContentState));
  }

  _onChange(value: EditorValue) {
    this.setState({value});
  }

  _onChangeSource(event: Object) {
    let source = event.target.value;
    let oldValue = this.state.value;
    this.setState({
      value: oldValue.setContentFromString(source, this.state.format),
    });
  }

  _onChangeFormat(event: Object) {
    this.setState({format: event.target.value});
  }
}
<commit_msg>Add placeholder text to component<commit_after>/* @flow */
import React, {Component} from 'react';
import RichTextEditor from './RichTextEditor';
import {convertToRaw} from 'draft-js';
import autobind from 'class-autobind';

import type {EditorValue} from './RichTextEditor';

type Props = {};
type State = {
  value: EditorValue;
  format: string;
};

export default class EditorDemo extends Component<Props, State> {
  props: Props;
  state: State;

  constructor() {
    super(...arguments);
    autobind(this);
    this.state = {
      value: RichTextEditor.createEmptyValue(),
      format: 'html',
    };
  }

  render(): React.Element {
    let {value, format} = this.state;
    return (

This is a demo of the react-rte editor.

          <RichTextEditor
            value={value}
            onChange={this._onChange}
            placeholder="Tell a story"
          />

            <input
              type="radio"
              name="format"
              value="html"
              checked={format === 'html'}
              onChange={this._onChangeFormat}
            />
            HTML

            <input
              type="radio"
              name="format"
              value="markdown"
              checked={format === 'markdown'}
              onChange={this._onChangeFormat}
            />
            Markdown

          <textarea
            className="source"
            placeholder="Editor Source"
            value={value.toString(format)}
            onChange={this._onChangeSource}
          />

          Debugging:
          <button className="btn" onClick={this._logState}>Log Content State</button>
          <button className="btn" onClick={this._logStateRaw}>Log Raw</button>

    );
  }

  _logState() {
    let editorState = this.state.value.getEditorState();
    let contentState = window.contentState = editorState.getCurrentContent().toJS();
    console.log(contentState);
  }

  _logStateRaw() {
    let editorState = this.state.value.getEditorState();
    let contentState = editorState.getCurrentContent();
    let rawContentState = window.rawContentState = convertToRaw(contentState);
    console.log(JSON.stringify(rawContentState));
  }

  _onChange(value: EditorValue) {
    this.setState({value});
  }

  _onChangeSource(event: Object) {
    let source = event.target.value;
    let oldValue = this.state.value;
    this.setState({
      value: oldValue.setContentFromString(source, this.state.format),
    });
  }

  _onChangeFormat(event: Object) {
    this.setState({format: event.target.value});
  }
}
<|endoftext|>