<commit_before>angular.module('yds').directive('ydsRegionSelectorGr', ['Data', '$q',
    function (Data, $q) {
        return {
            restrict: 'E',
            scope: {
                elementH:'@'    // Height of the component in pixels
            },
            templateUrl: ((typeof Drupal != 'undefined')? Drupal.settings.basePath  + Drupal.settings.yds_project.modulePath  +'/' :'') + 'templates/region-selector-gr.html',
            link: function (scope, element) {
                var elementH = parseInt(scope.elementH);

                var regionSelContainer = angular.element(element[0].querySelector('.region-selector-container'));

                //create a random id for the element that will render the plot
                var elementId = "regionsel" + Data.createRandomId();
                regionSelContainer[0].id = elementId;

                //check if the component's height attr is defined, else assign default value
                if(_.isUndefined(elementH) || _.isNaN(elementH))
                    elementH = 300;

                // Selectivity instance
                var selectivity = null;

                // Declare states of map points object, used in the configuration of the map later
                var states = {
                    hover: {
                        color: '#e5ed04'
                    },
                    select: {
                        color: '#a4edba',
                        borderColor: 'black',
                        dashStyle: 'shortdot'
                    }
                };

                // Declare object with regions
                var regions = {
                    "GR.TS": {
                        name: "Thessalia",
                        prefectures: [
                            "N. MAGNISIAS",
                            "N. KARDITSAS",
                            "N. LARISAS",
                            "N. TRIKALON"
                        ]
                    },
                    "GR.AT": {
                        name: "Attiki",
                        prefectures: [
                            "N. PIREOS KE NISON",
                            "N. ANATOLIKIS ATTIKIS",
                            "N. DYTIKIS ATTIKIS",
                            "N. ATHINON"
                        ]
                    },
                    "GR.GC": {
                        name: "Sterea Ellada",
                        prefectures: [
                            "N. VIOTIAS",
                            "N. EVVIAS",
                            "N. EVRYTANIAS",
                            "N. FOKIDAS",
                            "N. FTHIOTIDAS"
                        ]
                    },
                    "GR.MC": {
                        name: "Kentriki Makedonia",
                        prefectures: [
                            "N. IMATHIAS",
                            "N. THESSALONIKIS",
                            "N. KILKIS",
                            "N. PELLAS",
                            "N. PIERIAS",
                            "N. SERRON",
                            "N. CHALKIDIKIS"
                        ]
                    },
                    "GR.CR": {
                        name: "Kriti",
                        prefectures: [
                            "N. CHANION",
                            "N. IRAKLIOU",
                            "N. LASITHIOU",
                            "N. RETHYMNOU"
                        ]
                    },
                    "GR.MT": {
                        name: "Anatoliki Makedonia kai Thraki",
                        prefectures: [
                            "N. DRAMAS",
                            "N. EVROU",
                            "N. KAVALAS",
                            "N. XANTHIS",
                            "N. RODOPIS"
                        ]
                    },
                    "GR.EP": {
                        name: "Ipeiros",
                        prefectures: [
                            "N. ARTAS",
                            "N. IOANNINON",
                            "N. PREVEZAS",
                            "N. THESPROTIAS"
                        ]
                    },
                    "GR.II": {
                        name: "Ionioi Nisoi",
                        prefectures: [
                            "N. KERKYRAS",
                            "N. KEFALLONIAS",
                            "N. LEFKADAS",
                            "N. ZAKYNTHOU"
                        ]
                    },
                    "GR.AN": {
                        name: "Voreio Aigaio",
                        prefectures: [
                            "N. CHIOU",
                            "N. SAMOU",
                            "N. LESVOU"
                        ]
                    },
                    "GR.PP": {
                        name: "Peloponnisos",
                        prefectures: [
                            "N. ARKADIAS",
                            "N. ARGOLIDAS",
                            "N. KORINTHOU",
                            "N. LAKONIAS",
                            "N. MESSINIAS"
                        ]
                    },
                    "GR.AS": {
                        name: "Notio Aigaio",
                        prefectures: [
                            "N. KYKLADON",
                            "N. DODEKANISON"
                        ]
                    },
                    "GR.GW": {
                        name: "Dytiki Ellada",
                        prefectures: [
                            "N. ACHAIAS",
                            "N. ETOLOAKARNANIAS",
                            "N. ILIAS"
                        ]
                    },
                    "GR.MW": {
                        name: "Dytiki Makedonia",
                        prefectures: [
                            "N. FLORINAS",
                            "N. GREVENON",
                            "N. KASTORIAS",
                            "N. KOZANIS"
                        ]
                    },
                    "GR.MA": {
                        name: "Ayion Oros",
                        prefectures: [
                            "AGIO OROS"
                        ]
                    }
                };

                /**
                 * Callback for when drillup happens. Clears the selected points from the chart,
                 * and sets the chart's subtitle to empty
                 */
                var drillup = function () {
                    var chart = this,
                        points = [];
                    setTimeout(function () {
                        points = chart.getSelectedPoints();

                        Highcharts.each(points, function (p) {
                            // unselect points from previous drilldown
                            p.selected = false;
                            p.setState('', true);
                        });
                    }, 0);

                    chart.setTitle(null, {text: ''});
                };

                /**
                 * Callback for when drilldown happens. Gets the drilled-down point, and creates the series that should
                 * be shown based on the drilldownMap
                 * @param e
                 */
                var drilldown = function (e) {
                    if (!e.seriesOptions  && e.point.selected) {
                        var chart = this,
                            mapKey = e.point.drilldown,
                            regionName = e.point.name;
                        chart.showLoading("Loading...");

                        Data.getGeoJSON("high", mapKey).then(function(response) {
                            var mapData = response;
                            var drilldownData = [];

                            // For each prefecture to display, create a value of 1 for it so it is colored
                            $.each(mapData.features, function () {
                                drilldownData.push({
                                    name: this.properties.NAME_ENG,
                                    value: 1
                                });
                            });

                            // Hide loading and add series
                            chart.hideLoading();
                            chart.addSeriesAsDrilldown(e.point, {
                                name: regionName,
                                data: drilldownData,
                                mapData: mapData,
                                joinBy: ['NAME_ENG', "name"],
                                keys: ['NAME_ENG', 'value'],
                                allowPointSelect: true,
                                dataLabels: {
                                    enabled: true,
                                    format: '{point.properties.NAME_ENG}'
                                },
                                tooltip: {
                                    enabled: false,
                                    pointFormatter: function() {
                                        return "" + this.properties.NAME_ENG + "";
                                    }
                                },
                                point: {
                                    events: {
                                        select: prefectureSelectionHandler,
                                        unselect: prefectureUnselectionHandler
                                    }
                                },
                                states: states
                            });
                        });
                    }

                    this.setTitle(null, {text: regionName});
                };

                // Declare object which shows how many prefectures are in each region of Greece
                var drilldownMap = {
                    "GR.TS": 4,
                    "GR.AT": 4,
                    "GR.GC": 5,
                    "GR.MC": 7,
                    "GR.CR": 4,
                    "GR.MT": 5,
                    "GR.EP": 4,
                    "GR.II": 4,
                    "GR.AN": 3,
                    "GR.PP": 5,
                    "GR.AS": 2,
                    "GR.GW": 3,
                    "GR.MW": 4,
                    "GR.MA": 1
                };

                // Get low detail Greece map
                Data.getGeoJSON("low", null).then(function(response) {
                    Highcharts.maps["countries/gr-low-res"] = response;

                    // Get low detail map data
                    var mapData = Highcharts.geojson(Highcharts.maps['countries/gr-low-res']);
                    var data = [];

                    _.each(mapData, function (item) {
                        var code = item.properties.hasc;
                        item.drilldown = code;
                        if (_.has(drilldownMap, code)) {
                            data.push({
                                code: code,
                                value: drilldownMap[code]
                            });
                        } else {
                            data.push({
                                code: code,
                                value: 1
                            });
                            console.warn(code + " does not exist in drilldownMap, something went wrong?");
                        }
                    });

                    new Highcharts.mapChart(elementId, getMapOptions(data, mapData));

                    initializeSelectivity();
                });

                /**
                 * Selection handler for regions and prefectures. Uses the given function to create the new item
                 * to give to selectivity to select
                 * @param e         Highcharts event
                 * @param newItem   Function to create a selectivity item
                 */
                var selectionHandler = function(e, newItem) {
                    var clickedPoint = e.target;

                    // Get currently selected vales from Selectivity
                    var selectedValues = $(selectivity).selectivity("data");

                    // Find the name of the clicked point and add it to the selected values
                    var item = regions[clickedPoint.code];  // this object contains a "name" attribute

                    selectedValues.push(newItem(clickedPoint, item));

                    // Set the new selected data in selectivity (do not trigger change event to prevent loop)
                    $(selectivity).selectivity("data", selectedValues, {
                        triggerChange: false
                    });

                    // Redraw selectivity to show the new selection
                    $(selectivity).selectivity("rerenderSelection");

                    // Redraw the chart to show updated tooltip for the selected point
                    setTimeout(function() {
                        clickedPoint.series.chart.redraw();
                    }, 0);
                };

                /**
                 * Unselection handler for regions and prefectures. Uses the given function to remove the
                 * unselected values from the Selectivity selection
                 * @param e             Highcharts event
                 * @param updateValues  Function that removes the unselected point from a list
                 */
                var unselectionHandler = function(e, updateValues) {
                    var pointToUnselect = e.target;

                    // Get currently selected vales from Selectivity
                    var selectedValues = $(selectivity).selectivity("data");

                    // Remove the clicked point from the selected values
                    selectedValues = updateValues(selectedValues, pointToUnselect);

                    // Set the new selected data in selectivity (do not trigger change event to prevent loop)
                    $(selectivity).selectivity("data", selectedValues, {
                        triggerChange: false
                    });

                    // Redraw selectivity to show the new selection
                    $(selectivity).selectivity("rerenderSelection");
                };

                /**
                 * Handles the selection of a region on the Highmaps chart
                 */
                var regionSelectionHandler = function(e) {
                    selectionHandler(e, function(point, item) {
                        return {
                            id: point.code,
                            text: item.name
                        }
                    });
                };

                /**
                 * Handle the unselection of a region on the Highmaps chart
                 * @param e
                 */
                var regionUnselectionHandler = function(e) {
                    unselectionHandler(e, function(selectedValues, clickedPoint) {
                        return _.reject(selectedValues, function(val) {
                            return val.id == clickedPoint.code;
                        });
                    })
                };

                /**
                 * Handle the selection of a prefecture
                 * @param e
                 */
                var prefectureSelectionHandler = function(e) {
                    selectionHandler(e, function(point, item) {
                        return {
                            id: point.NAME_ENG,
                            text: point.NAME_ENG
                        }
                    });
                };

                /**
                 * Handle the unselection of a prefecture
                 * @param e
                 */
                var prefectureUnselectionHandler = function(e) {
                    unselectionHandler(e, function(selectedValues, pointToUnselect) {
                        return _.reject(selectedValues, function(val) {
                            return val.id == pointToUnselect.NAME_ENG;
                        });
                    });
                };

                /**
                 * Create and return the options for the highmaps chart
                 * @param data
                 * @param mapData
                 * @returns {*}
                 */
                var getMapOptions = function(data, mapData) {
                    return {
                        chart: {
                            height: elementH,
                            events: {
                                drilldown: drilldown,
                                drillup: drillup
                            }
                        },
                        legend: { enabled: false },
                        title: {
                            text: 'Greece'
                        },
                        tooltip: {
                            enabled: true,
                            pointFormatter: function() {
                                if (_.has(this, "selected") && this.selected == true) {
                                    return "" + this.name + ": " + this.value +
                                        '
(click again to drilldown)' +
                                        '';
                                } else {
                                    return "" + this.name + ": " + this.value;
                                }
                            }
                        },
                        mapNavigation: {
                            enabled: true,
                            enableMouseWheelZoom: true,
                            enableDoubleClickZoomTo: false,
                            enableDoubleClickZoom: false
                        },
                        colorAxis: {
                            min: 1,
                            type: "logarithmic",
                            minColor: '#FFFFFF',
                            maxColor: '#063798',
                            stops: [
                                [0, '#FFFFFF'],
                                [1, '#063798']
                            ]
                        },
                        series: [{
                            data: data,
                            mapData: mapData,
                            dataLabels: {
                                enabled: true,
                                format: '{point.properties.name}'
                            },
                            joinBy: ['hasc', 'code'],
                            keys: ['hasc', 'value'],
                            name: "Regions of Greece",
                            allowPointSelect: true,
                            states: states,
                            point: {
                                events: {
                                    select: regionSelectionHandler,
                                    unselect: regionUnselectionHandler
                                }
                            }
                        }],
                        drilldown: {
                            activeDataLabelStyle: {
                                color: '#FFFFFF',
                                textDecoration: 'none',
                                textShadow: '0px 1px 3px black'
                            },
                            drillUpButton: {
                                relativeTo: 'spacingBox',
                                position: {
                                    x: 0,
                                    y: 60
                                }
                            }
                        }
                    };
                };

                /**
                 * Get the regions of a country with their prefectures and names, and return them
                 * as an array of items for Selectivity.js
                 * @param regions
                 * @returns {Array}
                 */
                var getSelectivityItemsFromRegions = function(regions) {
                    // Variable to hold the selectivity items
                    var items = [];

                    _.each(regions, function(region, key) {
                        // Add the actual region to the items
                        items.push({
                            id: key,
                            text: region.name
                        });

                        // Add the region's prefectures to the items
                        _.each(region.prefectures, function(pref) {
                            items.push({
                                id: pref,
                                text: pref
                            });
                        });
                    });

                    return items;
                };

                /**
                 * Initialize Selectivity dropdown for region or prefecture selection
                 */
                var initializeSelectivity = function() {
                    // Use jQuery to initialize Selectivity
                    var dropdownContainer = _.first(angular.element(element[0].querySelector('.selectivity-container')));

                    selectivity = $(dropdownContainer).selectivity({
                        items: getSelectivityItemsFromRegions(regions),
                        multiple: true,
                        placeholder: 'Type to search a region or prefecture'
                    });
                };
            }
        };
    }
]);
<commit_msg>Unselect prefectures when drilling up<commit_after>angular.module('yds').directive('ydsRegionSelectorGr', ['Data', '$q',
    function (Data, $q) {
        return {
            restrict: 'E',
            scope: {
                elementH:'@'    // Height of the component in pixels
            },
            templateUrl: ((typeof Drupal != 'undefined')? Drupal.settings.basePath  + Drupal.settings.yds_project.modulePath  +'/' :'') + 'templates/region-selector-gr.html',
            link: function (scope, element) {
                var elementH = parseInt(scope.elementH);

                var regionSelContainer = angular.element(element[0].querySelector('.region-selector-container'));

                //create a random id for the element that will render the plot
                var elementId = "regionsel" + Data.createRandomId();
                regionSelContainer[0].id = elementId;

                //check if the component's height attr is defined, else assign default value
                if(_.isUndefined(elementH) || _.isNaN(elementH))
                    elementH = 300;

                // Selectivity instance
                var selectivity = null;

                // Declare states of map points object, used in the configuration of the map later
                var states = {
                    hover: {
                        color: '#e5ed04'
                    },
                    select: {
                        color: '#a4edba',
                        borderColor: 'black',
                        dashStyle: 'shortdot'
                    }
                };

                // Declare object with regions
                var regions = {
                    "GR.TS": {
                        name: "Thessalia",
                        prefectures: [
                            "N. MAGNISIAS",
                            "N. KARDITSAS",
                            "N. LARISAS",
                            "N. TRIKALON"
                        ]
                    },
                    "GR.AT": {
                        name: "Attiki",
                        prefectures: [
                            "N. PIREOS KE NISON",
                            "N. ANATOLIKIS ATTIKIS",
                            "N. DYTIKIS ATTIKIS",
                            "N. ATHINON"
                        ]
                    },
                    "GR.GC": {
                        name: "Sterea Ellada",
                        prefectures: [
                            "N. VIOTIAS",
                            "N. EVVIAS",
                            "N. EVRYTANIAS",
                            "N. FOKIDAS",
                            "N. FTHIOTIDAS"
                        ]
                    },
                    "GR.MC": {
                        name: "Kentriki Makedonia",
                        prefectures: [
                            "N. IMATHIAS",
                            "N. THESSALONIKIS",
                            "N. KILKIS",
                            "N. PELLAS",
                            "N. PIERIAS",
                            "N. SERRON",
                            "N. CHALKIDIKIS"
                        ]
                    },
                    "GR.CR": {
                        name: "Kriti",
                        prefectures: [
                            "N. CHANION",
                            "N. IRAKLIOU",
                            "N. LASITHIOU",
                            "N. RETHYMNOU"
                        ]
                    },
                    "GR.MT": {
                        name: "Anatoliki Makedonia kai Thraki",
                        prefectures: [
                            "N. DRAMAS",
                            "N. EVROU",
                            "N. KAVALAS",
                            "N. XANTHIS",
                            "N. RODOPIS"
                        ]
                    },
                    "GR.EP": {
                        name: "Ipeiros",
                        prefectures: [
                            "N. ARTAS",
                            "N. IOANNINON",
                            "N. PREVEZAS",
                            "N. THESPROTIAS"
                        ]
                    },
                    "GR.II": {
                        name: "Ionioi Nisoi",
                        prefectures: [
                            "N. KERKYRAS",
                            "N. KEFALLONIAS",
                            "N. LEFKADAS",
                            "N. ZAKYNTHOU"
                        ]
                    },
                    "GR.AN": {
                        name: "Voreio Aigaio",
                        prefectures: [
                            "N. CHIOU",
                            "N. SAMOU",
                            "N. LESVOU"
                        ]
                    },
                    "GR.PP": {
                        name: "Peloponnisos",
                        prefectures: [
                            "N. ARKADIAS",
                            "N. ARGOLIDAS",
                            "N. KORINTHOU",
                            "N. LAKONIAS",
                            "N. MESSINIAS"
                        ]
                    },
                    "GR.AS": {
                        name: "Notio Aigaio",
                        prefectures: [
                            "N. KYKLADON",
                            "N. DODEKANISON"
                        ]
                    },
                    "GR.GW": {
                        name: "Dytiki Ellada",
                        prefectures: [
                            "N. ACHAIAS",
                            "N. ETOLOAKARNANIAS",
                            "N. ILIAS"
                        ]
                    },
                    "GR.MW": {
                        name: "Dytiki Makedonia",
                        prefectures: [
                            "N. FLORINAS",
                            "N. GREVENON",
                            "N. KASTORIAS",
                            "N. KOZANIS"
                        ]
                    },
                    "GR.MA": {
                        name: "Ayion Oros",
                        prefectures: [
                            "AGIO OROS"
                        ]
                    }
                };

                /**
                 * Callback for when drillup happens. Clears the selected points from the chart,
                 * and sets the chart's subtitle to empty. "this" refers to the Highcharts Chart
                 */
                var drillup = function () {
                    // Remove any selected prefectures from Selectivity selection
                    var selData = $(selectivity).selectivity("data");

                    // Keep only regions (reject prefectures)
                    selData = _.filter(selData, function(item) {
                        return _.has(regions, item.id);
                    });

                    // Set new data to Selectivity and set the chart subtitle to empty
                    $(selectivity).selectivity("data", selData);

                    this.setTitle(null, {text: ''});
                };

                /**
                 * Callback for when drilldown happens. Gets the drilled-down point, and creates the series that should
                 * be shown based on the drilldownMap
                 * @param e
                 */
                var drilldown = function (e) {
                    if (!e.seriesOptions  && e.point.selected) {
                        var chart = this,
                            mapKey = e.point.drilldown,
                            regionName = e.point.name;
                        chart.showLoading("Loading...");

                        Data.getGeoJSON("high", mapKey).then(function(response) {
                            var mapData = response;
                            var drilldownData = [];

                            // For each prefecture to display, create a value of 1 for it so it is colored
                            $.each(mapData.features, function () {
                                drilldownData.push({
                                    name: this.properties.NAME_ENG,
                                    value: 1
                                });
                            });

                            // Hide loading and add series
                            chart.hideLoading();
                            chart.addSeriesAsDrilldown(e.point, {
                                name: regionName,
                                data: drilldownData,
                                mapData: mapData,
                                joinBy: ['NAME_ENG', "name"],
                                keys: ['NAME_ENG', 'value'],
                                allowPointSelect: true,
                                dataLabels: {
                                    enabled: true,
                                    format: '{point.properties.NAME_ENG}'
                                },
                                tooltip: {
                                    enabled: false,
                                    pointFormatter: function() {
                                        return "" + this.properties.NAME_ENG + "";
                                    }
                                },
                                point: {
                                    events: {
                                        select: prefectureSelectionHandler,
                                        unselect: prefectureUnselectionHandler
                                    }
                                },
                                states: states
                            });
                        });
                    }

                    this.setTitle(null, {text: regionName});
                };

                // Declare object which shows how many prefectures are in each region of Greece
                var drilldownMap = {
                    "GR.TS": 4,
                    "GR.AT": 4,
                    "GR.GC": 5,
                    "GR.MC": 7,
                    "GR.CR": 4,
                    "GR.MT": 5,
                    "GR.EP": 4,
                    "GR.II": 4,
                    "GR.AN": 3,
                    "GR.PP": 5,
                    "GR.AS": 2,
                    "GR.GW": 3,
                    "GR.MW": 4,
                    "GR.MA": 1
                };

                // Get low detail Greece map
                Data.getGeoJSON("low", null).then(function(response) {
                    Highcharts.maps["countries/gr-low-res"] = response;

                    // Get low detail map data
                    var mapData = Highcharts.geojson(Highcharts.maps['countries/gr-low-res']);
                    var data = [];

                    _.each(mapData, function (item) {
                        var code = item.properties.hasc;
                        item.drilldown = code;
                        if (_.has(drilldownMap, code)) {
                            data.push({
                                code: code,
                                value: drilldownMap[code]
                            });
                        } else {
                            data.push({
                                code: code,
                                value: 1
                            });
                            console.warn(code + " does not exist in drilldownMap, something went wrong?");
                        }
                    });

                    new Highcharts.mapChart(elementId, getMapOptions(data, mapData));

                    initializeSelectivity();
                });

                /**
                 * Selection handler for regions and prefectures. Uses the given function to create the new item
                 * to give to selectivity to select
                 * @param e         Highcharts event
                 * @param newItem   Function to create a selectivity item
                 */
                var selectionHandler = function(e, newItem) {
                    var clickedPoint = e.target;

                    // Get currently selected vales from Selectivity
                    var selectedValues = $(selectivity).selectivity("data");

                    // Find the name of the clicked point and add it to the selected values
                    var item = regions[clickedPoint.code];  // this object contains a "name" attribute

                    selectedValues.push(newItem(clickedPoint, item));

                    // Set the new selected data in selectivity (do not trigger change event to prevent loop)
                    $(selectivity).selectivity("data", selectedValues, {
                        triggerChange: false
                    });

                    // Redraw selectivity to show the new selection
                    $(selectivity).selectivity("rerenderSelection");

                    // Redraw the chart to show updated tooltip for the selected point
                    setTimeout(function() {
                        clickedPoint.series.chart.redraw();
                    }, 0);
                };

                /**
                 * Unselection handler for regions and prefectures. Uses the given function to remove the
                 * unselected values from the Selectivity selection
                 * @param e             Highcharts event
                 * @param updateValues  Function that removes the unselected point from a list
                 */
                var unselectionHandler = function(e, updateValues) {
                    var pointToUnselect = e.target;

                    // Get currently selected vales from Selectivity
                    var selectedValues = $(selectivity).selectivity("data");

                    // Remove the clicked point from the selected values
                    selectedValues = updateValues(selectedValues, pointToUnselect);

                    // Set the new selected data in selectivity (do not trigger change event to prevent loop)
                    $(selectivity).selectivity("data", selectedValues, {
                        triggerChange: false
                    });

                    // Redraw selectivity to show the new selection
                    $(selectivity).selectivity("rerenderSelection");
                };

                /**
                 * Handles the selection of a region on the Highmaps chart
                 */
                var regionSelectionHandler = function(e) {
                    selectionHandler(e, function(point, item) {
                        return {
                            id: point.code,
                            text: item.name
                        }
                    });
                };

                /**
                 * Handle the unselection of a region on the Highmaps chart
                 * @param e
                 */
                var regionUnselectionHandler = function(e) {
                    unselectionHandler(e, function(selectedValues, clickedPoint) {
                        return _.reject(selectedValues, function(val) {
                            return val.id == clickedPoint.code;
                        });
                    })
                };

                /**
                 * Handle the selection of a prefecture
                 * @param e
                 */
                var prefectureSelectionHandler = function(e) {
                    selectionHandler(e, function(point, item) {
                        return {
                            id: point.NAME_ENG,
                            text: point.NAME_ENG
                        }
                    });
                };

                /**
                 * Handle the unselection of a prefecture
                 * @param e
                 */
                var prefectureUnselectionHandler = function(e) {
                    unselectionHandler(e, function(selectedValues, pointToUnselect) {
                        return _.reject(selectedValues, function(val) {
                            return val.id == pointToUnselect.NAME_ENG;
                        });
                    });
                };

                /**
                 * Create and return the options for the highmaps chart
                 * @param data
                 * @param mapData
                 * @returns {*}
                 */
                var getMapOptions = function(data, mapData) {
                    return {
                        chart: {
                            height: elementH,
                            events: {
                                drilldown: drilldown,
                                drillup: drillup
                            }
                        },
                        legend: { enabled: false },
                        title: {
                            text: 'Greece'
                        },
                        tooltip: {
                            enabled: true,
                            pointFormatter: function() {
                                if (_.has(this, "selected") && this.selected == true) {
                                    return "" + this.name + ": " + this.value +
                                        '
(click again to drilldown)' +
                                        '';
                                } else {
                                    return "" + this.name + ": " + this.value;
                                }
                            }
                        },
                        mapNavigation: {
                            enabled: true,
                            enableMouseWheelZoom: true,
                            enableDoubleClickZoomTo: false,
                            enableDoubleClickZoom: false
                        },
                        colorAxis: {
                            min: 1,
                            type: "logarithmic",
                            minColor: '#FFFFFF',
                            maxColor: '#063798',
                            stops: [
                                [0, '#FFFFFF'],
                                [1, '#063798']
                            ]
                        },
                        series: [{
                            data: data,
                            mapData: mapData,
                            dataLabels: {
                                enabled: true,
                                format: '{point.properties.name}'
                            },
                            joinBy: ['hasc', 'code'],
                            keys: ['hasc', 'value'],
                            name: "Regions of Greece",
                            allowPointSelect: true,
                            states: states,
                            point: {
                                events: {
                                    select: regionSelectionHandler,
                                    unselect: regionUnselectionHandler
                                }
                            }
                        }],
                        drilldown: {
                            activeDataLabelStyle: {
                                color: '#FFFFFF',
                                textDecoration: 'none',
                                textShadow: '0px 1px 3px black'
                            },
                            drillUpButton: {
                                relativeTo: 'spacingBox',
                                position: {
                                    x: 0,
                                    y: 60
                                }
                            }
                        }
                    };
                };

                /**
                 * Get the regions of a country with their prefectures and names, and return them
                 * as an array of items for Selectivity.js
                 * @param regions
                 * @returns {Array}
                 */
                var getSelectivityItemsFromRegions = function(regions) {
                    // Variable to hold the selectivity items
                    var items = [];

                    _.each(regions, function(region, key) {
                        // Add the actual region to the items
                        items.push({
                            id: key,
                            text: region.name
                        });

                        // Add the region's prefectures to the items
                        _.each(region.prefectures, function(pref) {
                            items.push({
                                id: pref,
                                text: pref
                            });
                        });
                    });

                    return items;
                };

                /**
                 * Initialize Selectivity dropdown for region or prefecture selection
                 */
                var initializeSelectivity = function() {
                    // Use jQuery to initialize Selectivity
                    var dropdownContainer = _.first(angular.element(element[0].querySelector('.selectivity-container')));

                    selectivity = $(dropdownContainer).selectivity({
                        items: getSelectivityItemsFromRegions(regions),
                        multiple: true,
                        placeholder: 'Type to search a region or prefecture'
                    });
                };
            }
        };
    }
]);
<|endoftext|>


