<commit_before>'use strict';

describe("Search controller: ", function () {
    var searchController, $scope, $controller, $httpBackend, $injector, $templateCache, $rootScope;

    beforeEach(function() {
        module('owh');

        inject(function (_$controller_, _$rootScope_, _$injector_, _$templateCache_) {
            // The injector unwraps the underscores (_) from around the parameter names when matching
            $rootScope = _$rootScope_;
            $controller = _$controller_;
            $injector   = _$injector_;
            $scope= _$rootScope_.$new();
            $httpBackend = $injector.get('$httpBackend');
            $templateCache = _$templateCache_;

            searchController= $controller('SearchController',{$scope:$scope});
            $httpBackend.whenGET('app/i18n/messages-en.json').respond({ hello: 'World' });
            $httpBackend.whenGET('app/partials/marker-template.html').respond( $templateCache.get('app/partials/marker-template.html'));
            $httpBackend.whenGET('app/partials/home/home.html').respond( $templateCache.get('app/partials/home/home.html'));
            $httpBackend.whenPOST('/search').respond( $templateCache.get('app/partials/marker-template.html'))
        });
    });

    it("Should execute showFbDialog",function() {
        var shareUtilService= {
            shareOnFb: function(){}
        };
        var searchController= $controller('SearchController',{$scope:$scope, shareUtilService:shareUtilService});
        searchController.showFbDialog([],"graphTitle","graph subtitle");
    });

    it("Should execute showExpandedGraph",function() {
        var chartUtilService= {
            showExpandedGraph: function(){}
        };
        var searchController= $controller('SearchController',{$scope:$scope, chartUtilService:chartUtilService});
        searchController.showExpandedGraph([]);
    });

    it("With selectedPrimaryfilter as disease ",function(){

        var stateparams = { primaryFilterKey: "deaths" };
        var primaryFilterChangedFn, searchResultThenFn;
        var allFilters = [
            /*Demographics*/
            {key: 'race', title: 'label.filter.race', queryKey:"race", primary: false, value: [], groupBy: 'row',
                type:"label.filter.group.demographics", showChart: true, defaultGroup:"column",
                autoCompleteOptions: []},
            {key: 'gender', title: 'label.filter.gender', queryKey:"sex", primary: false, value: [], groupBy: 'column',
                type:"label.filter.group.demographics", groupByDefault: 'column', showChart: true,
                autoCompleteOptions: [], defaultGroup:"column"},

            /*Year and Month*/
            {key: 'year', title: 'label.filter.year', queryKey:"current_year",primary: false, value: ['2014'],
                groupBy: false,type:"label.filter.group.year.month", defaultGroup:"row",autoCompleteOptions:[
                    { "key": "2014", "title": "2014" },
                    { "key": "2013", "title": "2013" },
                    { "key": "2012", "title": "2012" }
                ]}
        ];

        function searchResultFn() {
            return {then:function(func){
                searchResultThenFn = func;
            }}
        }
        var maps = {"states":[
            {"name":"NY","deaths":53107,"sex":[{"name":"M","deaths":27003},{"name":"F","deaths":26104}]},
            {"name":"MT","deaths":53060,"sex":[{"name":"M","deaths":26800},{"name":"F","deaths":26260}]},
            {"name":"WA","deaths":53057,"sex":[{"name":"M","deaths":26955},{"name":"F","deaths":26102}]}
        ]};

        //mock searchFactory object
        var searchFactory= {
            addCountsToAutoCompleteOptions: function(){
                return {then: function(func) {
                    primaryFilterChangedFn= func;
                }};
            },
            getAllFilters:function () {
                return {search:[{
                    key: 'deaths', title: 'label.filter.mortality', primary: true, value: [], header:"Mortality",
                    allFilters: allFilters, searchResults: searchResultFn, showMap:true,
                    countLabel: 'Number of Deaths', mapData:{}, searchCount:30032, maps: maps,
                    sideFilters:[
                        {
                            filterGroup: false, collapse: false, allowGrouping: true,
                            filters: allFilters[0]
                        },
                        {
                            filterGroup: false, collapse: true, allowGrouping: true,
                            filters: allFilters[1]
                        }
                    ]
                },
                    {
                        key: 'mental_health',title: 'label.risk.behavior',primary: true,value: [],
                        header: "Youth risk behavior",allFilters: [],searchResults: searchResultFn,
                        dontShowInlineCharting: true,additionalHeaders: [], countLabel: 'Total',
                        sideFilters: [
                            {
                                filterGroup: false, collapse: false, allowGrouping: false, dontShowCounts: true,
                                filters: allFilters[2]
                            }
                        ]
                    }
                ]}
            },
            showPhaseTwoModal:function (text) {
                return text;
            }
        };

        var searchController= $controller('SearchController',{$scope: $scope, searchFactory:searchFactory, $stateParams:stateparams});
        expect(searchController.filters).toBeDefined();
        expect(searchController.selectedMapSize).toEqual("small");

        //change map size to big
        searchController.selectedMapSize = "big";

        //Call primaryFilterChanged
        primaryFilterChangedFn();

        //Call SearchResultFn
        searchResultThenFn();

        //show phase two graphs
        searchController.showPhaseTwoGraphs("show next graph modal");

        var dummyFeatureObj = {
            properties: {
                totalCount:53100
            }
        };
        //call map style method of map to get the legend colors
        var styleObj = searchController.filters.selectedPrimaryFilter.mapData.geojson.style(dummyFeatureObj);
        expect(styleObj.weight).toBe(2);
        expect(styleObj.color).toEqual("white");

        /*getSelectedYears */
        //getSelectedYears
        var selectedYear = searchController.getSelectedYears();
        expect(selectedYear.length).toEqual(1);

        //If selected year has no value
        searchController.filters.selectedPrimaryFilter.allFilters[2].value="";
        selectedYear = searchController.getSelectedYears();
        expect(selectedYear.length).toEqual(3);

        //yearFilter is empty
        searchController.filters.selectedPrimaryFilter.allFilters=[];
        searchController.getSelectedYears();
        /*getSelectedYears */

        ////Changes the key values from deaths to yrbs
        //// make an initial selection
        //$scope.$apply('sc.filters.selectedPrimaryFilter.key="deaths"');
        //
        //// make another one
        //$scope.$apply('sc.filters.selectedPrimaryFilter.key="mental_health"');

        //on event
        //var args = {leafletEvent:{leafEvent:{latlng:{lat:3434,lng:42234}, target:{feature: {properties:{}}}, _map:{}}}}
        //$rootScope.$broadcast('leafletDirectiveGeoJson.click',event, args);
    });

    it("downloadCSV should call out to xlsService and $window.open",inject(function(utilService) {
        var mockWindow = {
          open: function() {

          }
        };

        spyOn(mockWindow, 'open');
        spyOn(utilService, 'prepareMixedTableData').and.returnValue({});
        var searchController= $controller('SearchController',{$scope:$scope, $window: mockWindow});
        searchController.filters = {selectedPrimaryFilter: {data: {}} };
        searchController.downloadCSV();

        expect(mockWindow.open).toHaveBeenCalled();
    }));

});
<commit_msg>OWH-21: adding tests to search controller<commit_after>'use strict';