<commit_before>// Separate Numbers with Commas in JavaScript **Pairing Challenge**

// I worked on this challenge with: .

// Pseudocode
//separateComma(1569743) == "1,569,743"

// Initial Solution

// var number = 123456789;

// function seprateComma(num) {

// // var num = 123456789;

// num = num.toString().split("").reverse().join("");;
// console.log(num)

// var revNum = num;

// var corNum = [];

// //Create a way to take 3 add a comma
// corNum.push(revNum.substring(0,3) + ",");
// console.log(corNum);
// //Remove 3 from reverse number
// revNum = (revNum.slice(3));

// corNum.push(revNum.substring(0,3) + ",");
// console.log(corNum);
// revNum = (revNum.slice(3));

// //Driver code
// console.log(revNum.length)

// // If less than 4 do this.
// corNum.push(revNum.substring(0,3));

// corNum = corNum.join("");
// corNum = corNum.split("").reverse();
// corNum = corNum.join("")

// console.log(corNum)

// };

// //Driver code
// seprateComma(number);

// Refactored Solution

function seprateComma(num) {

  num = num.toString().split("").reverse().join("");

  var revNum = num;
  var corNum = [];

  for ( ; revNum.length >= 4;){
    corNum.push(revNum.substring(0,3) + ",");
    revNum = (revNum.slice(3));
    }

  corNum.push(revNum.substring());

  console.log(corNum.join("").split("").reverse().join(""));

};

// Your Own Tests (OPTIONAL)

//Driver code
seprateComma(123456111117189);

// Reflection

// What was it like to approach the problem from the perspective of JavaScript? Did you approach the problem differently?

// I ran into so much issues with JavaScript.  There aren’t as much build in methods as Ruby and a lot of things was very foreign to me because I never learn JavaScript and its a big world out there.  But with the knowledge of Ruby’s concepts we were able to tackle this problem.

// What did you learn about iterating over arrays in JavaScript?

//   I learned how to use a FOR loop and what I was able to do with it.  I didn’t do the index like most people did.  I took a different approach to the problem.

// What was different about solving this problem in JavaScript?

//   I had to use different loop but the concept was pretty much the same as the last one we did in Ruby.  I think I did a better job in JavaScript even with less tools.  I hope its just skill level of programing has increased a bit.

// What built-in methods did you find to incorporate in your refactored solution?

//   I used the for loop.  Instead of using the whole 3 argument of the for loop I only used the middle condition of the for loop which made it work.  I was fuzzy about knowing how to use the FOR loop but I was able to get some clarification on it.<commit_msg>added notes to comma<commit_after>// Separate Numbers with Commas in JavaScript **Pairing Challenge**

// I worked on this challenge with: with Sanderfer Chau

// Pseudocode
// Take a large number and add commas
// take the NUMBER and turn it into a STRING, SEPARATE IT, REVERSE IT, AND JOIN IT BACK TOGETHER
// the number now should be reversed.
//
// create an empty container called CorrectNumber
// take the last three and add a comma to it and insert it to the container
// subtract the first 3 from the Revsered number
// Do this till the LENGTH of the number is 4 or less.
// Then add the rest of the numbers to the empty container if there is any.
//
//Take the empty contrainer, JOIN it together, SEPARATE IT, REVERSE IT, JOIN IT.  Then call it.