describe("Search controller: ", function () {
    var searchController, $scope, $controller, $httpBackend, $injector, $templateCache, $rootScope;

    beforeEach(function() {
        module('owh');

        inject(function (_$controller_, _$rootScope_, _$injector_, _$templateCache_) {
            // The injector unwraps the underscores (_) from around the parameter names when matching
            $rootScope = _$rootScope_;
            $controller = _$controller_;
            $injector   = _$injector_;
            $scope= _$rootScope_.$new();
            $httpBackend = $injector.get('$httpBackend');
            $templateCache = _$templateCache_;

            searchController= $controller('SearchController',{$scope:$scope});
            $httpBackend.whenGET('app/i18n/messages-en.json').respond({ hello: 'World' });
            $httpBackend.whenGET('app/partials/marker-template.html').respond( $templateCache.get('app/partials/marker-template.html'));
            $httpBackend.whenGET('app/partials/home/home.html').respond( $templateCache.get('app/partials/home/home.html'));
            $httpBackend.whenPOST('/search').respond( $templateCache.get('app/partials/marker-template.html'))
        });
    });

    it("Should execute showFbDialog",function() {
        var shareUtilService= {
            shareOnFb: function(){}
        };
        var searchController= $controller('SearchController',{$scope:$scope, shareUtilService:shareUtilService});
        searchController.showFbDialog([],"graphTitle","graph subtitle");
    });

    it("Should execute showExpandedGraph",function() {
        var chartUtilService= {
            showExpandedGraph: function(){}
        };
        var searchController= $controller('SearchController',{$scope:$scope, chartUtilService:chartUtilService});
        searchController.showExpandedGraph([]);
    });

    it("With selectedPrimaryfilter as disease ",function(){

        var stateparams = { primaryFilterKey: "deaths" };
        var primaryFilterChangedFn, searchResultThenFn;
        var allFilters = [
            /*Demographics*/
            {key: 'race', title: 'label.filter.race', queryKey:"race", primary: false, value: [], groupBy: 'row',
                type:"label.filter.group.demographics", showChart: true, defaultGroup:"column",
                autoCompleteOptions: []},
            {key: 'gender', title: 'label.filter.gender', queryKey:"sex", primary: false, value: [], groupBy: 'column',
                type:"label.filter.group.demographics", groupByDefault: 'column', showChart: true,
                autoCompleteOptions: [], defaultGroup:"column"},

            /*Year and Month*/
            {key: 'year', title: 'label.filter.year', queryKey:"current_year",primary: false, value: ['2014'],
                groupBy: false,type:"label.filter.group.year.month", defaultGroup:"row",autoCompleteOptions:[
                    { "key": "2014", "title": "2014" },
                    { "key": "2013", "title": "2013" },
                    { "key": "2012", "title": "2012" }
                ]}
        ];

        function searchResultFn() {
            return {then:function(func){
                searchResultThenFn = func;
            }}
        }
        var maps = {"states":[
            {"name":"NY","deaths":53107,"sex":[{"name":"M","deaths":27003},{"name":"F","deaths":26104}]},
            {"name":"MT","deaths":53060,"sex":[{"name":"M","deaths":26800},{"name":"F","deaths":26260}]},
            {"name":"WA","deaths":53057,"sex":[{"name":"M","deaths":26955},{"name":"F","deaths":26102}]}
        ]};

        //mock searchFactory object
        var searchFactory= {
            addCountsToAutoCompleteOptions: function(){
                return {then: function(func) {
                    primaryFilterChangedFn= func;
                }};
            },
            getAllFilters:function () {
                return {search:[{
                    key: 'deaths', title: 'label.filter.mortality', primary: true, value: [], header:"Mortality",
                    allFilters: allFilters, searchResults: searchResultFn, showMap:true,
                    countLabel: 'Number of Deaths', mapData:{}, searchCount:30032, maps: maps,
                    sideFilters:[
                        {
                            filterGroup: false, collapse: false, allowGrouping: true,
                            filters: allFilters[0]
                        },
                        {
                            filterGroup: false, collapse: true, allowGrouping: true,
                            filters: allFilters[1]
                        }
                    ]
                },
                    {
                        key: 'mental_health',title: 'label.risk.behavior',primary: true,value: [],
                        header: "Youth risk behavior",allFilters: [],searchResults: searchResultFn,
                        dontShowInlineCharting: true,additionalHeaders: [], countLabel: 'Total',
                        sideFilters: [
                            {
                                filterGroup: false, collapse: false, allowGrouping: false, dontShowCounts: true,
                                filters: allFilters[2]
                            }
                        ]
                    }
                ]}
            },
            showPhaseTwoModal:function (text) {
                return text;
            }
        };

        var searchController= $controller('SearchController',{$scope: $scope, searchFactory:searchFactory, $stateParams:stateparams});
        expect(searchController.filters).toBeDefined();
        expect(searchController.selectedMapSize).toEqual("small");

        //change map size to big
        searchController.selectedMapSize = "big";

        //Call primaryFilterChanged
        primaryFilterChangedFn();

        //Call SearchResultFn
        searchResultThenFn();

        //show phase two graphs
        searchController.showPhaseTwoGraphs("show next graph modal");

        var dummyFeatureObj = {
            properties: {
                totalCount:53100
            }
        };
        //call map style method of map to get the legend colors
        var styleObj = searchController.filters.selectedPrimaryFilter.mapData.geojson.style(dummyFeatureObj);
        expect(styleObj.weight).toBe(2);
        expect(styleObj.color).toEqual("white");

        /*getSelectedYears */
        //getSelectedYears
        var selectedYear = searchController.getSelectedYears();
        expect(selectedYear.length).toEqual(1);

        //If selected year has no value
        searchController.filters.selectedPrimaryFilter.allFilters[2].value="";
        selectedYear = searchController.getSelectedYears();
        expect(selectedYear.length).toEqual(3);

        //yearFilter is empty
        searchController.filters.selectedPrimaryFilter.allFilters=[];
        searchController.getSelectedYears();
        /*getSelectedYears */

        ////Changes the key values from deaths to yrbs
        //// make an initial selection
        //$scope.$apply('sc.filters.selectedPrimaryFilter.key="deaths"');
        //
        //// make another one
        //$scope.$apply('sc.filters.selectedPrimaryFilter.key="mental_health"');

        //on event
        //var args = {leafletEvent:{leafEvent:{latlng:{lat:3434,lng:42234}, target:{feature: {properties:{}}}, _map:{}}}}
        //$rootScope.$broadcast('leafletDirectiveGeoJson.click',event, args);
    });

    it("downloadCSV should call out to xlsService",inject(function(utilService, xlsService) {
        spyOn(utilService, 'prepareMixedTableData').and.returnValue({});
        spyOn(xlsService, 'exportCSVFromMixedTable');
        var searchController= $controller('SearchController',{$scope:$scope});
        searchController.filters = {selectedPrimaryFilter: {data: {}} };
        searchController.downloadCSV();

        expect(xlsService.exportCSVFromMixedTable).toHaveBeenCalled();
    }));

    it('downloadXLS should call out to xlsService', inject(function(utilService, xlsService) {
        spyOn(utilService, 'prepareMixedTableData').and.returnValue({});
        spyOn(xlsService, 'exportXLSFromMixedTable');
        var searchController= $controller('SearchController',{$scope:$scope});
        searchController.filters = {selectedPrimaryFilter: {data: {}} };
        searchController.downloadXLS();

        expect(xlsService.exportXLSFromMixedTable).toHaveBeenCalled();
    }));

});
<|endoftext|>


<commit_before>/*global twemoji, s9e*/

import { override } from 'flarum/extend';
import app from 'flarum/app';
import Post from 'flarum/models/Post';

app.initializers.add('emoji', () => {
  override(Post.prototype, 'contentHtml', original => {
    return twemoji.parse(original());
  });

  override(s9e.TextFormatter, 'preview', (original, text, element) => {
    original(text, element);

    twemoji.parse(element);
  });
});
<commit_msg>PERF: Cache emojified post content<commit_after>/*global twemoji, s9e*/

import { override } from 'flarum/extend';
import app from 'flarum/app';
import Post from 'flarum/models/Post';

app.initializers.add('emoji', () => {
  override(Post.prototype, 'contentHtml', function(original) {
    const contentHtml = original();

    if (this.oldContentHtml !== contentHtml) {
      this.emojifiedContentHtml = twemoji.parse(contentHtml);
      this.oldContentHtml = contentHtml;
    }

    return this.emojifiedContentHtml;
  });

  override(s9e.TextFormatter, 'preview', (original, text, element) => {
    original(text, element);

    twemoji.parse(element);
  });
});
<|endoftext|>


<commit_before>// Karma configuration
// Generated on Sun May 08 2016 23:14:26 GMT-0700 (PDT)

module.exports = function(config) {
  var settings = {

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '..',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      //{pattern: 'node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js', watched: false, included: true, served: true},
      //{pattern: 'tests/boot.js', watched: true, included: true, served: true},
      //{pattern: 'build/*', watched: true, included: true, served: true},
      {pattern: 'build/janusweb.js', watched: true, included: true, served: true},
      {pattern: 'build/janusweb.assetworker.js', watched: true, included: false, served: true},
      {pattern: 'build/janusweb.css', watched: true, included: true, served: true},
      {pattern: 'build/media/*', watched: false, included: false, served: true},
      {pattern: 'build/media/**', watched: false, included: false, served: true},
      //'tests/imagediff.js',
      //{pattern: 'tests/janusweb.test.js', watched: true, included: true, served: true},
      {pattern: 'tests/assets/*.test.js', watched: true, included: true, served: true},
      //{pattern: 'tests/render/*.test.js', watched: true, included: true, served: true},
      {pattern: 'tests/room.test.js', watched: true, included: true, served: true},
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_DEBUG,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    customLaunchers: {
        Chrome_travis_ci: {
            base: 'Chrome',
            flags: ['--no-sandbox', '--enable-webgl', '--ignore-gpu-blacklist']
        }
    },

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    //browsers: ['Chrome', 'Firefox'],
    browsers: ['ChromeHeadless'],
    browserNoActivityTimeout: 60000,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  };

  if (process.env.TRAVIS) {
    //settings.browsers = ['Chrome_travis_ci'];
  }

  config.set(settings);
}
<commit_msg>CI tweaks<commit_after>// Karma configuration
// Generated on Sun May 08 2016 23:14:26 GMT-0700 (PDT)

module.exports = function(config) {
  var settings = {

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '..',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      //{pattern: 'node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js', watched: false, included: true, served: true},
      //{pattern: 'tests/boot.js', watched: true, included: true, served: true},
      //{pattern: 'build/*', watched: true, included: true, served: true},
      {pattern: 'build/janusweb.js', watched: true, included: true, served: true},
      {pattern: 'build/janusweb.assetworker.js', watched: true, included: false, served: true},
      {pattern: 'build/janusweb.css', watched: true, included: true, served: true},
      {pattern: 'build/media/*', watched: false, included: false, served: true},
      {pattern: 'build/media/**', watched: false, included: false, served: true},
      //'tests/imagediff.js',
      //{pattern: 'tests/janusweb.test.js', watched: true, included: true, served: true},
      {pattern: 'tests/assets/*.test.js', watched: true, included: true, served: true},
      //{pattern: 'tests/render/*.test.js', watched: true, included: true, served: true},
      {pattern: 'tests/room.test.js', watched: true, included: true, served: true},
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_DEBUG,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    customLaunchers: {
        Chrome_travis_ci: {
            base: 'Chrome',
            flags: ['--no-sandbox', '--headless', '--enable-webgl', '--ignore-gpu-blacklist']
        }
    },

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    //browsers: ['Chrome', 'Firefox'],
    browsers: ['Chrome_travis_ci'],
    browserNoActivityTimeout: 60000,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  };

  if (process.env.TRAVIS) {
    //settings.browsers = ['Chrome_travis_ci'];
  }

  config.set(settings);
}
<|endoftext|>