// Initial Solution

// var number = 123456789;

// function seprateComma(num) {

// // var num = 123456789;

// num = num.toString().split("").reverse().join("");;
// console.log(num)

// var revNum = num;

// var corNum = [];

// //Create a way to take 3 add a comma
// corNum.push(revNum.substring(0,3) + ",");
// console.log(corNum);
// //Remove 3 from reverse number
// revNum = (revNum.slice(3));

// corNum.push(revNum.substring(0,3) + ",");
// console.log(corNum);
// revNum = (revNum.slice(3));

// //Driver code
// console.log(revNum.length)

// // If less than 4 do this.
// corNum.push(revNum.substring(0,3));

// corNum = corNum.join("");
// corNum = corNum.split("").reverse();
// corNum = corNum.join("")

// console.log(corNum)

// };

// //Driver code
// seprateComma(number);

// Refactored Solution

function seprateComma(num) {

  num = num.toString().split("").reverse().join("");

  var revNum = num;
  var corNum = [];

  for ( ; revNum.length >= 4;){
    corNum.push(revNum.substring(0,3) + ",");
    revNum = (revNum.slice(3));
    }

  corNum.push(revNum.substring());

  console.log(corNum.join("").split("").reverse().join(""));

};

// Your Own Tests (OPTIONAL)

//Driver code
seprateComma(123456111117189);

// Reflection

// What was it like to approach the problem from the perspective of JavaScript? Did you approach the problem differently?

// I ran into so much issues with JavaScript.  There aren’t as much build in methods as Ruby and a lot of things was very foreign to me because I never learn JavaScript and its a big world out there.  But with the knowledge of Ruby’s concepts we were able to tackle this problem.

// What did you learn about iterating over arrays in JavaScript?

//   I learned how to use a FOR loop and what I was able to do with it.  I didn’t do the index like most people did.  I took a different approach to the problem.

// What was different about solving this problem in JavaScript?

//   I had to use different loop but the concept was pretty much the same as the last one we did in Ruby.  I think I did a better job in JavaScript even with less tools.  I hope its just skill level of programing has increased a bit.

// What built-in methods did you find to incorporate in your refactored solution?

//   I used the for loop.  Instead of using the whole 3 argument of the for loop I only used the middle condition of the for loop which made it work.  I was fuzzy about knowing how to use the FOR loop but I was able to get some clarification on it.<|endoftext|>


<commit_before>Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");
var EventUtils = Components.utils.import("resource://zotero-unit/EventUtils.jsm");

var ZoteroUnit = Components.classes["@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit"].
	             getService(Components.interfaces.nsISupports).
	             wrappedJSObject;
var dump = ZoteroUnit.dump;

function quit(failed) {
	// Quit with exit status
	if(!failed) {
		OS.File.writeAtomic(FileUtils.getFile("ProfD", ["success"]).path, new Uint8Array(0));
	}
	if(!ZoteroUnit.noquit) {
		setTimeout(function () {
			Components.classes['@mozilla.org/toolkit/app-startup;1']
				.getService(Components.interfaces.nsIAppStartup)
				.quit(Components.interfaces.nsIAppStartup.eForceQuit);
		}, 250);
	}
}

function Reporter(runner) {
	var indents = 0, passed = 0, failed = 0;

	function indent() {
		return Array(indents).join('  ');
	}

	runner.on('start', function(){});

	runner.on('suite', function(suite){
		++indents;
		dump(indent()+suite.title+"\n");
	});

	runner.on('suite end', function(suite){
		--indents;
		if (1 == indents) dump("\n");
	});

	runner.on('pending', function(test){
		dump(indent()+"pending  -"+test.title);
	});

	runner.on('pass', function(test){
		passed++;
		var msg = "\r"+indent()+Mocha.reporters.Base.symbols.ok+" "+test.title;
		if ('fast' != test.speed) {
			msg += " ("+Math.round(test.duration)+" ms)";
		}
		dump(msg+"\n");
	});

	runner.on('fail', function(test, err){
		failed++;
		dump("\r" + indent()
			// Dark red X for errors
			+ "\033[31;40m" + Mocha.reporters.Base.symbols.err + "\033[0m"
			+ " " + test.title + "\n"
			+ indent() + "  " + err.toString() + " at\n"
			+ indent() + "    " + err.stack.replace("\n", "\n" + indent() + "    ", "g"));
	});

	runner.on('end', function() {
		dump(passed+"/"+(passed+failed)+" tests passed.\n");
		quit(failed != 0);
	});
}

// Setup Mocha
mocha.setup({ui:"bdd", reporter:Reporter});

// Enable Bluebird generator support in Mocha
(function () {
	var Runnable = Mocha.Runnable;
	var run = Runnable.prototype.run;
	Runnable.prototype.run = function (fn) {
		if (this.fn.constructor.name === 'GeneratorFunction') {
			this.fn = Zotero.Promise.coroutine(this.fn);
		}
		return run.call(this, fn);
	};
})();

var assert = chai.assert,
    expect = chai.expect;

// Set up tests to run
var run = true;
if(ZoteroUnit.tests) {
	var testDirectory = getTestDataDirectory().parent,
	    testFiles = [];
	if(ZoteroUnit.tests == "all") {
		var enumerator = testDirectory.directoryEntries;
		while(enumerator.hasMoreElements()) {
			var file = enumerator.getNext().QueryInterface(Components.interfaces.nsIFile);
			if(file.leafName.endsWith(".js")) {
				testFiles.push(file.leafName);
			}
		}
	} else {
		var specifiedTests = ZoteroUnit.tests.split(",");
		for (let test of specifiedTests) {
			// Allow foo, fooTest, fooTest.js, and tests/fooTest.js
			test = test.replace(/\.js$/, "");
			test = test.replace(/Test$/, "");
			test = test.replace(/^tests[/\\]/, "");
			let fname = test + "Test.js";
			let file = testDirectory.clone();
			file.append(fname);
			if (!file.exists()) {
				dump("Invalid test file "+test+"\n");
				run = false;
				quit(true);
			}
			testFiles.push(fname);
		}
	}

	for(var fname of testFiles) {
		var el = document.createElement("script");
		el.type = "application/javascript;version=1.8";
		el.src = "resource://zotero-unit-tests/"+fname;
		document.body.appendChild(el);
	}
}

if(run) {
	window.onload = function() {
		Zotero.Schema.schemaUpdatePromise.then(function() {
			mocha.run();
		});
	};
}<commit_msg>Increase default timeout to 5 seconds from 2<commit_after>Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");
var EventUtils = Components.utils.import("resource://zotero-unit/EventUtils.jsm");

var ZoteroUnit = Components.classes["@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit"].
	             getService(Components.interfaces.nsISupports).
	             wrappedJSObject;