<commit_before>var path = function(){
    var saving = false;
    var cStep = null;
    var tPubic = 'public';
    var tPrivate = 'private';
    var tEval = 'eval';
    var $dataInput = null;

    function addslashes(str){
        return (str + '').replace(/[\"]/g, '"');
    }
    function _appendTest(tcDetails){
        $("#{0}_test_tbody".format(tcDetails.tType)).append($.tmpl("testcase_row",tcDetails));
        $(".eval_expression, .expected_output, .fail_hint").unbind().change(function() {path.updateTest($(this))});
        $(".delete_test").unbind().click(function() {path.deleteTest(($(this)))});
    }

    /** data types **/

    function _newTest(){
        return {
            expected: "",
            expression: "",
            hint:""
        };
    }

    return {
        data: {
            type: "do",
            prefill: "",
            included: "",
            private: [],
            public: [],
            eval: []
        },

        saveQuestion: function(){
            saving = true;
            $dataInput.val(JSON.stringify(path.data));
        },
        initialize: function() {
            $("#saveCQ").click(path.saveQuestion);
            cStep = path.data;
            $dataInput = $("#coding_question_data");
            var tcType = JSON.parse($("#tc-type-data").val());
            path.loadTestTypes(tcType);
            if( $dataInput.val() != "") {
                path.data =  JSON.parse($dataInput.val());
                path.loadStep();
            }
        },

        /** metadata **/
        changeLang: function(val){

            cStep.language = val;

            cmPrefill.setOption("mode",val);
            cmIncluded.setOption("mode",val);
        },
        changePrefill: function(val){
            cStep.prefill = val;
        },
        changeIncluded: function(val){
            cStep.included = val;
        },
        /** tests **/
        addTest: function(event){
            var testType = event.data.param1;
            var ci = cStep;
            var tNo = ci[testType].length;
            ci[testType].push(_newTest());

            _appendTest({
                tNo:tNo,
                tType: testType,
                expression: "",
                expected: "",
                fail_hint: "",
                has_hint: testType == tPrivate
            });
        },

        updateTest: function($ele){
            var $tr = $ele.parents(".test_case");
            var c = $tr.attr("data-test-no") - 0;
            var $eo = $tr.find(".expected_output");
            var $ep = $tr.find(".eval_expression");
            var $hint = $tr.find(".fail_hint");

            cStep[$tr.attr("data-test-type")][c] = {
                expression: $ep.val(),
                expected: $eo.val(),
                hint: $hint.val()
            };
        },

        deleteTest: function($del){
            var $tr = $del.parents(".test_case");
            var c = $tr.attr("data-test-no") - 0;
            var testType = $tr.attr("data-test-type");
            cStep[testType].splice(c, 1);
            $tr.remove();
            $("#"+testType+"_test_tbody").children().each(function(index, e){
                $(e).attr("data-test-no", index);
            });
        } ,
        loadTestTypes: function(tcType) {
            var $tcDiv = $("#path_testcases");
            for (var type in tcType) {
                $tcDiv.append($.tmpl("testcase_table", {type: type, title: tcType[type], has_hint: type == tPrivate}));
                $("#add-{0}-test".format(type)).click({param1: type}, path.addTest);
            }
        },
        loadStep:function(){
            cStep = path.data;

            $("#public_test_tbody").html("");
            $("#private_test_tbody").html("");
            $("#eval_test_tbody").html("");
            var i = 0;
            var testTypes = [tPubic, tPrivate, tEval];

            for (var tt in testTypes) {
                var tType = testTypes[tt];
                if(cStep[tType]) {
                    for(i = 0 ; i < cStep[tType].length; i++){
                        var tcDetail = cStep[tType][i];
                        tcDetail["tNo"] = i;
                        tcDetail["tType"] = tType;
                        tcDetail["has_hint"] = tType == tPrivate;
                        _appendTest(tcDetail);
                    }
                }
            }

            cmPrefill.setValue(cStep.prefill);
            if(cStep.included == null) cStep.included = "";
            cmIncluded.setValue(cStep.included);
        }
    };
}();

var cmPrefill;
var cmIncluded;

$(document).ready(function() {
    if(document.getElementById("pathstep_content")) {
        //TODO: refactoring
        var options1 = {
            mode: {name: "python",
                version: 3,
                singleLineStringErrors: false},
            lineNumbers: true,
            indentUnit: 4,
            tabMode: "shift",
            matchBrackets: true,
            theme:'molokai',
            extraKeys: {
                "Tab": function(){
                    cmPrefill.replaceSelection("    " , "end");
                }
            }
        };

        var options2 = {
            mode: {name: "python",
                version: 3,
                singleLineStringErrors: false},
            lineNumbers: true,
            indentUnit: 4,
            tabMode: "shift",
            matchBrackets: true,
            theme:'molokai',
            extraKeys: {
                "Tab": function(){
                    cmIncluded.replaceSelection("    " , "end");
                }
            }
        };

        cmPrefill = CodeMirror.fromTextArea(document.getElementById("prefilled"), options1);
        cmIncluded = CodeMirror.fromTextArea(document.getElementById("included"), options2);

        cmPrefill.on("change",function(){
            path.changePrefill(cmPrefill.getValue());
        });
        cmIncluded.on("change",function(){
            path.changeIncluded(cmIncluded.getValue());
        });
        path.initialize();
    }
});
<commit_msg>fix coding question rendering, now generic<commit_after>var path = function(){
    var saving = false;
    var cStep = null;
    var tPubic = 'public';
    var tPrivate = 'private';
    var tEval = 'eval';
    var $dataInput = null;

    function addslashes(str){
        return (str + '').replace(/[\"]/g, '"');
    }
    function _appendTest(tcDetails){
        $("#{0}_test_tbody".format(tcDetails.tType)).append($.tmpl("testcase_row",tcDetails));
        $(".eval_expression, .expected_output, .fail_hint").unbind().change(function() {path.updateTest($(this))});
        $(".delete_test").unbind().click(function() {path.deleteTest(($(this)))});
    }

    /** data types **/

    function _newTest(){
        return {
            expected: "",
            expression: "",
            hint:""
        };
    }

    return {
        data: {
            private: [],
            public: [],
            eval: []
        },

        saveQuestion: function(){
            saving = true;
            $dataInput.val(JSON.stringify(path.data));
        },
        initialize: function() {
            $("#saveCQ").click(path.saveQuestion);
            cStep = path.data;
            $dataInput = $("#coding_question_data");
            var tcType = JSON.parse($("#tc-type-data").val());
            path.loadTestTypes(tcType);
            if( $dataInput.val() != "") {
                path.data =  JSON.parse($dataInput.val());
                path.loadStep();
            }
        },

        /** tests **/
        addTest: function(event){
            var testType = event.data.param1;
            var ci = cStep;
            var tNo = ci[testType].length;
            ci[testType].push(_newTest());

            _appendTest({
                tNo:tNo,
                tType: testType,
                expression: "",
                expected: "",
                fail_hint: "",
                has_hint: testType == tPrivate
            });
        },

        updateTest: function($ele){
            var $tr = $ele.parents(".test_case");
            var c = $tr.attr("data-test-no") - 0;
            var $eo = $tr.find(".expected_output");
            var $ep = $tr.find(".eval_expression");
            var $hint = $tr.find(".fail_hint");

            cStep[$tr.attr("data-test-type")][c] = {
                expression: $ep.val(),
                expected: $eo.val(),
                hint: $hint.val()
            };
        },

        deleteTest: function($del){
            var $tr = $del.parents(".test_case");
            var c = $tr.attr("data-test-no") - 0;
            var testType = $tr.attr("data-test-type");
            cStep[testType].splice(c, 1);
            $tr.remove();
            $("#"+testType+"_test_tbody").children().each(function(index, e){
                $(e).attr("data-test-no", index);
            });
        } ,
        loadTestTypes: function(tcType) {
            var $tcDiv = $("#path_testcases");
            for (var type in tcType) {
                $tcDiv.append($.tmpl("testcase_table", {type: type, title: tcType[type], has_hint: type == tPrivate}));
                $("#add-{0}-test".format(type)).click({param1: type}, path.addTest);
            }
        },
        loadStep:function(){
            cStep = path.data;

            $("#public_test_tbody").html("");
            $("#private_test_tbody").html("");
            $("#eval_test_tbody").html("");
            var i = 0;
            var testTypes = [tPubic, tPrivate, tEval];

            for (var tt in testTypes) {
                var tType = testTypes[tt];
                if(cStep[tType]) {
                    for(i = 0 ; i < cStep[tType].length; i++){
                        var tcDetail = cStep[tType][i];
                        tcDetail["tNo"] = i;
                        tcDetail["tType"] = tType;
                        tcDetail["has_hint"] = tType == tPrivate;
                        _appendTest(tcDetail);
                    }
                } else {
                    cStep[tType] = [];
                }
            }
        }
    };
}();

$(document).ready(function() {
    //TODO: handle change of language
    var code_blocks = $("[render='code']");
    if (code_blocks.length > 0) {
        code_blocks.each(function(){
            $block = $(this);
            var language = $block.attr("language"), version = $block.attr("version");
            var cmBlock;
            var options = {
                mode: {name: language, version: version, singleLineStringErrors: false},
                lineNumbers: true,
                tabMode: "shift",
                matchBrackets: true,
//                TODO: refactor theme
                theme:'molokai',
                extraKeys: {
                    "Tab": function(){
                        cmBlock.replaceSelection("    " , "end");
                    }
                }
            };
            cmBlock = CodeMirror.fromTextArea(this, options);
            cmBlock.on("change",function(){
                $block.val(cmBlock.getValue());
            });
        })
    }
    if(document.getElementById("pathstep_content")) {
        path.initialize();
    }
});
<|endoftext|>


<commit_before>/*
* Kendo UI v2015.2.902 (http://www.telerik.com/kendo-ui)
* Copyright 2015 Telerik AD. All rights reserved.
*
* Kendo UI commercial licenses may be obtained at
* http://www.telerik.com/purchase/license-agreement/kendo-ui-complete
* If you do not own a commercial license, this file shall be governed by the trial license terms.
*/
!function(e,define){define([],e)}(function(){return function(e){kendo.ui.FilterCell&&(kendo.ui.FilterCell.prototype.options.operators=e.extend(!0,kendo.ui.FilterCell.prototype.options.operators,{date:{eq:"равна",gte:"после или равна",gt:"после",lte:"до или равна",lt:"до",neq:"не равна"},number:{eq:"равно",gte:"больше или равно",gt:"больше",lte:"меньше или равно",lt:"меньше",neq:"не равно"},string:{endswith:"оканчивается на",eq:"равно",neq:"не равно",startswith:"начинающимися на",contains:"содержащими",doesnotcontain:"не содержит"},enums:{eq:"равно",neq:"не равно"}})),kendo.ui.FilterMenu&&(kendo.ui.FilterMenu.prototype.options.operators=e.extend(!0,kendo.ui.FilterMenu.prototype.options.operators,{date:{eq:"равна",gte:"после или равна",gt:"после",lte:"до или равна",lt:"до",neq:"не равна"},number:{eq:"равно",gte:"больше или равно",gt:"больше",lte:"меньше или равно",lt:"меньше",neq:"не равно"},string:{endswith:"оканчивается на",eq:"равно",neq:"не равно",startswith:"начинающимися на",contains:"содержащими",doesnotcontain:"не содержит"},enums:{eq:"равно",neq:"не равно"}})),kendo.ui.ColumnMenu&&(kendo.ui.ColumnMenu.prototype.options.messages=e.extend(!0,kendo.ui.ColumnMenu.prototype.options.messages,{columns:"Колонны",sortAscending:"Сортировка по возрастанию",sortDescending:"Сортировка по убыванию",settings:"Параметры столбцов",done:"Cделанный",lock:"Запирать",unlock:"Отпереть",filter:"Фильтровать"})),kendo.ui.RecurrenceEditor&&(kendo.ui.RecurrenceEditor.prototype.options.messages=e.extend(!0,kendo.ui.RecurrenceEditor.prototype.options.messages,{daily:{interval:"days(s)",repeatEvery:"Repeat every:"},end:{after:"After",occurrence:"occurrence(s)",label:"End:",never:"Never",on:"On",mobileLabel:"Ends"},frequencies:{daily:"Daily",monthly:"Monthly",never:"Never",weekly:"Weekly",yearly:"Yearly"},monthly:{day:"Day",interval:"month(s)",repeatEvery:"Repeat every:",repeatOn:"Repeat on:"},offsetPositions:{first:"first",fourth:"fourth",last:"last",second:"second",third:"third"},weekly:{repeatEvery:"Repeat every:",repeatOn:"Repeat on:",interval:"week(s)"},yearly:{of:"of",repeatEvery:"Repeat every:",repeatOn:"Repeat on:",interval:"year(s)"},weekdays:{day:"day",weekday:"weekday",weekend:"weekend day"}})),kendo.ui.Grid&&(kendo.ui.Grid.prototype.options.messages=e.extend(!0,kendo.ui.Grid.prototype.options.messages,{commands:{create:"Добавить",destroy:"Удалить",canceledit:"Отмена",update:"Обновить",edit:"Изменить",excel:"Export to Excel",pdf:"Export to PDF",select:"Выбрать",cancel:"Отменить изменения",save:"Сохранить изменения"},editable:{confirmation:"Вы уверены, что хотите удалить эту запись?",cancelDelete:"Отмена",confirmDelete:"Удалить"},noRecords:"Нет записей доступны."})),kendo.ui.Pager&&(kendo.ui.Pager.prototype.options.messages=e.extend(!0,kendo.ui.Pager.prototype.options.messages,{page:"Страница",display:"Отображены записи {0} - {1} из {2}",of:"из {0}",empty:"Нет записей для отображения",refresh:"Обновить",first:"Вернуться на первую страницу",itemsPerPage:"элементов на странице",last:"К последней странице",next:"Перейдите на следующую страницу",previous:"Перейти на предыдущую страницу",morePages:"Больше страниц"})),kendo.ui.FilterCell&&(kendo.ui.FilterCell.prototype.options.messages=e.extend(!0,kendo.ui.FilterCell.prototype.options.messages,{filter:"фильтровать",clear:"очистить",isFalse:"ложь",isTrue:"истина",operator:"Оператор"})),kendo.ui.FilterMenu&&(kendo.ui.FilterMenu.prototype.options.messages=e.extend(!0,kendo.ui.FilterMenu.prototype.options.messages,{filter:"фильтровать",and:"И",clear:"очистить",info:"Строки со значениями",selectValue:"-выберите-",isFalse:"ложь",isTrue:"истина",or:"или",cancel:"Отмена",operator:"Оператор",value:"Значение"})),kendo.ui.Groupable&&(kendo.ui.Groupable.prototype.options.messages=e.extend(!0,kendo.ui.Groupable.prototype.options.messages,{empty:"Переместите сюда заголовок колонки, чтобы сгрупировать записи из этой колонки"})),kendo.ui.Editor&&(kendo.ui.Editor.prototype.options.messages=e.extend(!0,kendo.ui.Editor.prototype.options.messages,{bold:"Полужирный",createLink:"Вставить гиперссылку",fontName:"Шрифт",fontNameInherit:"(шрифт как в документе)",fontSize:"Выбрать размер шрифта",fontSizeInherit:"(размер как в документе)",formatBlock:"Текст изображения",indent:"Увеличить отступ",insertHtml:"Вставить HTML",insertImage:"Изображение",insertOrderedList:"Нумерованный список",insertUnorderedList:"Маркированныйсписок",italic:"Курсив",justifyCenter:"По центру",justifyFull:"По ширине",justifyLeft:"Влево",justifyRight:"Вправо",outdent:"Уменьшить отступ",strikethrough:"Зачеркнутый",styles:"Стиль",subscript:"Под строкой",superscript:"Над строкой",underline:"Подчеркнутый",unlink:"Удалить гиперссылку",dialogButtonSeparator:"или",dialogCancel:"Отмена",dialogInsert:"Вставить",imageAltText:"Alternate text",imageWebAddress:"Веб адрес",linkOpenInNewWindow:"Открыть в новом окне",linkText:"Текст",linkToolTip:"Всплывающая подсказка",linkWebAddress:"Веб адрес",search:"Поиск",createTable:"Вставить таблицу",addColumnLeft:"Add column on the left",addColumnRight:"Add column on the right",addRowAbove:"Add row above",addRowBelow:"Add row below",deleteColumn:"Delete column",deleteRow:"Delete row",backColor:"Background color",deleteFile:'Are you sure you want to delete "{0}"?',directoryNotFound:"A directory with this name was not found.",dropFilesHere:"drop files here to upload",emptyFolder:"Empty Folder",foreColor:"Color",invalidFileType:'The selected file "{0}" is not valid. Supported file types are {1}.',orderBy:"Arrange by:",orderByName:"Name",orderBySize:"Size",overwriteFile:'\'A file with name "{0}" already exists in the current directory. Do you want to overwrite it?',uploadFile:"Upload",formatting:"Format",viewHtml:"View HTML",dialogUpdate:"Update",insertFile:"Insert file"})),kendo.ui.Upload&&(kendo.ui.Upload.prototype.options.localization=e.extend(!0,kendo.ui.Upload.prototype.options.localization,{cancel:"Отменить загрузку",dropFilesHere:"перетащите сюда файлы для загрузки",remove:"Удалить",retry:"Повторить",select:"Выбрать...",statusFailed:"загрузка прервана",statusUploaded:"загружено",statusUploading:"загружается",uploadSelectedFiles:"Загрузить выбранные файлы",headerStatusUploaded:"Done",headerStatusUploading:"Uploading..."})),kendo.ui.Scheduler&&(kendo.ui.Scheduler.prototype.options.messages=e.extend(!0,kendo.ui.Scheduler.prototype.options.messages,{allDay:"all day",cancel:"Отмена",editable:{confirmation:"Are you sure you want to delete this event?"},date:"Date",destroy:"Delete",editor:{allDayEvent:"All day event",description:"Description",editorTitle:"Event",end:"End",endTimezone:"End timezone",repeat:"Repeat",separateTimezones:"Use separate start and end time zones",start:"Start",startTimezone:"Start timezone",timezone:" ",timezoneEditorButton:"Time zone",timezoneEditorTitle:"Timezones",title:"Title",noTimezone:"No timezone"},event:"Event",recurrenceMessages:{deleteRecurring:"Do you want to delete only this event occurrence or the whole series?",deleteWindowOccurrence:"Delete current occurrence",deleteWindowSeries:"Delete the series",deleteWindowTitle:"Delete Recurring Item",editRecurring:"Do you want to edit only this event occurrence or the whole series?",editWindowOccurrence:"Edit current occurrence",editWindowSeries:"Edit the series",editWindowTitle:"Edit Recurring Item"},save:"Save",time:"Time",today:"Today",views:{agenda:"Agenda",day:"Day",month:"Month",week:"Week",workWeek:"Work Week"},deleteWindowTitle:"Delete event",showFullDay:"Show full day",showWorkDay:"Show business hours"})),kendo.ui.Validator&&(kendo.ui.Validator.prototype.options.messages=e.extend(!0,kendo.ui.Validator.prototype.options.messages,{required:"{0} обязателен",pattern:"{0} не верен",min:"{0} должен быть больше или равен {1}",max:"{0} должен быть меньше или равен {1}",step:"{0} не верен",email:"{0} не корректный email",url:"{0} не корректный URL",date:"{0} не корректная дата"}))}(window.kendo.jQuery),window.kendo},"function"==typeof define&&define.amd?define:function(e,t){t()});<commit_msg>Delete kendo.messages.ru-RU.min.js<commit_after><|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name ngWindowManager.directive:wmwindow
 * @description
 * # wmWindow
 */
angular.module('ngWindowManager',[])
.directive('wmwindow', function () {
	return {
		template: '
'+
					'
'+
						'
' +
							'
{{title}}
'+
							'
' +
								'<button class="wmMaximize" ng-show="isMaximizable()">' +
								'<button style="display:none" class="wmRestore"/>'+
								'<button class="wmClose" ng-show="isCloseable()" />'+
							'
'+
						'
'+
						'

'+
						'<button  class="wmResize" />'+
					'
'+
				'
',
		restrict: 'E',
		replace: true,
		transclude: true,
		scope: {
			title: '@',
			close: '=',
			open: '=',
			selectwindow: '=',
			maximize: '=',
			restore: '=',
			options: '@',
			maximizable: '@',
			closeable: '@',
		},
		link: function (scope, element) {
			var parentWindow = element[0].parentElement;
			var windowArea = parentWindow;

			var titleBarElement = element[0].children[0].children[0];
			var contentButtonElement = element[0].children[0].children[1];
			var resizeButtonElement = element[0].children[0].children[2];

			var buttonBar = titleBarElement.children[1];

			var maximizeButton = buttonBar.children[0];
			var closeButton = buttonBar.children[2];

			//State variables
			var positionState = null;
			var sizeState = null;
			var maximizeState = null;

			var winHandler = {};
			winHandler.elem = element;

			//Parse the options
			var options = scope.options ? JSON.parse(scope.options) :{};

			//If it's defined a windowContainer zone we will use it to bind
			//all the listeners, that way we can fit windows under an element but move in other
			if (options.windowContainer){
				windowArea = document.getElementById(options.windowContainer);
			}

			//Set some tricky controls to handle the layering
			if (parentWindow.topZ === undefined){
				parentWindow.topZ = options.initialZIndex || parentElement.css('z-index') || 100000;
			}

			//This function is executed when close button is pushed
			winHandler.close = function (){
				setTimeout (function (){
						element.addClass ('closing');
						setTimeout (function (){
						element.removeClass ('closing');
						element.remove();
					},300);
				},50);

				if (scope.close){
					scope.close(winHandler);
				}
			};

			scope.isMaximizable = function (){
				return (scope.maximizable === undefined || scope.maximizable === true || scope.maximizable === 'true') ? true : false ;
			}

			scope.isCloseable = function (){
				return (scope.closeable === undefined || scope.closeable === true || scope.closeable === 'true') ? true : false ;
			}

			//Executed when touches or clicks in the title bar
			var startMoving = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);
				var moveRef =  isTouch ?  e.targetTouches[0] : e;

				positionState = calculatePos({
					x: moveRef.pageX,
					y: moveRef.pageY
				});

				element.addClass('moving');

				windowArea.addEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindow);
				windowArea.addEventListener (isTouch ? 'touchend' : 'mouseup',dragWindowEnds);

				selectWindow();

				e.preventDefault();
			};

			//Executed when touches or clicks in the resize button
			var startResizing = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);
				var moveRef =  isTouch ?  e.targetTouches[0] : e;

				sizeState = calculateSize ({
					width:  moveRef.pageX,
					height: moveRef.pageY
				});

				element.addClass('resizing');

				windowArea.addEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindowCorner);
				windowArea.addEventListener (isTouch ? 'touchend' : 'mouseup', dragWindowCornerEnds);
				selectWindow();

				e.preventDefault();

			};

			//Execute when user moves the mouse after title is clicked
			var dragWindow = function(e) {
				var moveRef = (e.targetTouches && e.targetTouches.length === 1) ?  e.targetTouches[0] : e;

				if (positionState){
					move(
						moveRef.pageX - positionState.x,
						moveRef.pageY - positionState.y
					);
				}

				e.preventDefault();
			};

			//Execute when user moves the pointer after resize button is clicked
			var dragWindowCorner = function (e){
				var moveRef = (e.targetTouches && e.targetTouches.length === 1) ?  e.targetTouches[0] : e;

				if (sizeState){
					resize (
						moveRef.pageX + sizeState.width,
						moveRef.pageY + sizeState.height
					);
				}

				e.preventDefault();
			};

			//The user ends moving window when mouseup or touchends
			var dragWindowEnds = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);

				if (positionState) {
					element.removeClass('moving');
					positionState = null;
				}

				windowArea.removeEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindow);
				windowArea.removeEventListener (isTouch ? 'touchend' : 'mouseup',dragWindowEnds);
				titleBarElement.removeEventListener ('click', selectWindow);

				e.preventDefault();
			};

			//The user ends moving the resize button when mouseup or touchends
			var dragWindowCornerEnds = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);

				if (sizeState){
					element.removeClass ('resizing');
					sizeState = null;
				}

				windowArea.removeEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindowCorner);
				windowArea.removeEventListener (isTouch ? 'touchend' : 'mouseup',dragWindowCornerEnds);

				e.preventDefault();
			};

			//it just makes a postion calculation from the current positon reference passed
			var calculatePos = function(ref) {
				var winX = parseInt(element.prop('offsetLeft'), 10);
				var winY = parseInt(element.prop('offsetTop'), 10);

				return {
					x: ref.x - winX,
					y: ref.y - winY
				};
			};

			//it just makes a size calculation from the current positon reference passed
			var calculateSize = function (ref){
				var winWidth = parseInt(element.prop('offsetWidth'), 10);
				var winHeight = parseInt(element.prop('offsetHeight'), 10);

				return {
					width: winWidth - ref.width,
					height: winHeight - ref.height
				};
			};

			//set the element in the specified position
			var move = function(x, y) {
				element.css('left',x +'px');
				element.css('top',y + 'px');

			};

			//set the new size of the element
			var resize = function (width,height) {
				element.css ('width', width + 'px');
				element.css ('height', height + 'px');
			};

			//Move the current window to the highest position
			var selectWindow = function (){
				parentWindow.topZ = parentWindow.topZ +1;
				element.css ('z-index', parentWindow.topZ);
				if (scope.selectwindow) scope.selectwindow(winHandler);
			};

			//This functions is executed when maximize is executed
			var maximize = function (){

				//Store the position and the size state
				maximizeState = {
					x: parseInt(element.prop('offsetLeft'), 10),
					y: parseInt(element.prop('offsetTop'), 10),
					width: parseInt(element.prop('offsetWidth'), 10),
					height: parseInt(element.prop('offsetHeight'), 10),
					z: element.css ('z-index')
				};

				//Select the element where to maximize
				var maximizeToElement  = window;

				if (options.maximizeTo!=='window'){
					var elementToMaximize = document.getElementById (options.maximizeTo) || document.getElementsByTagName (options.maximizeTo);
					maximizeToElement = options.maximizeTo ? (elementToMaximize) : windowArea;
				}

				var maximizeCoords = {
					x: parseInt(maximizeToElement.offsetLeft || 0, 10) ,
					y: parseInt(maximizeToElement.offsetTop ||0, 10),
					width: parseInt(maximizeToElement.offsetWidth ||maximizeToElement.innerWidth, 10),
					height: parseInt(maximizeToElement.offsetHeight || maximizeToElement.innerHeight, 10)
				};

				//move, set the effect and resize
				move (maximizeCoords.x + 10,maximizeCoords.y +10 );
				element.addClass ('maximizing');
				element.addClass('maximized');
				resize (maximizeCoords.width -20, maximizeCoords.height - 20);

				//Set the apropiate listeners
				maximizeButton.removeEventListener ('click',maximize);
				maximizeButton.removeEventListener ('touchstart',maximize);

				maximizeButton.addEventListener ('click',restore);
				maximizeButton.addEventListener ('touchstart',restore);

				titleBarElement.removeEventListener ('dblclick', maximize);
				titleBarElement.addEventListener ('dblclick', restore);

				//Stop all the window listener (drag,resize...)
				stopWindowListeners();

				//Program the effect extraction
				setTimeout (function (){
					element.removeClass ('maximizing');

				},500);

				if (scope.maximize){
					scope.maximize();
				}

			};

			var restore = function (){
				//move and resize to previus state
				element.addClass ('restoring');
				element.removeClass ('maximized');

				//move and resize to prior state
				move (maximizeState.x,maximizeState.y);
				resize(maximizeState.width,maximizeState.height);
				element.css ('z-index',maximizeState.z);
				//Restore the listeners
				maximizeButton.removeEventListener ('click',restore);
				maximizeButton.removeEventListener ('touchstart',restore);

				maximizeButton.addEventListener ('click',maximize);
				maximizeButton.addEventListener ('touchstart',maximize);

				titleBarElement.removeEventListener ('dblclick', restore);
				titleBarElement.addEventListener ('dblclick', maximize);

				//start all the window listener (drag,resize...)
				startWindowListeners();

				//Execute restore method if it's provided
				if (scope.restore){
					scope.restore();
				}

				//Removes the element some time ago
				setTimeout (function (){
					element.removeClass ('restoring');
				},500);

			};

			var startWindowListeners =  function (){
				titleBarElement.addEventListener ('mousedown', startMoving);
				titleBarElement.addEventListener ('touchstart', startMoving);

				resizeButtonElement.addEventListener ('mousedown',startResizing);
				resizeButtonElement.addEventListener ('touchstart',startResizing);
				contentButtonElement.addEventListener ('click', selectWindow);

			};

			var stopWindowListeners = function (){
				titleBarElement.removeEventListener ('mousedown', startMoving);
				titleBarElement.removeEventListener ('touchstart', startMoving);

				resizeButtonElement.removeEventListener ('mousedown',startResizing);
				resizeButtonElement.removeEventListener ('touchstart',startResizing);
				contentButtonElement.removeEventListener ('click', selectWindow);
			};

			//Set the window in creatio

			//Set and start all the window listener (drag,resize...)
			startWindowListeners ();

			//Set buttons listener
			closeButton.addEventListener ('click',winHandler.close);
			closeButton.addEventListener ('touchstart',winHandler.close);
			maximizeButton.addEventListener ('click',maximize);
			maximizeButton.addEventListener ('touchstart',maximize);
			if (scope.maximizable) {titleBarElement.addEventListener ('dblclick', maximize);}

			// apply the options for the window
			if (options.position){
				var position = options.position;
				move (position.x,position.y);
			}
			if (options.size){
				var size = options.size;
				resize (size.width,size.height);
			}

			//To avoid adding transition listeners we remove tha clas after some time
			setTimeout (function (){
				element.addClass ('active');
				element.addClass ('opening');
				selectWindow();

				setTimeout (function (){
					element.removeClass ('opening');
					if (scope.open)
						scope.open(winHandler);
				},400);
			},50);
		}
	};
});
<commit_msg>Expose some other methods from wmanager to be controlled from controllers<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name ngWindowManager.directive:wmwindow
 * @description
 * # wmWindow
 */
angular.module('ngWindowManager',[])
.directive('wmwindow', function () {
	return {
		template: '
'+
					'
'+
						'
' +
							'
{{title}}
'+
							'
' +
								'<button class="wmMaximize" ng-show="isMaximizable()">' +
								'<button style="display:none" class="wmRestore"/>'+
								'<button class="wmClose" ng-show="isCloseable()" />'+
							'
'+
						'
'+
						'

'+
						'<button  class="wmResize" />'+
					'
'+
				'
',
		restrict: 'E',
		replace: true,
		transclude: true,
		scope: {
			title: '@',
			close: '=',
			open: '=',
			selectwindow: '=',
			maximize: '=',
			restore: '=',
			options: '@',
			maximizable: '@',
			closeable: '@',
		},
		link: function (scope, element) {
			var parentWindow = element[0].parentElement;
			var windowArea = parentWindow;

			var titleBarElement = element[0].children[0].children[0];
			var contentButtonElement = element[0].children[0].children[1];
			var resizeButtonElement = element[0].children[0].children[2];

			var buttonBar = titleBarElement.children[1];

			var maximizeButton = buttonBar.children[0];
			var closeButton = buttonBar.children[2];

			//State variables
			var positionState = null;
			var sizeState = null;
			var maximizeState = null;

			var winHandler = {};
			winHandler.elem = element;

			//Parse the options
			var options = scope.options ? JSON.parse(scope.options) :{};

			//If it's defined a windowContainer zone we will use it to bind
			//all the listeners, that way we can fit windows under an element but move in other
			if (options.windowContainer){
				windowArea = document.getElementById(options.windowContainer);
			}

			//Set some tricky controls to handle the layering
			if (parentWindow.topZ === undefined){
				parentWindow.topZ = options.initialZIndex || parentElement.css('z-index') || 100000;
			}

			//This function is executed when close button is pushed
			winHandler.close = function (){
				setTimeout (function (){
						element.addClass ('closing');
						setTimeout (function (){
						element.removeClass ('closing');
						element.remove();
					},300);
				},50);

				if (scope.close){
					scope.close(winHandler);
				}
			};

			scope.isMaximizable = function (){
				return (scope.maximizable === undefined || scope.maximizable === true || scope.maximizable === 'true') ? true : false ;
			}

			scope.isCloseable = function (){
				return (scope.closeable === undefined || scope.closeable === true || scope.closeable === 'true') ? true : false ;
			}

			//Executed when touches or clicks in the title bar
			var startMoving = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);
				var moveRef =  isTouch ?  e.targetTouches[0] : e;

				positionState = calculatePos({
					x: moveRef.pageX,
					y: moveRef.pageY
				});

				element.addClass('moving');

				windowArea.addEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindow);
				windowArea.addEventListener (isTouch ? 'touchend' : 'mouseup',dragWindowEnds);

				winHandler.selectWindow();

				e.preventDefault();
			};

			//Executed when touches or clicks in the resize button
			var startResizing = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);
				var moveRef =  isTouch ?  e.targetTouches[0] : e;

				sizeState = calculateSize ({
					width:  moveRef.pageX,
					height: moveRef.pageY
				});

				element.addClass('resizing');

				windowArea.addEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindowCorner);
				windowArea.addEventListener (isTouch ? 'touchend' : 'mouseup', dragWindowCornerEnds);
				winHandler.selectWindow();

				e.preventDefault();

			};

			//Execute when user moves the mouse after title is clicked
			var dragWindow = function(e) {
				var moveRef = (e.targetTouches && e.targetTouches.length === 1) ?  e.targetTouches[0] : e;

				if (positionState){
					winHandler.move(
						moveRef.pageX - positionState.x,
						moveRef.pageY - positionState.y
					);
				}

				e.preventDefault();
			};

			//Execute when user moves the pointer after resize button is clicked
			var dragWindowCorner = function (e){
				var moveRef = (e.targetTouches && e.targetTouches.length === 1) ?  e.targetTouches[0] : e;

				if (sizeState){
					winHandler.resize (
						moveRef.pageX + sizeState.width,
						moveRef.pageY + sizeState.height
					);
				}

				e.preventDefault();
			};

			//The user ends moving window when mouseup or touchends
			var dragWindowEnds = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);

				if (positionState) {
					element.removeClass('moving');
					positionState = null;
				}

				windowArea.removeEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindow);
				windowArea.removeEventListener (isTouch ? 'touchend' : 'mouseup',dragWindowEnds);
				titleBarElement.removeEventListener ('click', winHandler.selectWindow);

				e.preventDefault();
			};

			//The user ends moving the resize button when mouseup or touchends
			var dragWindowCornerEnds = function (e){
				var isTouch = (e.targetTouches && e.targetTouches.length === 1);

				if (sizeState){
					element.removeClass ('resizing');
					sizeState = null;
				}

				windowArea.removeEventListener (isTouch ? 'touchmove' : 'mousemove',dragWindowCorner);
				windowArea.removeEventListener (isTouch ? 'touchend' : 'mouseup',dragWindowCornerEnds);

				e.preventDefault();
			};

			//it just makes a postion calculation from the current positon reference passed
			var calculatePos = function(ref) {
				var winX = parseInt(element.prop('offsetLeft'), 10);
				var winY = parseInt(element.prop('offsetTop'), 10);

				return {
					x: ref.x - winX,
					y: ref.y - winY
				};
			};

			//it just makes a size calculation from the current positon reference passed
			var calculateSize = function (ref){
				var winWidth = parseInt(element.prop('offsetWidth'), 10);
				var winHeight = parseInt(element.prop('offsetHeight'), 10);

				return {
					width: winWidth - ref.width,
					height: winHeight - ref.height
				};
			};

			//set the element in the specified position
			winHandler.move = function(x, y) {
				element.css('left',x +'px');
				element.css('top',y + 'px');

			};

			//set the new size of the element
			winHandler.resize = function (width,height) {
				element.css ('width', width + 'px');
				element.css ('height', height + 'px');
			};

			//Move the current window to the highest position
			winHandler.selectWindow = function (){
				parentWindow.topZ = parentWindow.topZ +1;
				element.css ('z-index', parentWindow.topZ);
				if (scope.selectwindow) scope.selectwindow(winHandler);
			};

			//This functions is executed when maximize is executed
			winHandler.maximize = function (){

				//Store the position and the size state
				maximizeState = {
					x: parseInt(element.prop('offsetLeft'), 10),
					y: parseInt(element.prop('offsetTop'), 10),
					width: parseInt(element.prop('offsetWidth'), 10),
					height: parseInt(element.prop('offsetHeight'), 10),
					z: element.css ('z-index')
				};

				//Select the element where to maximize
				var maximizeToElement  = window;

				if (options.maximizeTo!=='window'){
					var elementToMaximize = document.getElementById (options.maximizeTo) || document.getElementsByTagName (options.maximizeTo);
					maximizeToElement = options.maximizeTo ? (elementToMaximize) : windowArea;
				}

				var maximizeCoords = {
					x: parseInt(maximizeToElement.offsetLeft || 0, 10) ,
					y: parseInt(maximizeToElement.offsetTop ||0, 10),
					width: parseInt(maximizeToElement.offsetWidth ||maximizeToElement.innerWidth, 10),
					height: parseInt(maximizeToElement.offsetHeight || maximizeToElement.innerHeight, 10)
				};

				//move, set the effect and resize
				winHandler.move (maximizeCoords.x + 10,maximizeCoords.y +10 );
				element.addClass ('maximizing');
				element.addClass('maximized');
				winHandler.resize (maximizeCoords.width -20, maximizeCoords.height - 20);

				//Set the apropiate listeners
				maximizeButton.removeEventListener ('click',winHandler.maximize);
				maximizeButton.removeEventListener ('touchstart',winHandler.maximize);

				maximizeButton.addEventListener ('click',winHandler.restore);
				maximizeButton.addEventListener ('touchstart',winHandler.restore);

				titleBarElement.removeEventListener ('dblclick', winHandler.maximize);
				titleBarElement.addEventListener ('dblclick', winHandler.restore);

				//Stop all the window listener (drag,resize...)
				stopWindowListeners();

				//Program the effect extraction
				setTimeout (function (){
					element.removeClass ('maximizing');

				},500);

				if (scope.maximize){
					scope.maximize();
				}

			};

			winHandler.restore = function (){
				//move and resize to previus state
				element.addClass ('restoring');
				element.removeClass ('maximized');

				//move and resize to prior state
				winHandler.move (maximizeState.x,maximizeState.y);
				winHandler.resize(maximizeState.width,maximizeState.height);
				element.css ('z-index',maximizeState.z);
				//Restore the listeners
				maximizeButton.removeEventListener ('click',winHandler.restore);
				maximizeButton.removeEventListener ('touchstart',winHandler.restore);

				maximizeButton.addEventListener ('click',winHandler.maximize);
				maximizeButton.addEventListener ('touchstart',winHandler.maximize);

				titleBarElement.removeEventListener ('dblclick',winHandler.restore);
				titleBarElement.addEventListener ('dblclick', winHandler.maximize);

				//start all the window listener (drag,resize...)
				startWindowListeners();

				//Execute restore method if it's provided
				if (scope.restore){
					scope.restore();
				}

				//Removes the element some time ago
				setTimeout (function (){
					element.removeClass ('restoring');
				},500);

			};

			var startWindowListeners =  function (){
				titleBarElement.addEventListener ('mousedown', startMoving);
				titleBarElement.addEventListener ('touchstart', startMoving);

				resizeButtonElement.addEventListener ('mousedown',startResizing);
				resizeButtonElement.addEventListener ('touchstart',startResizing);
				contentButtonElement.addEventListener ('click', winHandler.selectWindow);

			};

			var stopWindowListeners = function (){
				titleBarElement.removeEventListener ('mousedown', startMoving);
				titleBarElement.removeEventListener ('touchstart', startMoving);

				resizeButtonElement.removeEventListener ('mousedown',startResizing);
				resizeButtonElement.removeEventListener ('touchstart',startResizing);
				contentButtonElement.removeEventListener ('click', winHandler.selectWindow);
			};

			//Set the window in creatio

			//Set and start all the window listener (drag,resize...)
			startWindowListeners ();

			//Set buttons listener
			closeButton.addEventListener ('click',winHandler.close);
			closeButton.addEventListener ('touchstart',winHandler.close);
			maximizeButton.addEventListener ('click',winHandler.maximize);
			maximizeButton.addEventListener ('touchstart',winHandler.maximize);
			if (scope.maximizable) {titleBarElement.addEventListener ('dblclick', winHandler.maximize);}

			// apply the options for the window
			if (options.position){
				var position = options.position;
				winHandler.move (position.x,position.y);
			}
			if (options.size){
				var size = options.size;
				winHandler.resize (size.width,size.height);
			}

			//To avoid adding transition listeners we remove tha clas after some time
			setTimeout (function (){
				element.addClass ('active');
				element.addClass ('opening');
				winHandler.selectWindow();

				setTimeout (function (){
					element.removeClass ('opening');
					if (scope.open)
						scope.open(winHandler);
				},400);
			},50);
		}
	};
});
<|endoftext|>