var dump = ZoteroUnit.dump;

function quit(failed) {
	// Quit with exit status
	if(!failed) {
		OS.File.writeAtomic(FileUtils.getFile("ProfD", ["success"]).path, new Uint8Array(0));
	}
	if(!ZoteroUnit.noquit) {
		setTimeout(function () {
			Components.classes['@mozilla.org/toolkit/app-startup;1']
				.getService(Components.interfaces.nsIAppStartup)
				.quit(Components.interfaces.nsIAppStartup.eForceQuit);
		}, 250);
	}
}

function Reporter(runner) {
	var indents = 0, passed = 0, failed = 0;

	function indent() {
		return Array(indents).join('  ');
	}

	runner.on('start', function(){});

	runner.on('suite', function(suite){
		++indents;
		dump(indent()+suite.title+"\n");
	});

	runner.on('suite end', function(suite){
		--indents;
		if (1 == indents) dump("\n");
	});

	runner.on('pending', function(test){
		dump(indent()+"pending  -"+test.title);
	});

	runner.on('pass', function(test){
		passed++;
		var msg = "\r"+indent()+Mocha.reporters.Base.symbols.ok+" "+test.title;
		if ('fast' != test.speed) {
			msg += " ("+Math.round(test.duration)+" ms)";
		}
		dump(msg+"\n");
	});

	runner.on('fail', function(test, err){
		failed++;
		dump("\r" + indent()
			// Dark red X for errors
			+ "\033[31;40m" + Mocha.reporters.Base.symbols.err + "\033[0m"
			+ " " + test.title + "\n"
			+ indent() + "  " + err.toString() + " at\n"
			+ indent() + "    " + err.stack.replace("\n", "\n" + indent() + "    ", "g"));
	});

	runner.on('end', function() {
		dump(passed+"/"+(passed+failed)+" tests passed.\n");
		quit(failed != 0);
	});
}

// Setup Mocha
mocha.setup({
	ui: "bdd",
	reporter: Reporter,
	timeout: 5000
});

// Enable Bluebird generator support in Mocha
(function () {
	var Runnable = Mocha.Runnable;
	var run = Runnable.prototype.run;
	Runnable.prototype.run = function (fn) {
		if (this.fn.constructor.name === 'GeneratorFunction') {
			this.fn = Zotero.Promise.coroutine(this.fn);
		}
		return run.call(this, fn);
	};
})();

var assert = chai.assert,
    expect = chai.expect;

// Set up tests to run
var run = true;
if(ZoteroUnit.tests) {
	var testDirectory = getTestDataDirectory().parent,
	    testFiles = [];
	if(ZoteroUnit.tests == "all") {
		var enumerator = testDirectory.directoryEntries;
		while(enumerator.hasMoreElements()) {
			var file = enumerator.getNext().QueryInterface(Components.interfaces.nsIFile);
			if(file.leafName.endsWith(".js")) {
				testFiles.push(file.leafName);
			}
		}
	} else {
		var specifiedTests = ZoteroUnit.tests.split(",");
		for (let test of specifiedTests) {
			// Allow foo, fooTest, fooTest.js, and tests/fooTest.js
			test = test.replace(/\.js$/, "");
			test = test.replace(/Test$/, "");
			test = test.replace(/^tests[/\\]/, "");
			let fname = test + "Test.js";
			let file = testDirectory.clone();
			file.append(fname);
			if (!file.exists()) {
				dump("Invalid test file "+test+"\n");
				run = false;
				quit(true);
			}
			testFiles.push(fname);
		}
	}

	for(var fname of testFiles) {
		var el = document.createElement("script");
		el.type = "application/javascript;version=1.8";
		el.src = "resource://zotero-unit-tests/"+fname;
		document.body.appendChild(el);
	}
}

if(run) {
	window.onload = function() {
		Zotero.Schema.schemaUpdatePromise.then(function() {
			mocha.run();
		});
	};
}<|endoftext|>


<commit_before>import React from 'react';
import ApplicationStore from '../stores/ApplicationStore';
import ga from '../plugins/googleAnalytics/ga';

let hook = require('css-modules-require-hook');

hook({
    generateScopedName: '[hash:base64:5]',
});

class DefaultHTMLLayout extends React.Component {
    render() {
        let user = this.props.context.getUser();
        return (

                <meta charSet="utf-8" />
                <title>{this.props.context.getStore(ApplicationStore).getPageTitle()}</title>
                <meta name="viewport" content="width=device-width, user-scalable=no" />
                <link href="/custom_modules/custom-semantic-ui/dist/semantic.min.css" rel="stylesheet" type="text/css" />
                <link href="/assets/css/custom.css" rel="stylesheet" type="text/css" />
                <link href="/sweetalert2/dist/sweetalert2.min.css" rel="stylesheet" type="text/css" />
                <link href="/custom_modules/reveal.js/css/reveal.css" rel="stylesheet" type="text/css" />
                <link href="/glidejs/dist/css/glide.core.min.css" rel="stylesheet" type="text/css" />
                <link href="/glidejs/dist/css/glide.theme.min.css" rel="stylesheet" type="text/css" />
                { user ?
                  <link href="/jquery-ui-dist/jquery-ui.min.css" rel="stylesheet" type="text/css" />
                  : <meta name="placeholder" content="jquery-ui" />
                }
                { user ?
                  <link href="/font-awesome/css/font-awesome.css" rel="stylesheet" type="text/css" />
                  : <meta name="placeholder" content="font-awesome" />
                }
                { user ?
                  <link href="/jquery-contextmenu/dist/jquery.contextMenu.min.css" rel="stylesheet" type="text/css" />
                  : <meta name="placeholder" content="jquery.contextMenu" />
                }
                {/* Vendors css bundle */
                    this.props.addAssets ? <link href="/public/css/vendor.bundle.css" rel="stylesheet" type="text/css" />:
                }
                {/*<link href="/custom_modules/reveal.js/css/print/pdf.css" rel="stylesheet" type="text/css" />*/}
                {/* we add this config option for mathjax so we can better control when the typesetting will occur */}

                {/* Following are added only to support IE browser */}

                {/* Above are added only to support IE browser */}

                {/* TODO: load specific parts of jquery UI for performance */}
                { user ?

                  : ''
                }

                {/* All external vendors bundle*/
                    this.props.addAssets ?  : ''
                }
                { user ?

                  : ''
                }

                {/* Adding for dependency loading with reveal.js*/}

                {/* Main app bundle */}

                { user ?

                  : ''
                }
                {/*
                */}
                {/**/}

                {/* Following are added only to support IE browser */}

                {/* Above are added only to support IE browser */}

                {/* TODO: load specific parts of jquery UI for performance */}
                { user ?

                  : ''
                }

                {/* All external vendors bundle*/
                    this.props.addAssets ?  : ''
                }
                { user ?

                  : ''
                }

                {/* Adding for dependency loading with reveal.js*/}

                {/* Main app bundle */}

                { user ?

                  : ''
                }
                {/*
                */}
                {/**/}


<commit_before>import React from 'react';

export default React.createClass({

	canvasPlane : '',
	context : '',

	getInitialState(){
		return {
			started: false
		}
	},

	componentDidMount() {
		this.canvasPlane = this.refs.drawPlane.getDOMNode();
		this.context = this.canvasPlane.getContext('2d');
		this.canvasPlane.addEventListener('mousedown', this.drawCanvas);
		this.canvasPlane.addEventListener('mousemove', this.drawCanvas);
		this.canvasPlane.addEventListener('mouseup', this.drawCanvas);
		this.props.socket.on('sendURL', data => {
			this.props.handleImageRendering(data.dataURL);
		});
	},

	componentWillUnmount() {
		this.canvasPlane.removeEventListener('mousedown', this.drawCanvas);
		this.canvasPlane.removeEventListener('mousemove', this.drawCanvas);
		this.canvasPlane.removeEventListener('mouseup', this.drawCanvas);
	},

	_mousedown(x, y) {
		this.context.beginPath();
		this.context.moveTo(x, y);
		this.setState({started: true});
	},

	_mousemove(x, y){
		if (this.state.started) {
			this.context.lineTo(x, y);
			this.context.stroke();
		}
	},

	_mouseup(x, y){
		if (this.state.started) {
			this._mousemove(x, y);
			this.setState({started: false});
		}
	},

	drawCanvas(e){
		let x, y;

		if (e.layerX || e.layerX == 0) {
			x = e.layerX;
			y = e.layerY;
		} else if (e.offsetX || e.offsetX == 0) {
			x = e.offsetX;
			y = e.offsetY;
		}

		let func = e.type;
		if (func) {
			this['_'+func](x, y);
		}
	},

	handleClick(e){
		var data = this.canvasPlane.toDataURL();
		this.props.socket.emit('sendPic', {
			'dataURL' : data,
			'name' : this.props.userName
		});
	},

	render() {
		return

Draw the picture using your mouse. Fun!

			<canvas className="draw-area" ref="drawPlane" width="500px" height="300px"/>
			<button className="send-image" onClick={this.handleClick}>Send Image</button>

	}
});
<commit_msg>Canvas Rendering<commit_after>import React from 'react';

export default React.createClass({

	canvasPlane : '',
	context : '',

	getInitialState(){
		return {
			started: false
		}
	},

	componentDidMount() {
		this.canvasPlane = this.refs.drawPlane.getDOMNode();
		this.canvasPlane.addEventListener('mousedown', this.drawCanvas);
		this.canvasPlane.addEventListener('mousemove', this.drawCanvas);
		this.canvasPlane.addEventListener('mouseup', this.drawCanvas);
		this.props.socket.on('sendURL', data => {
			this.props.handleImageRendering(data.dataURL);
		});
	},

	componentWillUnmount() {
		this.canvasPlane.removeEventListener('mousedown', this.drawCanvas);
		this.canvasPlane.removeEventListener('mousemove', this.drawCanvas);
		this.canvasPlane.removeEventListener('mouseup', this.drawCanvas);
	},

	_mousedown(x, y, context) {
		context.beginPath();
		context.moveTo(x, y);
		this.setState({started: true});
	},

	_mousemove(x, y, context){
		if (this.state.started) {
			context.lineTo(x, y);
			context.stroke();
		}
	},

	_mouseup(x, y, context){
		if (this.state.started) {
			this._mousemove(x, y, context);
			this.setState({started: false});
		}
	},

	drawCanvas(e){
		let x, y;
		this.context = this.canvasPlane.getContext('2d');

		if (e.layerX || e.layerX == 0) {
			x = e.layerX;
			y = e.layerY;
		} else if (e.offsetX || e.offsetX == 0) {
			x = e.offsetX;
			y = e.offsetY;
		}

		let func = e.type;
		if (func) {
			this['_'+func](x, y, this.context);
		}
	},

	handleClick(e){
		var data = this.canvasPlane.toDataURL();
		this.context.clearRect(0,0,this.canvasPlane.width,this.canvasPlane.height);
		this.props.socket.emit('sendPic', {
			'dataURL' : data,
			'name' : this.props.userName
		});
	},

	render() {
		return

Draw the picture using your mouse. Fun!

			<canvas className="draw-area" ref="drawPlane" width="500px" height="300px"/>
			<button className="send-image" onClick={this.handleClick}>Send Image</button>

	}
});
<|endoftext|>


<commit_before>/*
 * Unstrap: dropdown.js v1.0.0-1
 * http://unstrap.org/components/dropdown
 * 2015
 * MIT license
 */
define(function () {

	function caret () {
		var c = document.createElement('span');
		c.classList.add('caret');
		return c;
	}

	function extend (elem) {
		var but = elem.querySelector('.dropdown-toggle');
		Object.defineProperty(but, 'value', {
			set: function (val) {
				var li = but.nextSibling.querySelector('[data-value=' + val +']');
				if (li) {
					but._value = val;
					but.textContent = li.textContent || val;
					but.appendChild(caret());
				}
			},
			get: function () {
				 return but._value;
			}
		});
		but.nextSibling.evt('click', function (evt) {
			but.value = evt.target.getAttribute('data-value') || evt.target.textContent;
			evt.target.parentNode.parentNode.parentNode.classList.remove('open');
		})
		but.evt('click', function (evt) {
			var dd = evt.target.parentNode;
			dd.classList.toggle('open');
		})
		return elem;
	}

	return {
		version: '1.0.0',
		name: 'dropdown',
		selectors: ['.bs.dropdown', '.us.dropdown'],
		extend: extend
	}
})
<commit_msg>checkin<commit_after>/*
 * Unstrap: dropdown.js v1.0.0-2
 * http://unstrap.org/components/dropdown
 * 2015
 * MIT license
 */
define(function () {

	function caret () {
		var c = document.createElement('span');
		c.classList.add('caret');
		return c;
	}

	function extend (elem) {
		var but = elem.querySelector('.dropdown-toggle');
		if (!but) return;
		Object.defineProperty(but, 'value', {
			set: function (val) {
				var v, li = this.nextElementSibling.querySelectorAll('li');
				for (var i = 0; i < li.length; i++) {
					v = li.item(i).getAttribute('data-value') || li.item(i).textContent;
					if (val === v) {
						but._value = val;
						but.textContent = li.textContent || val;
						but.appendChild(caret());
					}
				}
			},
			get: function () {
				 return but._value;
			}
		});
		but.nextElementSibling.addEventListener('click', function (evt) {
			but.value = evt.target.getAttribute('data-value') || evt.target.textContent;
			evt.target.parentNode.parentNode.parentNode.classList.remove('open');
		})
		but.addEventListener('click', function (evt) {
			var dd = evt.target.parentNode;
			dd.classList.toggle('open');
		})
		return elem;
	}

	return {
		version: '1.0.0',
		name: 'dropdown',
		selectors: ['.dropdown', '.dropup'],
		extend: extend
	}
});
<|endoftext|>


<commit_before>(function() {
  "use strict";

  /**
   * forEach implementation for Objects/NodeLists/Arrays, automatic type loops and context options
   *
   * @private
   * @author Todd Motto
   * @link https://github.com/toddmotto/foreach
   * @param {Array|Object|NodeList} collection - Collection of items to iterate, could be an Array, Object or NodeList
   * @callback requestCallback      callback   - Callback function for each iteration.
   * @param {Array|Object|NodeList} scope=null - Object/NodeList/Array that forEach is iterating over, to use as the this value when executing callback.
   * @returns {}
   */
  var forEach = function (collection, callback, scope) {
    if (Object.prototype.toString.call(collection) === "[object Object]") {
      for (var prop in collection) {
        if (Object.prototype.hasOwnProperty.call(collection, prop)) {
          callback.call(scope, collection[prop], prop, collection);
        }
      }
    } else {
      for (var i = 0, len = collection.length; i < len; i++) {
        callback.call(scope, collection[i], i, collection);
      }
    }
  };

  /**
  Drop in replace functions for setTimeout() & setInterval() that
  make use of requestAnimationFrame() for performance where available
  http://www.joelambert.co.uk

  Copyright 2011, Joe Lambert.
  Free to use under the MIT license.
  http://www.opensource.org/licenses/mit-license.php
  */

  // requestAnimationFrame() shim by Paul Irish
  // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  window.requestAnimFrame = (function() {
    return window.requestAnimationFrame  ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame    ||
      window.oRequestAnimationFrame      ||
      window.msRequestAnimationFrame     ||
      function(callback, element){
        window.setTimeout(callback, 1000 / 60);
      };
  })();

  /**
   * Behaves the same as setInterval except uses requestAnimationFrame() where possible for better performance
   * @param {function} fn The callback function
   * @param {int} delay The delay in milliseconds
   */
  window.requestInterval = function(fn, delay) {
    if ( ! window.requestAnimationFrame    &&
      ! window.webkitRequestAnimationFrame &&
      ! (window.mozRequestAnimationFrame   && window.mozCancelRequestAnimationFrame) &&
      ! window.oRequestAnimationFrame      &&
      ! window.msRequestAnimationFrame)
        return window.setInterval(fn, delay);

    var start = new Date().getTime(),
        handle = new Object();

    function loop() {
      var current = new Date().getTime(),
        delta = current - start;

      if (delta >= delay) {
        fn.call();
        start = new Date().getTime();
      }

      handle.value = window.requestAnimFrame(loop);
    }

    handle.value = window.requestAnimFrame(loop);
    return handle;
  }

  /**
   * Behaves the same as clearInterval except uses cancelRequestAnimationFrame() where possible for better performance
   * @param {int|object} fn The callback function
   */
  window.clearRequestInterval = function(handle) {
    window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) :
    window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) :
    window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */
    window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) :
    window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) :
    window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) :
    clearInterval(handle);
  };

  /**
   * Behaves the same as setTimeout except uses requestAnimationFrame() where possible for better performance
   * @param {function} fn The callback function
   * @param {int} delay The delay in milliseconds
   */
  window.requestTimeout = function(fn, delay) {
    if ( ! window.requestAnimationFrame    &&
      ! window.webkitRequestAnimationFrame &&
      ! (window.mozRequestAnimationFrame   && window.mozCancelRequestAnimationFrame) && // Firefox 5 ships without cancel support
      ! window.oRequestAnimationFrame      &&
      ! window.msRequestAnimationFrame)
        return window.setTimeout(fn, delay);

    var start = new Date().getTime(),
        handle = new Object();

    function loop() {
      var current = new Date().getTime(),
          delta = current - start;

      delta >= delay ? fn.call() : handle.value = window.requestAnimFrame(loop);
    }

    handle.value = window.requestAnimFrame(loop);
    return handle;
  };

  /**
   * Shuffles array in place.
   * @link http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript
   * @param {Array} a items The array containing the items.
   * @return {Array} a The shuffled array
   */
  function shuffle(array) {
    var j, x, i;

    for (i = array.length; i; i -= 1) {
        j = Math.floor(Math.random() * i);
        x = array[i - 1];
        array[i - 1] = array[j];
        array[j] = x;
    }

    return array;
  }

  /**
           _....----"""----...._
        .-'  o    o    o    o   '-.
       /  o    o    o         o    \
    __/__o___o_ _ o___ _ o_ o_ _ _o_\__
   /                                   \
   \___________________________________/
     \~`-`.__.`-~`._.~`-`~.-~.__.~`-`/
  jgs \                             /
       `-._______________________.-'

   */
  var Hamburgers = {
    make: function() {
      var hamburgers = document.querySelectorAll(".js-hamburger");

      if (hamburgers.length > 0) {
        forEach(hamburgers, function(hamburger) {
          hamburger.addEventListener("click", Hamburgers.clickHandle, false);
        });
      }

      Hamburgers.navAnimate();

      document.querySelector(".js-hint").addEventListener("click", Hamburgers.hintHandle, false);
    },

    clickHandle: function(e) {
      e.preventDefault();

      this.classList.toggle("is-active");
    },

    hintHandle: function(e) {
      e.preventDefault();

      this.parentNode.removeChild(this);

      document.getElementById("hint").classList.add("is-visible");
    },

    navAnimate: function() {
      var classes = [
        "slider", "squeeze", "arrow", "arrowalt", "spin", "elastic", "emphatic", "collapse", "vortex", "boring"
      ];

      shuffle(classes);

      var logo = document.querySelector(".hamburger--header");

      window.requestInterval(function() {
        var current = parseInt(logo.getAttribute("data-class"), 10);

        logo.classList.add("hamburger--" + classes[current]);

        window.requestTimeout(function() {
          logo.classList.add("is-active");

          window.requestTimeout(function() {
            logo.classList.remove("is-active");

            window.requestTimeout(function() {
              logo.classList.remove("hamburger--" + classes[current]);

              var next = current + 1;

              if (next === classes.length) {
                next = 1;
              }
              logo.setAttribute("data-class", next);
            }, 750);
          }, 1000);
        }, 750);
      }, 3250);
    }
  };

  Hamburgers.make();

}());
<commit_msg>Improve header animate.<commit_after>(function() {
  "use strict";

  /**
   * forEach implementation for Objects/NodeLists/Arrays, automatic type loops and context options
   *
   * @private
   * @author Todd Motto
   * @link https://github.com/toddmotto/foreach
   * @param {Array|Object|NodeList} collection - Collection of items to iterate, could be an Array, Object or NodeList
   * @callback requestCallback      callback   - Callback function for each iteration.
   * @param {Array|Object|NodeList} scope=null - Object/NodeList/Array that forEach is iterating over, to use as the this value when executing callback.
   * @returns {}
   */
  var forEach = function (collection, callback, scope) {
    if (Object.prototype.toString.call(collection) === "[object Object]") {
      for (var prop in collection) {
        if (Object.prototype.hasOwnProperty.call(collection, prop)) {
          callback.call(scope, collection[prop], prop, collection);
        }
      }
    } else {
      for (var i = 0, len = collection.length; i < len; i++) {
        callback.call(scope, collection[i], i, collection);
      }
    }
  };

  /**
  Drop in replace functions for setTimeout() & setInterval() that
  make use of requestAnimationFrame() for performance where available
  http://www.joelambert.co.uk

  Copyright 2011, Joe Lambert.
  Free to use under the MIT license.
  http://www.opensource.org/licenses/mit-license.php
  */

  // requestAnimationFrame() shim by Paul Irish
  // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  window.requestAnimFrame = (function() {
    return window.requestAnimationFrame  ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame    ||
      window.oRequestAnimationFrame      ||
      window.msRequestAnimationFrame     ||
      function(callback, element){
        window.setTimeout(callback, 1000 / 60);
      };
  })();

  /**
   * Behaves the same as setInterval except uses requestAnimationFrame() where possible for better performance
   * @param {function} fn The callback function
   * @param {int} delay The delay in milliseconds
   */
  window.requestInterval = function(fn, delay) {
    if ( ! window.requestAnimationFrame    &&
      ! window.webkitRequestAnimationFrame &&
      ! (window.mozRequestAnimationFrame   && window.mozCancelRequestAnimationFrame) &&
      ! window.oRequestAnimationFrame      &&
      ! window.msRequestAnimationFrame)
        return window.setInterval(fn, delay);

    var start = new Date().getTime(),
        handle = new Object();

    function loop() {
      var current = new Date().getTime(),
        delta = current - start;

      if (delta >= delay) {
        fn.call();
        start = new Date().getTime();
      }

      handle.value = window.requestAnimFrame(loop);
    }

    handle.value = window.requestAnimFrame(loop);
    return handle;
  }

  /**
   * Behaves the same as clearInterval except uses cancelRequestAnimationFrame() where possible for better performance
   * @param {int|object} fn The callback function
   */
  window.clearRequestInterval = function(handle) {
    window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) :
    window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) :
    window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */
    window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) :
    window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) :
    window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) :
    clearInterval(handle);
  };

  /**
   * Behaves the same as setTimeout except uses requestAnimationFrame() where possible for better performance
   * @param {function} fn The callback function
   * @param {int} delay The delay in milliseconds
   */
  window.requestTimeout = function(fn, delay) {
    if ( ! window.requestAnimationFrame    &&
      ! window.webkitRequestAnimationFrame &&
      ! (window.mozRequestAnimationFrame   && window.mozCancelRequestAnimationFrame) && // Firefox 5 ships without cancel support
      ! window.oRequestAnimationFrame      &&
      ! window.msRequestAnimationFrame)
        return window.setTimeout(fn, delay);

    var start = new Date().getTime(),
        handle = new Object();

    function loop() {
      var current = new Date().getTime(),
          delta = current - start;

      delta >= delay ? fn.call() : handle.value = window.requestAnimFrame(loop);
    }

    handle.value = window.requestAnimFrame(loop);
    return handle;
  };

  /**
   * Shuffles array in place.
   * @link http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript
   * @param {Array} a items The array containing the items.
   * @return {Array} a The shuffled array
   */
  function shuffle(array) {
    var j, x, i;

    for (i = array.length; i; i -= 1) {
        j = Math.floor(Math.random() * i);
        x = array[i - 1];
        array[i - 1] = array[j];
        array[j] = x;
    }

    return array;
  }

  /**
           _....----"""----...._
        .-'  o    o    o    o   '-.
       /  o    o    o         o    \
    __/__o___o_ _ o___ _ o_ o_ _ _o_\__
   /                                   \
   \___________________________________/
     \~`-`.__.`-~`._.~`-`~.-~.__.~`-`/
  jgs \                             /
       `-._______________________.-'

   */
  var Hamburgers = {
    make: function() {
      var hamburgers = document.querySelectorAll(".js-hamburger");

      if (hamburgers.length > 0) {
        forEach(hamburgers, function(hamburger) {
          hamburger.addEventListener("click", Hamburgers.clickHandle, false);
        });
      }

      Hamburgers.headerAnimate();

      document.querySelector(".js-hint").addEventListener("click", Hamburgers.hintHandle, false);
    },

    clickHandle: function(e) {
      e.preventDefault();

      this.classList.toggle("is-active");
    },

    hintHandle: function(e) {
      e.preventDefault();

      this.parentNode.removeChild(this);

      document.getElementById("hint").classList.add("is-visible");
    },

    headerAnimateDelay: 200,
    headerAnimateInterval: 3250,

    headerAnimate: function() {
      var classes = [
        "slider", "squeeze", "arrow", "arrowalt", "spin", "elastic", "emphatic", "collapse", "vortex", "boring"
      ];

      shuffle(classes);

      var logo = document.querySelector(".hamburger--header");

      var animateTimer = window.requestInterval(animate, Hamburgers.headerAnimateDelay);

      window.requestTimeout(function() {
        window.clearRequestInterval(animateTimer);
        animateTimer = window.requestInterval(animate, Hamburgers.headerAnimateInterval);
      }, Hamburgers.headerAnimateDelay);

      function animate() {
        var current = parseInt(logo.getAttribute("data-class"), 10);

        logo.classList.add("hamburger--" + classes[current]);

        window.requestTimeout(function() {
          logo.classList.add("is-active");

          window.requestTimeout(function() {
            logo.classList.remove("is-active");

            window.requestTimeout(function() {
              logo.classList.remove("hamburger--" + classes[current]);

              var next = current + 1;

              if (next === classes.length) {
                next = 1;
              }
              logo.setAttribute("data-class", next);
            }, 750);
          }, 1000);
        }, 750);
      }
    }
  };

  Hamburgers.make();

}());
<|endoftext|>