<commit_before>import { createStore } from 'redux';
import { initialState } from './initialState';

const reducer = (state = initialState, action) => {
  switch (action.type) {
  case 'ADD_TOPIC':
    return addTopic(state, action.topic);
  default:
    return state;
  }
};

export const store = createStore(reducer);
<commit_msg>feat: update src/client/store/store.js<commit_after>import { createStore } from 'redux';
import { initialState } from './initialState';
import { addTopic } from './helpers';

const reducer = (state = initialState, action) => {
  switch (action.type) {
  case 'ADD_TOPIC':
    return addTopic(state, action.topic);
  default:
    return state;
  }
};

export const store = createStore(reducer);
<|endoftext|>


<commit_before>/*
 * Configure the Jasmine testing framework.
 */

import {
  tasks, arrayMap, arrayFilter, ieVersion
} from '../index.js';

window.DEBUG = true;
window.amdRequire = window.require;

// Use a different variable name (not 'jQuery') to avoid overwriting
// window.jQuery with 'undefined' on IE < 9
window.jQueryInstance = window.jQuery;

jasmine.updateInterval = 500;

/*
    Some helper functions for jasmine on the browser
 */
jasmine.prepareTestNode = function() {
    // The bindings specs make frequent use of this utility function to set up
    // a clean new DOM node they can execute code against
    var existingNode = document.getElementById("testNode");
    if (existingNode !== null)
        existingNode.parentNode.removeChild(existingNode);
    testNode = document.createElement("div");
    testNode.id = "testNode";
    document.body.appendChild(testNode);
};