<commit_before>IonModal = {
  transitionEndEvent: 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd',
  animationEndEvent: 'animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd',
  enterClasses: ['ng-enter', 'slide-in-up'],
  enterActiveClass: 'ng-enter-active',
  leaveClasses: ['ng-leave', 'slide-in-up'],
  leaveActiveClass: 'ng-leave-active',
  view: {},
  views: [],
  hooksOpen: {},
  hooksClose: {},
  hooksAllId: '__all__',
  open: function (templateName, data) {

    Meteor.setTimeout(function () {

      this.template = Template[templateName];
      this.views.push(templateName);
      if (!this.view[templateName]) this.view[templateName] = [];

      var view = Blaze.renderWithData(this.template, data, $('.ionic-body').get(0));
      this.view[templateName].push(view);

      var $modalBackdrop = $(view.firstNode());
      var $modal = $('.modal', $modalBackdrop);

      if (this.views.length === 1) {
        $modalBackdrop.addClass('active');
      }

      $modal.addClass(this.enterClasses.join(' '));
      Meteor.setTimeout(function () {
        $modal.addClass(this.enterActiveClass);
      }.bind(this), 50);

      var hooksAll = this.hooksOpen[this.hooksAllId] || [];
      _.each(hooksAll, function(hook) {
        hook.apply(this, [templateName]);
      });

      var hooks = this.hooksOpen[templateName] || [];
      _.each(hooks, function(hook) {
        hook.apply(this, [templateName]);
      });

    }.bind(this), 0);

  },
  close: function (templateName) {

    this.templateClosed = templateName;
    Meteor.setTimeout(function () {

      var templateName = this.templateClosed || this.views.slice(-1)[0];
      delete this.templateClosed;

      var view = (this.view[templateName] || []).slice(-1)[0];
      if (!view) return;

      var $modalBackdrop = $(view.firstNode());
      var $modal = $('.modal', $modalBackdrop);

      $modal.addClass(this.leaveClasses.join(' '));
      Meteor.setTimeout(function () {
        $modal.addClass(this.leaveActiveClass);
      }.bind(this), 50);

      $modalBackdrop.fadeOut(500, function() {
        $('body').removeClass('modal-open');
      });

      var hooksAll = this.hooksClose[this.hooksAllId] || [];
      _.each(hooksAll, function(hook) {
        hook.apply(this, [templateName]);
      });

      var hooks = this.hooksClose[templateName] || [];
      _.each(hooks, function(hook) {
        hook.apply(this, [templateName]);
      });

    }.bind(this), 0);

  },
  onOpen: function(templateName, callback) {
    if (!callback) {
      callback = templateName;
      templateName = this.hooksAllId;
    }
    this.hooksOpen[templateName] = this.hooksOpen[templateName] || [];
    this.hooksOpen[templateName].push(callback);
  },
  onClose: function(templateName, callback) {
    if (!callback) {
      callback = templateName;
      templateName = this.hooksAllId;
    }
    this.hooksClose[templateName] = this.hooksClose[templateName] || [];
    this.hooksClose[templateName].push(callback);
  }
};