jasmine.Clock.mockScheduler = function (callback) {
    setTimeout(callback, 0);
};

jasmine.Clock.useMockForTasks = function() {
    jasmine.Clock.useMock();

    // Make sure tasks is using setTimeout so that it uses the mock clock
    if (tasks.scheduler != jasmine.Clock.mockScheduler) {
        jasmine.getEnv().currentSpec.restoreAfter(tasks, 'scheduler');
        tasks.scheduler = jasmine.Clock.mockScheduler;
    }
};

jasmine.Spec.prototype.restoreAfter = function(object, propertyName) {
    var originalValue = object[propertyName];
    this.after(function() {
        object[propertyName] = originalValue;
    });
};

jasmine.nodeText = function(node) {
    return node.nodeType == 3 ? node.data : 'textContent' in node ? node.textContent : node.innerText;
};

jasmine.browserSupportsProtoAssignment = { __proto__: [] } instanceof Array;

jasmine.ieVersion = ieVersion;
/*
    Custom Matchers
    ~~~~~~~~~~~~~~~
 */
var matchers = {};

matchers.toContainText = function (expectedText, ignoreSpaces) {
    if (ignoreSpaces) {
        expectedText = expectedText.replace(/\s/g, "");
    }

    var actualText = jasmine.nodeText(this.actual);
    var cleanedActualText = actualText.replace(/\r\n/g, "\n");
    if (ignoreSpaces) {
        cleanedActualText = cleanedActualText.replace(/\s/g, "");
    }

    this.actual = cleanedActualText;    // Fix explanatory message
    return cleanedActualText === expectedText;
};

matchers.toHaveOwnProperties = function (expectedProperties) {
    var ownProperties = [];
    for (var prop in this.actual) {
        if (this.actual.hasOwnProperty(prop)) {
            ownProperties.push(prop);
        }
    }
    return this.env.equals_(ownProperties, expectedProperties);
};

matchers.toHaveTexts = function (expectedTexts) {
    var texts = arrayMap(this.actual.childNodes, jasmine.nodeText);
    this.actual = texts;   // Fix explanatory message
    return this.env.equals_(texts, expectedTexts);
};

matchers.toHaveValues = function (expectedValues) {
    var values = arrayMap(this.actual.childNodes, function (node) { return node.value; });
    this.actual = values;   // Fix explanatory message
    return this.env.equals_(values, expectedValues);
};

matchers.toHaveSelectedValues = function (expectedValues) {
    var selectedNodes = arrayFilter(this.actual.childNodes, function (node) { return node.selected; }),
        selectedValues = arrayMap(selectedNodes, function (node) { return ko.selectExtensions.readValue(node); });
    this.actual = selectedValues;   // Fix explanatory message
    return this.env.equals_(selectedValues, expectedValues);
};

matchers.toThrowContaining = function(expected) {
    var exception;
    try {
        this.actual();
    } catch (e) {
        exception = e;
    }
    var exceptionMessage = exception && (exception.message || exception);

    this.message = function () {
        var notText = this.isNot ? " not" : "";
        var expectation = "Expected " + this.actual.toString() + notText + " to throw exception containing '" + expected + "'";
        var result = exception ? (", but it threw '" + exceptionMessage + "'") : ", but it did not throw anything";
        return expectation + result;
    };

    return exception ? this.env.contains_(exceptionMessage, expected) : false;
};

matchers.toEqualOneOf = function (expectedPossibilities) {
    for (var i = 0; i < expectedPossibilities.length; i++) {
        if (this.env.equals_(this.actual, expectedPossibilities[i])) {
            return true;
        }
    }
    return false;
};