$(document).delegate('.modal', IonModal.transitionEndEvent, function(e) {
  var $modal = $(e.currentTarget);
  if ($modal.hasClass(IonModal.enterClasses.join(' ')) || $modal.hasClass(IonModal.enterActiveClasse)) {
    $modal.removeClass(IonModal.enterClasses.join(' ')).removeClass(IonModal.enterActiveClass);
    $('body').addClass('modal-open');
  } else if ($modal.hasClass(IonModal.leaveClasses.join(' ')) || $modal.hasClass(IonModal.leaveActiveClasse)) {
    var firstChild = $modal.children().first();
    var templateName = getElementModalTemplateName(firstChild);
    IonModal.views = _.without(IonModal.views, templateName);
    var view = IonModal.view[templateName].pop();
    var $modalBackdrop = $(view.firstNode());
    $modalBackdrop.removeClass('active');
    $modal.removeClass(IonModal.leaveClasses.join(' ')).removeClass(IonModal.leaveActiveClass).off(IonModal.transitionEndEvent);
    $('body').removeClass('modal-open');
    $(e.target).parents('.modal-backdrop').remove();
    Blaze.remove(view);
  }
});

Template.ionModal.created = function () {
  this.data = this.data || {};
  this.customTemplate = this.data.customTemplate || false;
  this.title = this.data.title;
  this.title = this.data.closeText;
  this.focusFirstInput = _.isUndefined(this.data.focusFirstInput) ? true : this.data.focusFirstInput;
  this.animation = this.data.animation || 'slide-in-up';
};

Template.ionModal.rendered = function () {
  if (this.focusFirstInput) {
    Meteor.setTimeout(function () {
      if (!this._domrange) return;
      this.$('input:first').focus();
    }.bind(this), 600);
  }
  $(window).on('keyup.ionModal', function(event) {
    event.stopImmediatePropagation();
    if (event.which == 27) {
      IonModal.close();
    }
  });
};

Template.ionModal.destroyed = function () {
  if (!IonModal.views.length) {
    $(window).off('keyup.ionModal');
  }
};

Template.ionModal.helpers({
  barClass: function () {
    var defaultClasses = ['bar', 'bar-header', 'bar-stable'].join(' ');
    var customClasses = _.isString(this.barClass) ? this.barClass : '';
    return [defaultClasses, customClasses].join(' ');
  },

  titleClass: function () {
    var classes = ['title'];

    if (Platform.isAndroid()) {
      classes.push('title-left');
    }

    return classes.join(' ');
  },

  title: function () {
    return this.title;
  },

  closeText: function () {
    return this.closeText;
  },

  animation: function () {
    return this.animation || 'slide-in-up';
  },

  customTemplate: function () {
    return this.customTemplate;
  },

  classes: function () {
    var classes = ['modal'];

    if (this.class) {
      classes.push(this.class);
    }

    return classes.join(' ');
  }

});

Template.ionModal.events({
  // Handle clicking the backdrop
  'click': function (event, template) {
    if ($(event.target).hasClass('modal-backdrop')) {
      IonModal.close();
    }
  },
  'click [data-dismiss=modal]': function (event, template) {
    var tplName = getElementModalTemplateName(event.currentTarget);
    IonModal.close(tplName);
  }
});

var getElementModalTemplateName = function(element) {
  var modal = $(element).parents('.modal').get(0);
  var modalView = Blaze.getView(modal);
  var tplView = Meteor._get(modalView, 'parentView', 'parentView'); // Twice because the parent view is a #with block
  var tplName = tplView.name.slice('Template.'.length, tplView.name.length);
  return tplName;
};
<commit_msg>removed modal hooks -> can use Template.ionModal.onCreated / onDestroyed<commit_after>IonModal = {
  transitionEndEvent: 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd',
  animationEndEvent: 'animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd',
  enterClasses: ['ng-enter', 'slide-in-up'],
  enterActiveClass: 'ng-enter-active',
  leaveClasses: ['ng-leave', 'slide-in-up'],
  leaveActiveClass: 'ng-leave-active',
  view: {},
  views: [],
  open: function (templateName, data) {

    Meteor.setTimeout(function () {

      this.template = Template[templateName];
      this.views.push(templateName);
      if (!this.view[templateName]) this.view[templateName] = [];

      var view = Blaze.renderWithData(this.template, data, $('.ionic-body').get(0));
      this.view[templateName].push(view);

      var $modalBackdrop = $(view.firstNode());
      var $modal = $('.modal', $modalBackdrop);

      if (this.views.length === 1) {
        $modalBackdrop.addClass('active');
      }

      $modal.addClass(this.enterClasses.join(' '));
      Meteor.setTimeout(function () {
        $modal.addClass(this.enterActiveClass);
      }.bind(this), 50);

    }.bind(this), 0);

  },
  close: function (templateName) {

    this.templateClosed = templateName;
    Meteor.setTimeout(function () {

      var templateName = this.templateClosed || this.views.slice(-1)[0];
      delete this.templateClosed;

      var view = (this.view[templateName] || []).slice(-1)[0];
      if (!view) return;

      var $modalBackdrop = $(view.firstNode());
      var $modal = $('.modal', $modalBackdrop);

      $modal.addClass(this.leaveClasses.join(' '));
      Meteor.setTimeout(function () {
        $modal.addClass(this.leaveActiveClass);
      }.bind(this), 50);

      $modalBackdrop.fadeOut(500, function() {
        $('body').removeClass('modal-open');
      });

    }.bind(this), 0);

  }
};

$(document).delegate('.modal', IonModal.transitionEndEvent, function(e) {
  var $modal = $(e.currentTarget);
  if ($modal.hasClass(IonModal.enterClasses.join(' ')) || $modal.hasClass(IonModal.enterActiveClasse)) {
    $modal.removeClass(IonModal.enterClasses.join(' ')).removeClass(IonModal.enterActiveClass);
    $('body').addClass('modal-open');
  } else if ($modal.hasClass(IonModal.leaveClasses.join(' ')) || $modal.hasClass(IonModal.leaveActiveClasse)) {
    var firstChild = $modal.children().first();
    var templateName = getElementModalTemplateName(firstChild);
    IonModal.views = _.without(IonModal.views, templateName);
    var view = IonModal.view[templateName].pop();
    var $modalBackdrop = $(view.firstNode());
    $modalBackdrop.removeClass('active');
    $modal.removeClass(IonModal.leaveClasses.join(' ')).removeClass(IonModal.leaveActiveClass).off(IonModal.transitionEndEvent);
    $('body').removeClass('modal-open');
    $(e.target).parents('.modal-backdrop').remove();
    Blaze.remove(view);
  }
});

Template.ionModal.created = function () {
  this.data = this.data || {};
  this.customTemplate = this.data.customTemplate || false;
  this.title = this.data.title;
  this.title = this.data.closeText;
  this.focusFirstInput = _.isUndefined(this.data.focusFirstInput) ? true : this.data.focusFirstInput;
  this.animation = this.data.animation || 'slide-in-up';
};

Template.ionModal.rendered = function () {
  if (this.focusFirstInput) {
    Meteor.setTimeout(function () {
      if (!this._domrange) return;
      this.$('input:first').focus();
    }.bind(this), 600);
  }
  $(window).on('keyup.ionModal', function(event) {
    event.stopImmediatePropagation();
    if (event.which == 27) {
      IonModal.close();
    }
  });
};

Template.ionModal.destroyed = function () {
  if (!IonModal.views.length) {
    $(window).off('keyup.ionModal');
  }
};

Template.ionModal.helpers({
  barClass: function () {
    var defaultClasses = ['bar', 'bar-header', 'bar-stable'].join(' ');
    var customClasses = _.isString(this.barClass) ? this.barClass : '';
    return [defaultClasses, customClasses].join(' ');
  },

  titleClass: function () {
    var classes = ['title'];

    if (Platform.isAndroid()) {
      classes.push('title-left');
    }

    return classes.join(' ');
  },

  title: function () {
    return this.title;
  },

  closeText: function () {
    return this.closeText;
  },

  animation: function () {
    return this.animation || 'slide-in-up';
  },

  customTemplate: function () {
    return this.customTemplate;
  },

  classes: function () {
    var classes = ['modal'];

    if (this.class) {
      classes.push(this.class);
    }

    return classes.join(' ');
  }

});

Template.ionModal.events({
  // Handle clicking the backdrop
  'click': function (event, template) {
    if ($(event.target).hasClass('modal-backdrop')) {
      IonModal.close();
    }
  },
  'click [data-dismiss=modal]': function (event, template) {
    var tplName = getElementModalTemplateName(event.currentTarget);
    IonModal.close(tplName);
  }
});

var getElementModalTemplateName = function(element) {
  var modal = $(element).parents('.modal').get(0);
  var modalView = Blaze.getView(modal);
  var tplView = Meteor._get(modalView, 'parentView', 'parentView'); // Twice because the parent view is a #with block
  var tplName = tplView.name.slice('Template.'.length, tplView.name.length);
  return tplName;
};
<|endoftext|>