matchers.toContainHtml = function (expectedHtml, postProcessCleanedHtml) {
    var cleanedHtml = this.actual.innerHTML.toLowerCase().replace(/\r\n/g, "");
    // IE < 9 strips whitespace immediately following comment nodes. Normalize by doing the same on all browsers.
    cleanedHtml = cleanedHtml.replace(/(<!--.*?-->)\s*/g, "$1");
    expectedHtml = expectedHtml.replace(/(<!--.*?-->)\s*/g, "$1");
    // Also remove __ko__ expando properties (for DOM data) - most browsers hide these anyway but IE < 9 includes them in innerHTML
    cleanedHtml = cleanedHtml.replace(/ __ko__\d+=\"(ko\d+|null)\"/g, "");
    if (postProcessCleanedHtml) {
        cleanedHtml = postProcessCleanedHtml(cleanedHtml);
    }
    this.actual = cleanedHtml;      // Fix explanatory message
    return cleanedHtml === expectedHtml;
};

//
// bmh: Monkeypatch so we can catch errors in asynchronous functions.
//
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
    var scheduledFunc;
    var funcsToRun = [];
    for (var timeoutKey in this.scheduledFunctions) {
        scheduledFunc = this.scheduledFunctions[timeoutKey];
        if (scheduledFunc != jasmine.undefined &&
            scheduledFunc.runAtMillis >= oldMillis &&
            scheduledFunc.runAtMillis <= nowMillis) {
            funcsToRun.push(scheduledFunc);
            this.scheduledFunctions[timeoutKey] = jasmine.undefined;
        }
    }

    if (funcsToRun.length > 0) {
        funcsToRun.sort(function(a, b) {
            return a.runAtMillis - b.runAtMillis;
        });

        for (var i = 0; i < funcsToRun.length; ++i) {
          //try {       // mbest: Removed so we can catch errors in asynchronous functions
            var funcToRun = funcsToRun[i];
            this.nowMillis = funcToRun.runAtMillis;
            funcToRun.funcToCall();
            if (funcToRun.recurring) {
                this.scheduleFunction(funcToRun.timeoutKey,
                  funcToRun.funcToCall,
                  funcToRun.millis,
                  true);
            }
          //} catch(e) {
          //}
        }
        this.runFunctionsWithinRange(oldMillis, nowMillis);
    }
};

beforeEach(function() {
    this.addMatchers(matchers);
});
<commit_msg>ko. reference fix for selectextns (#2)<commit_after>/*
 * Configure the Jasmine testing framework.
 */

import {
  tasks, arrayMap, arrayFilter, ieVersion
} from '../index.js';

window.DEBUG = true;
window.amdRequire = window.require;

// Use a different variable name (not 'jQuery') to avoid overwriting
// window.jQuery with 'undefined' on IE < 9
window.jQueryInstance = window.jQuery;

jasmine.updateInterval = 500;

/*
    Some helper functions for jasmine on the browser
 */
jasmine.prepareTestNode = function() {
    // The bindings specs make frequent use of this utility function to set up
    // a clean new DOM node they can execute code against
    var existingNode = document.getElementById("testNode");
    if (existingNode !== null)
        existingNode.parentNode.removeChild(existingNode);
    testNode = document.createElement("div");
    testNode.id = "testNode";
    document.body.appendChild(testNode);
};

jasmine.Clock.mockScheduler = function (callback) {
    setTimeout(callback, 0);
};

jasmine.Clock.useMockForTasks = function() {
    jasmine.Clock.useMock();

    // Make sure tasks is using setTimeout so that it uses the mock clock
    if (tasks.scheduler != jasmine.Clock.mockScheduler) {
        jasmine.getEnv().currentSpec.restoreAfter(tasks, 'scheduler');
        tasks.scheduler = jasmine.Clock.mockScheduler;
    }
};

jasmine.Spec.prototype.restoreAfter = function(object, propertyName) {
    var originalValue = object[propertyName];
    this.after(function() {
        object[propertyName] = originalValue;
    });
};

jasmine.nodeText = function(node) {
    return node.nodeType == 3 ? node.data : 'textContent' in node ? node.textContent : node.innerText;
};

jasmine.browserSupportsProtoAssignment = { __proto__: [] } instanceof Array;

jasmine.ieVersion = ieVersion;
/*
    Custom Matchers
    ~~~~~~~~~~~~~~~
 */
var matchers = {};

matchers.toContainText = function (expectedText, ignoreSpaces) {
    if (ignoreSpaces) {
        expectedText = expectedText.replace(/\s/g, "");
    }

    var actualText = jasmine.nodeText(this.actual);
    var cleanedActualText = actualText.replace(/\r\n/g, "\n");
    if (ignoreSpaces) {
        cleanedActualText = cleanedActualText.replace(/\s/g, "");
    }

    this.actual = cleanedActualText;    // Fix explanatory message
    return cleanedActualText === expectedText;
};

matchers.toHaveOwnProperties = function (expectedProperties) {
    var ownProperties = [];
    for (var prop in this.actual) {
        if (this.actual.hasOwnProperty(prop)) {
            ownProperties.push(prop);
        }
    }
    return this.env.equals_(ownProperties, expectedProperties);
};

matchers.toHaveTexts = function (expectedTexts) {
    var texts = arrayMap(this.actual.childNodes, jasmine.nodeText);
    this.actual = texts;   // Fix explanatory message
    return this.env.equals_(texts, expectedTexts);
};

matchers.toHaveValues = function (expectedValues) {
    var values = arrayMap(this.actual.childNodes, function (node) { return node.value; });
    this.actual = values;   // Fix explanatory message
    return this.env.equals_(values, expectedValues);
};

matchers.toHaveSelectedValues = function (expectedValues) {
    var selectedNodes = arrayFilter(this.actual.childNodes, function (node) { return node.selected; }),
        selectedValues = arrayMap(selectedNodes, function (node) { return this.selectExtensions.readValue(node); });
    this.actual = selectedValues;   // Fix explanatory message
    return this.env.equals_(selectedValues, expectedValues);
};

matchers.toThrowContaining = function(expected) {
    var exception;
    try {
        this.actual();
    } catch (e) {
        exception = e;
    }
    var exceptionMessage = exception && (exception.message || exception);

    this.message = function () {
        var notText = this.isNot ? " not" : "";
        var expectation = "Expected " + this.actual.toString() + notText + " to throw exception containing '" + expected + "'";
        var result = exception ? (", but it threw '" + exceptionMessage + "'") : ", but it did not throw anything";
        return expectation + result;
    };

    return exception ? this.env.contains_(exceptionMessage, expected) : false;
};

matchers.toEqualOneOf = function (expectedPossibilities) {
    for (var i = 0; i < expectedPossibilities.length; i++) {
        if (this.env.equals_(this.actual, expectedPossibilities[i])) {
            return true;
        }
    }
    return false;
};

matchers.toContainHtml = function (expectedHtml, postProcessCleanedHtml) {
    var cleanedHtml = this.actual.innerHTML.toLowerCase().replace(/\r\n/g, "");
    // IE < 9 strips whitespace immediately following comment nodes. Normalize by doing the same on all browsers.
    cleanedHtml = cleanedHtml.replace(/(<!--.*?-->)\s*/g, "$1");
    expectedHtml = expectedHtml.replace(/(<!--.*?-->)\s*/g, "$1");
    // Also remove __ko__ expando properties (for DOM data) - most browsers hide these anyway but IE < 9 includes them in innerHTML
    cleanedHtml = cleanedHtml.replace(/ __ko__\d+=\"(ko\d+|null)\"/g, "");
    if (postProcessCleanedHtml) {
        cleanedHtml = postProcessCleanedHtml(cleanedHtml);
    }
    this.actual = cleanedHtml;      // Fix explanatory message
    return cleanedHtml === expectedHtml;
};

//
// bmh: Monkeypatch so we can catch errors in asynchronous functions.
//
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
    var scheduledFunc;
    var funcsToRun = [];
    for (var timeoutKey in this.scheduledFunctions) {
        scheduledFunc = this.scheduledFunctions[timeoutKey];
        if (scheduledFunc != jasmine.undefined &&
            scheduledFunc.runAtMillis >= oldMillis &&
            scheduledFunc.runAtMillis <= nowMillis) {
            funcsToRun.push(scheduledFunc);
            this.scheduledFunctions[timeoutKey] = jasmine.undefined;
        }
    }

    if (funcsToRun.length > 0) {
        funcsToRun.sort(function(a, b) {
            return a.runAtMillis - b.runAtMillis;
        });

        for (var i = 0; i < funcsToRun.length; ++i) {
          //try {       // mbest: Removed so we can catch errors in asynchronous functions
            var funcToRun = funcsToRun[i];
            this.nowMillis = funcToRun.runAtMillis;
            funcToRun.funcToCall();
            if (funcToRun.recurring) {
                this.scheduleFunction(funcToRun.timeoutKey,
                  funcToRun.funcToCall,
                  funcToRun.millis,
                  true);
            }
          //} catch(e) {
          //}
        }
        this.runFunctionsWithinRange(oldMillis, nowMillis);
    }
};

beforeEach(function() {
    this.addMatchers(matchers);
});
<|endoftext|>


<commit_before>'use strict'

const test = require('tape')
const Hub = require('../')

test('serialize', function (t) {
  const server = new Hub({
    id: 'server',
    context: false,
    syncUp: false,
    port: 6000,
    clients: { sort: 'key' },
    obj1: {},
    obj2: {}
  })
  server.set({
    obj1: { ref: server.obj2 },
    obj2: { ref: server.obj1 }
  })

  const client = new Hub({
    id: 1,
    url: 'ws://localhost:6000',
    context: false
  })

  client.subscribe({ val: true })

  setTimeout(() => {
    t.pass('did not crash on circular references')
    t.end()
  }, 100)
})
<commit_msg>cleanup when test pass<commit_after>'use strict'

const test = require('tape')
const Hub = require('../')

test('serialize', function (t) {
  const server = new Hub({
    id: 'server',
    context: false,
    syncUp: false,
    port: 6000,
    clients: { sort: 'key' },
    obj1: {},
    obj2: {}
  })
  server.set({
    obj1: { ref: server.obj2 },
    obj2: { ref: server.obj1 }
  })

  const client = new Hub({
    id: 1,
    url: 'ws://localhost:6000',
    context: false
  })

  client.subscribe({ val: true })

  setTimeout(() => {
    client.remove()
    server.remove()
    t.pass('did not crash on circular references')
    t.end()
  }, 100)
})
<|endoftext|>