<commit_before>/**
 * jspsych-similarity.js
 * Josh de Leeuw
 *
 * This plugin create a trial where two images are shown sequentially, and the subject rates their similarity using a slider controlled with the mouse.
 *
 * parameters:
 *      stimuli:            array of arrays. inner arrays are two stimuli. stimuli can be image paths or html strings. each inner array is one trial.
 *      label_low:          label to display at the left end of the similarity slider scale.
 *      label_high:         label to display at the right end of the similiarity slider scale.
 *      timing_first_stim:  how long to show the first stimulus.
 *      timing_second_stim: how long to show the second stimulus. can be -1 to show until a response is given.
 *      timing_image_gap:   how long to show a blank screen between the two stimuli.
 *      timing_post_trial:  how long to show a blank screen after the trial is over.
 *      is_html:            must set to true when using HTML strings as the stimuli.
 *      prompt:             optional HTML string to display with the stimulus.
 *      data:               the optional data object
 *
 */

(function($) {
    jsPsych.similarity = (function() {

        var plugin = {};

        plugin.create = function(params) {
            var trials = new Array(params.stimuli.length);
            for (var i = 0; i < trials.length; i++) {
                trials[i] = {};
                trials[i].type = "similarity";
                trials[i].a_path = params.stimuli[i][0];
                trials[i].b_path = params.stimuli[i][1];

                // TODO make all changes related to following 4 parameters.
                trials[i].labels = (typeof params.labels === 'undefined') ? ["Not at all similar", "Identical"] : params.labels;
                trials[i].intervals = params.intervals || 100;
                trials[i].show_ticks = (typeof params.show_ticks === 'undefined') ? false : params.show_ticks;

                trials[i].show_response = params.show_response || "SECOND_STIMULUS";

                trials[i].timing_first_stim = params.timing_first_stim || 1000; // default 1000ms
                trials[i].timing_second_stim = params.timing_second_stim || -1; // -1 = inf time; positive numbers = msec to display second image.
                trials[i].timing_image_gap = params.timing_image_gap || 1000; // default 1000ms
                trials[i].timing_post_trial = params.timing_post_trial || 1000; // default 1000ms

                trials[i].is_html = (typeof params.is_html === 'undefined') ? false : params.is_html;
                trials[i].prompt = (typeof params.prompt === 'undefined') ? '' : params.prompt;
                trials[i].data = (typeof params.data === 'undefined') ? {} : params.data[i];
            }
            return trials;
        };

        var sim_trial_complete = false;

        plugin.trial = function(display_element, block, trial, part) {
            switch (part) {
            case 1:
                sim_trial_complete = false;
                // show the images
                if (!trial.is_html) {
                    display_element.append($('', {
                        "src": trial.a_path,
                        "id": 'jspsych_sim_stim'
                    }));
                }
                else {
                    display_element.append($('
', {
                        "html": trial.a_path,
                        "id": 'jspsych_sim_stim'
                    }));
                }

                if (trial.show_response == "FIRST_STIMULUS") {
                    show_response_slider(display_element, trial, block);
                }

                setTimeout(function() {
                    plugin.trial(display_element, block, trial, part + 1);
                }, trial.timing_first_stim);
                break;

            case 2:

                $('#jspsych_sim_stim').css('visibility', 'hidden');

                setTimeout(function() {
                    plugin.trial(display_element, block, trial, part + 1);
                }, trial.timing_image_gap);
                break;
            case 3:

                if (!trial.is_html) {
                    $('#jspsych_sim_stim').attr('src', trial.b_path);
                }
                else {
                    $('#jspsych_sim_stim').html(trial.b_path);
                }

                if (trial.show_response == "SECOND_STIMULUS") {
                    show_response_slider(display_element, trial, block);
                }

                if (trial.timing_second_stim > 0) {
                    setTimeout(function() {
                        if (!sim_trial_complete) {
                            $("#jspsych_sim_stim").css('visibility', 'hidden');
                            if (trial.show_response == "POST_STIMULUS") {
                                show_response_slider(display_element, trial, block);
                            }
                        }
                    }, trial.timing_second_stim);
                }

                break;
            }
        };

        function show_response_slider(display_element, trial, block) {

            var startTime = (new Date()).getTime();

            // create slider
            display_element.append($('
', {
                "id": 'slider',
                "class": 'sim'
            }));

            $("#slider").slider({
                value: Math.ceil(trial.intervals / 2),
                min: 1,
                max: trial.intervals,
                step: 1,
            });

            // show tick marks
            if (trial.show_ticks) {
                for (var j = 1; j < trial.intervals - 1; j++) {
                    $('#slider').append('

');
                }

                $('#slider .slidertickmark').each(function(index) {
                    var left = (index + 1) * (100 / (trial.intervals - 1));
                    $(this).css({
                        'position': 'absolute',
                        'left': left + '%',
                        'width': '1px',
                        'height': '100%',
                        'background-color': '#222222'
                    });
                });
            }

            // create labels for slider
            display_element.append($('
', {
                "id": "sliderlabels",
                "class": 'sliderlabels',
                "css": {
                    "width": "100%",
                    "margin": "10px 0px 0px 0px",
                    "padding": "0px",
                    "display": "block",
                    "position": "relative"
                }
            }));

            for (var j = 0; j < trial.labels.length; j++) {
                $("#sliderlabels").append('
' + trial.labels[j] + '
');
            }

            // position labels to match slider intervals
            var slider_width = $("#slider").width();
            var num_items = trial.labels.length;
            var item_width = slider_width / num_items;
            var spacing_interval = slider_width / (num_items - 1);

            $("#sliderlabels li").each(function(index) {
                $(this).css({
                    'display': 'inline-block',
                    'width': item_width + 'px',
                    'margin': '0px',
                    'padding': '0px',
                    'text-align': 'center',
                    'position': 'absolute',
                    'left': (spacing_interval * index) - (item_width / 2)
                });
            });

            //  create button
            display_element.append($('<button>', {
                'id': 'next',
                'class': 'sim',
                'html': 'Submit Answer'
            }));

            // if prompt is set, show prompt
            if (trial.prompt !== "") {
                display_element.append(trial.prompt);
            }

            $("#next").click(function() {
                var endTime = (new Date()).getTime();
                var response_time = endTime - startTime;
                sim_trial_complete = true;
                var score = $("#slider").slider("value");
                block.writeData($.extend({}, {
                    "sim_score": score,
                    "rt": response_time,
                    "stimulus": trial.a_path,
                    "stimulus_2": trial.b_path,
                    "trial_type": "similarity",
                    "trial_index": block.trial_idx
                }, trial.data));
                // goto next trial in block
                display_element.html('');
                setTimeout(function() {
                    block.next();
                }, trial.timing_post_trial);
            });
        }

        return plugin;
    })();
})(jQuery);<commit_msg>fixing height of labels container<commit_after>/**
 * jspsych-similarity.js
 * Josh de Leeuw
 *
 * This plugin create a trial where two images are shown sequentially, and the subject rates their similarity using a slider controlled with the mouse.
 *
 * parameters:
 *      stimuli:            array of arrays. inner arrays are two stimuli. stimuli can be image paths or html strings. each inner array is one trial.
 *      label_low:          label to display at the left end of the similarity slider scale.
 *      label_high:         label to display at the right end of the similiarity slider scale.
 *      timing_first_stim:  how long to show the first stimulus.
 *      timing_second_stim: how long to show the second stimulus. can be -1 to show until a response is given.
 *      timing_image_gap:   how long to show a blank screen between the two stimuli.
 *      timing_post_trial:  how long to show a blank screen after the trial is over.
 *      is_html:            must set to true when using HTML strings as the stimuli.
 *      prompt:             optional HTML string to display with the stimulus.
 *      data:               the optional data object
 *
 */

(function($) {
    jsPsych.similarity = (function() {

        var plugin = {};

        plugin.create = function(params) {
            var trials = new Array(params.stimuli.length);
            for (var i = 0; i < trials.length; i++) {
                trials[i] = {};
                trials[i].type = "similarity";
                trials[i].a_path = params.stimuli[i][0];
                trials[i].b_path = params.stimuli[i][1];

                // TODO make all changes related to following 4 parameters.
                trials[i].labels = (typeof params.labels === 'undefined') ? ["Not at all similar", "Identical"] : params.labels;
                trials[i].intervals = params.intervals || 100;
                trials[i].show_ticks = (typeof params.show_ticks === 'undefined') ? false : params.show_ticks;

                trials[i].show_response = params.show_response || "SECOND_STIMULUS";

                trials[i].timing_first_stim = params.timing_first_stim || 1000; // default 1000ms
                trials[i].timing_second_stim = params.timing_second_stim || -1; // -1 = inf time; positive numbers = msec to display second image.
                trials[i].timing_image_gap = params.timing_image_gap || 1000; // default 1000ms
                trials[i].timing_post_trial = params.timing_post_trial || 1000; // default 1000ms

                trials[i].is_html = (typeof params.is_html === 'undefined') ? false : params.is_html;
                trials[i].prompt = (typeof params.prompt === 'undefined') ? '' : params.prompt;
                trials[i].data = (typeof params.data === 'undefined') ? {} : params.data[i];
            }
            return trials;
        };

        var sim_trial_complete = false;

        plugin.trial = function(display_element, block, trial, part) {
            switch (part) {
            case 1:
                sim_trial_complete = false;
                // show the images
                if (!trial.is_html) {
                    display_element.append($('', {
                        "src": trial.a_path,
                        "id": 'jspsych_sim_stim'
                    }));
                }
                else {
                    display_element.append($('
', {
                        "html": trial.a_path,
                        "id": 'jspsych_sim_stim'
                    }));
                }

                if (trial.show_response == "FIRST_STIMULUS") {
                    show_response_slider(display_element, trial, block);
                }

                setTimeout(function() {
                    plugin.trial(display_element, block, trial, part + 1);
                }, trial.timing_first_stim);
                break;

            case 2:

                $('#jspsych_sim_stim').css('visibility', 'hidden');

                setTimeout(function() {
                    plugin.trial(display_element, block, trial, part + 1);
                }, trial.timing_image_gap);
                break;
            case 3:

                if (!trial.is_html) {
                    $('#jspsych_sim_stim').attr('src', trial.b_path);
                }
                else {
                    $('#jspsych_sim_stim').html(trial.b_path);
                }

                if (trial.show_response == "SECOND_STIMULUS") {
                    show_response_slider(display_element, trial, block);
                }

                if (trial.timing_second_stim > 0) {
                    setTimeout(function() {
                        if (!sim_trial_complete) {
                            $("#jspsych_sim_stim").css('visibility', 'hidden');
                            if (trial.show_response == "POST_STIMULUS") {
                                show_response_slider(display_element, trial, block);
                            }
                        }
                    }, trial.timing_second_stim);
                }

                break;
            }
        };

        function show_response_slider(display_element, trial, block) {

            var startTime = (new Date()).getTime();

            // create slider
            display_element.append($('
', {
                "id": 'slider',
                "class": 'sim'
            }));

            $("#slider").slider({
                value: Math.ceil(trial.intervals / 2),
                min: 1,
                max: trial.intervals,
                step: 1,
            });

            // show tick marks
            if (trial.show_ticks) {
                for (var j = 1; j < trial.intervals - 1; j++) {
                    $('#slider').append('

');
                }

                $('#slider .slidertickmark').each(function(index) {
                    var left = (index + 1) * (100 / (trial.intervals - 1));
                    $(this).css({
                        'position': 'absolute',
                        'left': left + '%',
                        'width': '1px',
                        'height': '100%',
                        'background-color': '#222222'
                    });
                });
            }

            // create labels for slider
            display_element.append($('
', {
                "id": "sliderlabels",
                "class": 'sliderlabels',
                "css": {
                    "width": "100%",
                    "height": "3em",
                    "margin": "10px 0px 0px 0px",
                    "padding": "0px",
                    "display": "block",
                    "position": "relative"
                }
            }));

            for (var j = 0; j < trial.labels.length; j++) {
                $("#sliderlabels").append('
' + trial.labels[j] + '
');
            }

            // position labels to match slider intervals
            var slider_width = $("#slider").width();
            var num_items = trial.labels.length;
            var item_width = slider_width / num_items;
            var spacing_interval = slider_width / (num_items - 1);

            $("#sliderlabels li").each(function(index) {
                $(this).css({
                    'display': 'inline-block',
                    'width': item_width + 'px',
                    'margin': '0px',
                    'padding': '0px',
                    'text-align': 'center',
                    'position': 'absolute',
                    'left': (spacing_interval * index) - (item_width / 2)
                });
            });

            //  create button
            display_element.append($('<button>', {
                'id': 'next',
                'class': 'sim',
                'html': 'Submit Answer'
            }));

            // if prompt is set, show prompt
            if (trial.prompt !== "") {
                display_element.append(trial.prompt);
            }

            $("#next").click(function() {
                var endTime = (new Date()).getTime();
                var response_time = endTime - startTime;
                sim_trial_complete = true;
                var score = $("#slider").slider("value");
                block.writeData($.extend({}, {
                    "sim_score": score,
                    "rt": response_time,
                    "stimulus": trial.a_path,
                    "stimulus_2": trial.b_path,
                    "trial_type": "similarity",
                    "trial_index": block.trial_idx
                }, trial.data));
                // goto next trial in block
                display_element.html('');
                setTimeout(function() {
                    block.next();
                }, trial.timing_post_trial);
            });
        }

        return plugin;
    })();
})(jQuery);<|endoftext|>


<commit_before>// Copyright (c) Microsoft Corporation. All rights reserved.

var telemetry = require('telemetry-helper');

var baseProps = {
    plugin: 'cordova-plugin-device',
    panel: 'device'
};

function initialize() {
    var devices = [
        {
            'id': 'AcerA500',
            'name': 'Acer A500',
            'model': 'Picasso',
            'platform': 'Android',
            'version': '4.0',
            'uuid': '500',
            'manufacturer': 'Acer'
        },
        {
            'id': 'Bold9700',
            'name': 'BlackBerry Bold 9700',
            'model': '9700',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Bold9900',
            'name': 'BlackBerry Bold 9900',
            'model': '9900',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Curve9300',
            'name': 'BlackBerry Curve 9300',
            'model': '9300',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Curve9350-9360-9370',
            'name': 'BlackBerry Curve 9350/9360/9370',
            'model': '9350-9360-9370',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'FWVGA',
            'name': 'Generic - FWVGA (480x854)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'G1',
            'name': 'HTC G1',
            'model': 'G1',
            'platform': 'Android',
            'version': '1.6',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'HPPre3',
            'name': 'HP Pre 3',
            'model': 'Pre',
            'platform': 'WebOS',
            'version': '2.x',
            'manufacturer': 'HP'
        },
        {
            'id': 'HPVeer',
            'name': 'HP Veer',
            'model': 'Veer',
            'platform': 'WebOS',
            'version': '2.x',
            'manufacturer': 'HP'
        },
        {
            'id': 'HVGA',
            'name': 'Generic - HVGA (320x480)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'iPad',
            'name': 'iPad',
            'model': 'iPad',
            'platform': 'iOS',
            'version': '1.6',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPad3',
            'name': 'iPad 3',
            'model': 'iPad3',
            'platform': 'iOS',
            'version': '5',
            'uuid': 'e0101010d38bde8e6740011221af335301010334',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPhone3',
            'name': 'iPhone 3G/3Gs',
            'model': '3G',
            'platform': 'iPhone',
            'version': '3',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPhone4',
            'name': 'iPhone 4/4s',
            'model': '4s',
            'platform': 'iOS',
            'version': '5',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPhone5',
            'name': 'iPhone 5',
            'model': '5',
            'platform': 'iOS',
            'version': '6',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'Legend',
            'name': 'HTC Legend',
            'model': 'Legend',
            'platform': 'Android',
            'version': '1.6',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'Nexus',
            'name': 'Nexus One',
            'model': 'Nexux One',
            'platform': 'Android',
            'version': '2.x.x',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'Nexus4',
            'name': 'Nexus 4',
            'model': 'Nexus 4',
            'platform': 'Android',
            'version': '4.2.x',
            'uuid': 'DC46B660-EF6F-46D4-AC24-85CFAB0C7694',
            'manufacturer': 'LG'
        },
        {
            'id': 'Nexus7',
            'name': 'Nexus 7 (Tablet)',
            'model': 'Nexus 7 8/16 GB',
            'platform': 'Android',
            'version': '4.x.x',
            'uuid': '903802EA-1786-4175-B0F1-1FDF87813CAA',
            'manufacturer': 'Asus'
        },
        {
            'id': 'NexusGalaxy',
            'name': 'Nexus (Galaxy)',
            'model': 'Galaxy Nexus (generic)',
            'platform': 'Android',
            'version': '4.x.x',
            'uuid': '3D0AD03B-8B46-431A-BEF5-FF01B96BA990',
            'manufacturer': 'Samsung'
        },
        {
            'id': 'NexusS',
            'name': 'Nexus S',
            'model': 'Nexux S',
            'platform': 'Android',
            'version': '2.3.x',
            'uuid': 'F54E13F1-C1B7-4212-BFA8-AB3C9C3F088F',
            'manufacturer': 'Samsung'
        },
        {
            'id': 'NokiaN8',
            'name': 'Nokia N8',
            'model': 'N8',
            'platform': 'SymbianOS',
            'version': '3',
            'uuid': '42',
            'manufacturer': 'Nokia'
        },
        {
            'id': 'NokiaN97',
            'name': 'Nokia N97/5800 (touch)',
            'model': 'N97',
            'platform': 'S60',
            'version': 'v5',
            'uuid': '42',
            'manufacturer': 'Nokia'
        },
        {
            'id': 'PalmPre',
            'name': 'Palm Pre',
            'model': 'Pre',
            'platform': 'WebOS',
            'version': '1.x',
            'manufacturer': 'Palm'
        },
        {
            'id': 'PalmPre2',
            'name': 'Palm Pre 2',
            'model': 'Pre',
            'platform': 'WebOS',
            'version': '2.x',
            'manufacturer': 'Palm'
        },
        {
            'id': 'Pearl9100',
            'name': 'BlackBerry Pearl 9100',
            'model': '9100',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Playbook',
            'name': 'BlackBerry Playbook',
            'model': '100669958',
            'platform': 'BlackBerry PlayBook OS',
            'version': 'BlackBerry PlayBook OS',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Q10',
            'name': 'BlackBerry Q10',
            'model': 'Q10',
            'platform': 'BlackBerry',
            'version': '10.1',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'QVGA',
            'name': 'Generic - QVGA (240X320)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'Style9670',
            'name': 'BlackBerry Style 9670',
            'model': '9670',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Tattoo',
            'name': 'HTC Tattoo',
            'model': 'Tattoo',
            'platform': 'Android',
            'version': '1.6',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'Torch9800',
            'name': 'BlackBerry Torch 9800',
            'model': '9800',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Torch9810',
            'name': 'BlackBerry Torch 9810',
            'model': '9810',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Torch9860-9850',
            'name': 'BlackBerry Torch 9860/9850',
            'model': '9860-9850',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Wave',
            'name': 'Samsung Wave',
            'model': 'Wave',
            'platform': 'Bada',
            'version': 'n/a',
            'manufacturer': 'Samsung'
        },
        {
            'id': 'WQVGA',
            'name': 'Generic - WQVGA (240x480)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'WVGA',
            'name': 'Generic - WVGA (480x800)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'Z10',
            'name': 'BlackBerry Z10',
            'model': 'Z10',
            'platform': 'BlackBerry',
            'version': '10.0.10',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        }
    ];

    devices.sort(function (left, right) {
        left = left.name.toUpperCase();
        right = right.name.toUpperCase();
        if (left < right) {
            return -1;
        }
        if (right < left) {
            return 1;
        }
        return 0;
    });

    var deviceList = document.getElementById('device-list');

    devices.forEach(function (device) {
        var option = document.createElement('option');
        option.value = device.id;

        var caption = document.createTextNode(device.name);
        option.appendChild(caption);

        option.setAttribute('_model', device.model);
        option.setAttribute('_manufacturer', device.manufacturer);
        option.setAttribute('_platform', device.platform);
        option.setAttribute('_version', device.version);
        option.setAttribute('_uuid', device.uuid);

        deviceList.appendChild(option);
    });

    deviceList.addEventListener('change', handleSelectDevice);
    deviceList.value = 'WVGA';
    handleSelectDevice();
    registerTelemetryEvents();
}

function handleSelectDevice() {
    var deviceList = document.getElementById('device-list');
    var option = deviceList.options[deviceList.selectedIndex];
    document.getElementById('device-model').value = option.getAttribute('_model');
    document.getElementById('device-manufacturer').value = option.getAttribute('_manufacturer');
    document.getElementById('device-platform').value = option.getAttribute('_platform');
    document.getElementById('device-uuid').value = option.getAttribute('_uuid');
    document.getElementById('device-version').value = option.getAttribute('_version');
    document.getElementById('is-virtual-device').checked = true; // by default, true for all devices
    document.getElementById('device-serial').value = '123456789';
}

function registerTelemetryForControl(controlId) {
    document.getElementById(controlId).addEventListener('change', telemetry.sendUITelemetry.bind(this, Object.assign({}, baseProps, {
        control: controlId
    })));
}

function registerTelemetryEvents() {
    // Register the simple events (onchange -> send the control ID).
    var basicTelemetryEventControls = [
        'device-model',
        'device-manufacturer',
        'device-platform',
        'device-uuid',
        'device-version',
        'device-serial'
    ];

    basicTelemetryEventControls.forEach(function (controlId) {
        registerTelemetryForControl(controlId);
    });

    // Register the event for the tdevice combo box.
    var deviceList = document.getElementById('device-list');

    deviceList.addEventListener('change', function () {
        var option = deviceList.options[deviceList.selectedIndex];

        telemetry.sendUITelemetry(Object.assign({}, baseProps, {
            control: 'device-list',
            value: option.value
        }));
    });
}

module.exports = function (messages) {

    var cordovaVersionLabel = document.getElementById('device-cordova-version');

    messages.call('cordova-version').then(function (version) {
        cordovaVersionLabel.value = version;
    }).fail(function () {
        cordovaVersionLabel.value = 'unknown';
    });

    return {
        initialize: initialize
    };
};
<commit_msg>Sending telemetry for isVirtual device control.<commit_after>// Copyright (c) Microsoft Corporation. All rights reserved.

var telemetry = require('telemetry-helper');

var baseProps = {
    plugin: 'cordova-plugin-device',
    panel: 'device'
};

function initialize() {
    var devices = [
        {
            'id': 'AcerA500',
            'name': 'Acer A500',
            'model': 'Picasso',
            'platform': 'Android',
            'version': '4.0',
            'uuid': '500',
            'manufacturer': 'Acer'
        },
        {
            'id': 'Bold9700',
            'name': 'BlackBerry Bold 9700',
            'model': '9700',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Bold9900',
            'name': 'BlackBerry Bold 9900',
            'model': '9900',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Curve9300',
            'name': 'BlackBerry Curve 9300',
            'model': '9300',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Curve9350-9360-9370',
            'name': 'BlackBerry Curve 9350/9360/9370',
            'model': '9350-9360-9370',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'FWVGA',
            'name': 'Generic - FWVGA (480x854)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'G1',
            'name': 'HTC G1',
            'model': 'G1',
            'platform': 'Android',
            'version': '1.6',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'HPPre3',
            'name': 'HP Pre 3',
            'model': 'Pre',
            'platform': 'WebOS',
            'version': '2.x',
            'manufacturer': 'HP'
        },
        {
            'id': 'HPVeer',
            'name': 'HP Veer',
            'model': 'Veer',
            'platform': 'WebOS',
            'version': '2.x',
            'manufacturer': 'HP'
        },
        {
            'id': 'HVGA',
            'name': 'Generic - HVGA (320x480)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'iPad',
            'name': 'iPad',
            'model': 'iPad',
            'platform': 'iOS',
            'version': '1.6',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPad3',
            'name': 'iPad 3',
            'model': 'iPad3',
            'platform': 'iOS',
            'version': '5',
            'uuid': 'e0101010d38bde8e6740011221af335301010334',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPhone3',
            'name': 'iPhone 3G/3Gs',
            'model': '3G',
            'platform': 'iPhone',
            'version': '3',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPhone4',
            'name': 'iPhone 4/4s',
            'model': '4s',
            'platform': 'iOS',
            'version': '5',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'iPhone5',
            'name': 'iPhone 5',
            'model': '5',
            'platform': 'iOS',
            'version': '6',
            'uuid': 'e0101010d38bde8e6740011221af335301010333',
            'manufacturer': 'Apple'
        },
        {
            'id': 'Legend',
            'name': 'HTC Legend',
            'model': 'Legend',
            'platform': 'Android',
            'version': '1.6',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'Nexus',
            'name': 'Nexus One',
            'model': 'Nexux One',
            'platform': 'Android',
            'version': '2.x.x',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'Nexus4',
            'name': 'Nexus 4',
            'model': 'Nexus 4',
            'platform': 'Android',
            'version': '4.2.x',
            'uuid': 'DC46B660-EF6F-46D4-AC24-85CFAB0C7694',
            'manufacturer': 'LG'
        },
        {
            'id': 'Nexus7',
            'name': 'Nexus 7 (Tablet)',
            'model': 'Nexus 7 8/16 GB',
            'platform': 'Android',
            'version': '4.x.x',
            'uuid': '903802EA-1786-4175-B0F1-1FDF87813CAA',
            'manufacturer': 'Asus'
        },
        {
            'id': 'NexusGalaxy',
            'name': 'Nexus (Galaxy)',
            'model': 'Galaxy Nexus (generic)',
            'platform': 'Android',
            'version': '4.x.x',
            'uuid': '3D0AD03B-8B46-431A-BEF5-FF01B96BA990',
            'manufacturer': 'Samsung'
        },
        {
            'id': 'NexusS',
            'name': 'Nexus S',
            'model': 'Nexux S',
            'platform': 'Android',
            'version': '2.3.x',
            'uuid': 'F54E13F1-C1B7-4212-BFA8-AB3C9C3F088F',
            'manufacturer': 'Samsung'
        },
        {
            'id': 'NokiaN8',
            'name': 'Nokia N8',
            'model': 'N8',
            'platform': 'SymbianOS',
            'version': '3',
            'uuid': '42',
            'manufacturer': 'Nokia'
        },
        {
            'id': 'NokiaN97',
            'name': 'Nokia N97/5800 (touch)',
            'model': 'N97',
            'platform': 'S60',
            'version': 'v5',
            'uuid': '42',
            'manufacturer': 'Nokia'
        },
        {
            'id': 'PalmPre',
            'name': 'Palm Pre',
            'model': 'Pre',
            'platform': 'WebOS',
            'version': '1.x',
            'manufacturer': 'Palm'
        },
        {
            'id': 'PalmPre2',
            'name': 'Palm Pre 2',
            'model': 'Pre',
            'platform': 'WebOS',
            'version': '2.x',
            'manufacturer': 'Palm'
        },
        {
            'id': 'Pearl9100',
            'name': 'BlackBerry Pearl 9100',
            'model': '9100',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Playbook',
            'name': 'BlackBerry Playbook',
            'model': '100669958',
            'platform': 'BlackBerry PlayBook OS',
            'version': 'BlackBerry PlayBook OS',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Q10',
            'name': 'BlackBerry Q10',
            'model': 'Q10',
            'platform': 'BlackBerry',
            'version': '10.1',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'QVGA',
            'name': 'Generic - QVGA (240X320)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'Style9670',
            'name': 'BlackBerry Style 9670',
            'model': '9670',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Tattoo',
            'name': 'HTC Tattoo',
            'model': 'Tattoo',
            'platform': 'Android',
            'version': '1.6',
            'uuid': '6F196F23-FD0D-4F62-B27B-730147FCC5A3',
            'manufacturer': 'HTC'
        },
        {
            'id': 'Torch9800',
            'name': 'BlackBerry Torch 9800',
            'model': '9800',
            'platform': 'BlackBerry OS',
            'version': '6',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Torch9810',
            'name': 'BlackBerry Torch 9810',
            'model': '9810',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Torch9860-9850',
            'name': 'BlackBerry Torch 9860/9850',
            'model': '9860-9850',
            'platform': 'BlackBerry OS',
            'version': '7',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        },
        {
            'id': 'Wave',
            'name': 'Samsung Wave',
            'model': 'Wave',
            'platform': 'Bada',
            'version': 'n/a',
            'manufacturer': 'Samsung'
        },
        {
            'id': 'WQVGA',
            'name': 'Generic - WQVGA (240x480)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'WVGA',
            'name': 'Generic - WVGA (480x800)',
            'model': 'Generic',
            'platform': 'Generic',
            'version': 'Generic',
            'uuid': '42',
            'manufacturer': 'Generic'
        },
        {
            'id': 'Z10',
            'name': 'BlackBerry Z10',
            'model': 'Z10',
            'platform': 'BlackBerry',
            'version': '10.0.10',
            'uuid': '42',
            'manufacturer': 'BlackBerry'
        }
    ];

    devices.sort(function (left, right) {
        left = left.name.toUpperCase();
        right = right.name.toUpperCase();
        if (left < right) {
            return -1;
        }
        if (right < left) {
            return 1;
        }
        return 0;
    });

    var deviceList = document.getElementById('device-list');

    devices.forEach(function (device) {
        var option = document.createElement('option');
        option.value = device.id;

        var caption = document.createTextNode(device.name);
        option.appendChild(caption);

        option.setAttribute('_model', device.model);
        option.setAttribute('_manufacturer', device.manufacturer);
        option.setAttribute('_platform', device.platform);
        option.setAttribute('_version', device.version);
        option.setAttribute('_uuid', device.uuid);

        deviceList.appendChild(option);
    });

    deviceList.addEventListener('change', handleSelectDevice);
    deviceList.value = 'WVGA';
    handleSelectDevice();
    registerTelemetryEvents();
}

function handleSelectDevice() {
    var deviceList = document.getElementById('device-list');
    var option = deviceList.options[deviceList.selectedIndex];
    document.getElementById('device-model').value = option.getAttribute('_model');
    document.getElementById('device-manufacturer').value = option.getAttribute('_manufacturer');
    document.getElementById('device-platform').value = option.getAttribute('_platform');
    document.getElementById('device-uuid').value = option.getAttribute('_uuid');
    document.getElementById('device-version').value = option.getAttribute('_version');
    document.getElementById('is-virtual-device').checked = true; // by default, true for all devices
    document.getElementById('device-serial').value = '123456789';
}

function registerTelemetryForControl(controlId) {
    document.getElementById(controlId).addEventListener('change', telemetry.sendUITelemetry.bind(this, Object.assign({}, baseProps, {
        control: controlId
    })));
}

function registerTelemetryEvents() {
    // Register the simple events (onchange -> send the control ID).
    var basicTelemetryEventControls = [
        'device-model',
        'device-manufacturer',
        'device-platform',
        'device-uuid',
        'device-version',
        'device-serial'
    ];

    basicTelemetryEventControls.forEach(function (controlId) {
        registerTelemetryForControl(controlId);
    });

    // Register the event for the device combo box.
    var deviceList = document.getElementById('device-list');

    deviceList.addEventListener('change', function () {
        var option = deviceList.options[deviceList.selectedIndex];

        telemetry.sendUITelemetry(Object.assign({}, baseProps, {
            control: 'device-list',
            value: option.value
        }));
    });

    // Register event for the isVirtual device checkbox
    document.getElementById('is-virtual-device')
        .addEventListener('click',
            telemetry.sendUITelemetry.bind(this, Object.assign({}, baseProps, {
                control: 'is-virtual-device'
            })));
}

module.exports = function (messages) {

    var cordovaVersionLabel = document.getElementById('device-cordova-version');

    messages.call('cordova-version').then(function (version) {
        cordovaVersionLabel.value = version;
    }).fail(function () {
        cordovaVersionLabel.value = 'unknown';
    });

    return {
        initialize: initialize
    };
};
<|endoftext|>


<commit_before>import { dependencies } from '../../external/dependencies'
import { DOM as dom } from '../../utils/browser'
import template from '../template/template.html'
import popoverTmpl from '../template/popover.html'
import {
    on,
    toDOM,
    query,
    props,
    prepend,
    nextUid,
    isHidden,
    setStyle,
    getStyle,
    getCoords,
    escapeHTML,
    createElem,
    forceReflow,
    getDOMState,
    removeStyle
} from '../../utils'
 import { transition } from '../../utils/transition'

const reEvent = /click|hover|focus|manual/
const reAutoHide = /auto|true/i
const reDirection = /top|bottom|left|right/
const reOffset =  /^\d{1,}$/

const unSupportDirection = 'Popover direction is not in announced list [top,bottom,left,right].'
const unSupportEvent = 'Event is not supported, it should one of the following values: [click, hover, focus, manual].'
const noTriggerSpecified = 'No trigger element was binded for popover component.'
const noTriggerFound = 'Trigger element cannot be found in component scope.'

//add disable function
export default class Popover{
    constructor(){
        this.restrict = 'EA'
        this.replace = true
        this.scope = {
            title:'@',
            manual:'='
        }
        this.transclude = true
        this.template = template
    }

    compile($tElement, tAttrs, transclude){
        let dire = (tAttrs.placement || "top").toLowerCase()
        if(!reDirection.test(dire)) throw Error(unSupportDirection)

        let tmpl = popoverTmpl.replace(/#{dire}/, dire)::toDOM()
        if($tElement::props('close')){
            tmpl::prepend('<button class="fm-close" ng-click="close()">×</button>')
        }

        $tElement.append(tmpl)
        if(tAttrs.trigger == undefined) throw new Error(noTriggerSpecified)

        return this.link
    }

    @dependencies('$scope')
    controller(scope){
        scope.open = () => this.popoverTrans.state = true
        scope.close = () => this.popoverTrans.state = false
        scope.toggle = () => this.popoverTrans.state ? scope.close() : scope.open()
    }

    link(scope, $element, attr, ctrl){
        this.rootDOM = $element[0]
        let popoverElem = this.rootDOM::query('.fm-popover')
        let trigger = this.rootDOM::query(attr.trigger)

        if(trigger === undefined) throw new Error(noTriggerFound)

        this.rootDOM::prepend(trigger)
        this.placement = attr.placement.toLowerCase()
        this.triggerLiteral = attr.trigger

        let actived = $element::props('actived')
        let offset = $element::props('offset')
        let event = attr.action || 'click'

        if(!reEvent.test(event)){
            throw new Error(unSupportEvent)
        } else if(event === 'hover'){
            event = 'mouseenter'
        } else if(event === 'manual'){
            scope.manual = {
                open:scope.open,
                close:scope.close
            }
        }

        if(reAutoHide.test(attr.hide)){
            let expr = event === 'mouseenter' ? 'mouseleave' : 'blur'
            trigger::on(expr, ::scope.close)
        }

        if(event !== 'manual'){
            trigger::on(event, ::scope.toggle)
        }

        this.offset = reOffset.test(offset) ? offset : 5
        this.title = attr.title
        this.popoverTrans = new transition(popoverElem, 'fm-popover-effect', actived)

        let arrowColor = attr.arrow || null

        setTimeout(() => {
            let init = false

            if(isHidden(popoverElem)){
                let display = 'block', opacity = 1, transform = 'scale(1)'
                popoverElem::setStyle({ display, opacity, transform })
                popoverElem::forceReflow()
                init = true
            }

            let trig = {
                height:trigger::getStyle('height','px'),
                width:trigger::getStyle('width','px')
            }

            let popover = {
                height:popoverElem::getStyle('height','px'),
                width:popoverElem::getStyle('width','px')
            }

            let left , top
            switch (this.placement) {
                case 'top':
                    left = `${-popover.width / 2 + trig.width / 2}px`
                    top = `${-popover.height + (-10) + (-this.offset)}px`
                    break
                case 'bottom':
                    left = `${-popover.width / 2 + trig.width / 2}px`
                    top = `${trig.height + 10 + this.offset}px`
                    break
                case 'left':
                    left = `${-popover.width + (-10) + (-this.offset)}px`
                    top = `${trig.height / 2 - popover.height / 2}px`
                    break
                case 'right':
                    left = `${trig.width + 10 + this.offset}px`
                    top = `${trig.height / 2 - popover.height / 2}px`
                    break
                default:
                    return
            }

            popoverElem::setStyle({ left, top})
            if(init){
                let display, opacity, transform
                popoverElem::removeStyle({ display, opacity, transform })
            }
            this.reColor(arrowColor)
        }, 0)
    }

    //auto calc arrow color
    reColor(color){
        let dire = this.placement
        let trigger = this.triggerLiteral
        if(color === null){
            let selector = dire === 'bottom' && this.title
            ? '+.fm-popover > .fm-popover-title'
            : '+.fm-popover > .fm-popover-content > *'

            let popoverMainElem = this.rootDOM::query(trigger + selector)
            color = popoverMainElem::getStyle('background-color')
        }

        let style = dom::query('#__arrowColor__')

        if(style === null){
            style = createElem('style')
            style.id = '__arrowColor__'
            dom::query('head').appendChild(style)
        }

        let triggerBtn = this.rootDOM::query(trigger)
        let uid = nextUid()
        triggerBtn.setAttribute(uid, '')

        let css = `
            ${escapeHTML(trigger)}[${uid}] + div.fm-popover > .fm-popover-arrow:after{
                border-${escapeHTML(dire)}-color:${color};
            }
        `
        style.innerHTML += css
    }
}
<commit_msg>update<commit_after>import { dependencies } from '../../external/dependencies'
import { DOM as dom } from '../../utils/browser'
import template from '../template/template.html'
import popoverTmpl from '../template/popover.html'
import {
    on,
    toDOM,
    query,
    props,
    prepend,
    nextUid,
    isHidden,
    setStyle,
    getStyle,
    getCoords,
    escapeHTML,
    createElem,
    forceReflow,
    getDOMState,
    removeStyle
} from '../../utils'
 import { transition } from '../../utils/transition'

const reEvent = /click|hover|focus|manual/
const reAutoHide = /auto|true/i
const reDirection = /top|bottom|left|right/
const reOffset =  /^\d{1,}$/

const unSupportedDirection = 'Popover direction is not in announced list [top,bottom,left,right].'
const unSupportedEvent = 'Event is not supported, it should one of the following values: [click, hover, focus, manual].'
const noTriggerSpecified = 'No trigger element was binded for popover component.'
const noTriggerFound = 'Trigger element cannot be found in component scope.'

//add disable function
export default class Popover{
    constructor(){
        this.restrict = 'EA'
        this.replace = true
        this.scope = {
            title:'@',
            manual:'='
        }
        this.transclude = true
        this.template = template
    }

    compile($tElement, tAttrs, transclude){
        let dire = (tAttrs.placement || "top").toLowerCase()
        if(!reDirection.test(dire)) throw Error(unSupportedDirection)

        let tmpl = popoverTmpl.replace(/#{dire}/, dire)::toDOM()
        if($tElement::props('close')){
            tmpl::prepend('<button class="fm-close" ng-click="close()">×</button>')
        }

        $tElement.append(tmpl)
        if(tAttrs.trigger == undefined) throw new Error(noTriggerSpecified)

        return this.link
    }

    @dependencies('$scope')
    controller(scope){
        scope.open = () => this.popoverTrans.state = true
        scope.close = () => this.popoverTrans.state = false
        scope.toggle = () => this.popoverTrans.state ? scope.close() : scope.open()
    }

    link(scope, $element, attr, ctrl){
        this.rootDOM = $element[0]
        let popoverElem = this.rootDOM::query('.fm-popover')
        let trigger = this.rootDOM::query(attr.trigger)

        if(trigger === undefined) throw new Error(noTriggerFound)

        this.rootDOM::prepend(trigger)
        this.placement = attr.placement.toLowerCase()
        this.triggerLiteral = attr.trigger

        let actived = $element::props('actived')
        let offset = $element::props('offset')
        let event = attr.action || 'click'

        if(!reEvent.test(event)){
            throw new Error(unSupportedEvent)
        } else if(event === 'hover'){
            event = 'mouseenter'
        } else if(event === 'manual'){
            scope.manual = {
                open:scope.open,
                close:scope.close
            }
        }

        if(reAutoHide.test(attr.hide)){
            let expr = event === 'mouseenter' ? 'mouseleave' : 'blur'
            trigger::on(expr, ::scope.close)
        }

        if(event !== 'manual'){
            trigger::on(event, ::scope.toggle)
        }

        this.offset = reOffset.test(offset) ? offset : 5
        this.title = attr.title
        this.popoverTrans = new transition(popoverElem, 'fm-popover-effect', actived)

        let arrowColor = attr.arrow || null

        setTimeout(() => {
            let init = false

            if(isHidden(popoverElem)){
                let display = 'block', opacity = 1, transform = 'scale(1)'
                popoverElem::setStyle({ display, opacity, transform })
                popoverElem::forceReflow()
                init = true
            }

            let trig = {
                height:trigger::getStyle('height','px'),
                width:trigger::getStyle('width','px')
            }

            let popover = {
                height:popoverElem::getStyle('height','px'),
                width:popoverElem::getStyle('width','px')
            }

            let left , top
            switch (this.placement) {
                case 'top':
                    left = `${-popover.width / 2 + trig.width / 2}px`
                    top = `${-popover.height + (-10) + (-this.offset)}px`
                    break
                case 'bottom':
                    left = `${-popover.width / 2 + trig.width / 2}px`
                    top = `${trig.height + 10 + this.offset}px`
                    break
                case 'left':
                    left = `${-popover.width + (-10) + (-this.offset)}px`
                    top = `${trig.height / 2 - popover.height / 2}px`
                    break
                case 'right':
                    left = `${trig.width + 10 + this.offset}px`
                    top = `${trig.height / 2 - popover.height / 2}px`
                    break
                default:
                    return
            }

            popoverElem::setStyle({ left, top})
            if(init){
                let display, opacity, transform
                popoverElem::removeStyle({ display, opacity, transform })
            }
            this.reColor(arrowColor)
        }, 0)
    }

    //auto calc arrow color
    reColor(color){
        let dire = this.placement
        let trigger = this.triggerLiteral
        if(color === null){
            let selector = dire === 'bottom' && this.title
            ? '+.fm-popover > .fm-popover-title'
            : '+.fm-popover > .fm-popover-content > *'

            let popoverMainElem = this.rootDOM::query(trigger + selector)
            color = popoverMainElem::getStyle('background-color')
        }

        let style = dom::query('#__arrowColor__')

        if(style === null){
            style = createElem('style')
            style.id = '__arrowColor__'
            dom::query('head').appendChild(style)
        }

        let triggerBtn = this.rootDOM::query(trigger)
        let uid = nextUid()
        triggerBtn.setAttribute(uid, '')

        let css = `
            ${escapeHTML(trigger)}[${uid}] + div.fm-popover > .fm-popover-arrow:after{
                border-${escapeHTML(dire)}-color:${color};
            }
        `
        style.innerHTML += css
    }
}
<|endoftext|>


<commit_before>function BPListController($scope, $http) {
    $scope.pressures = [];

    $scope.newPressure = {
        datetaken: new Date().getTime(),
        timeofday: 'Morning',
        systolic: 0,
        diastolic: 0,
        pulse: 0
    };

    $scope.setPressures = function(pressures) {
        $scope.pressures = pressures;
    };

    $scope.addNewPressure = function() {
        $http.post('/pressure.json', $scope.newPressure).success(function(data) {
            if(data.pressure) {
                $scope.pressures.push(data.pressure);
                //$scope.newPressure.timeofday('');
            } else {
                alert(JSON.stringify(data));
            }
        });
    };

    $scope.timeOptions = [
        { name: 'Morning', value: 'Morning' },
        { name: 'Evening', value: 'Evening' }
    ];

    $scope.pressure = { timeofday :
        $scope.timeOptions[0].value};

    $scope.selection = function() {
        console.log($scope.pressure);
    };
}
<commit_msg>use null to initialize form fields to show placeholder text<commit_after>function BPListController($scope, $http) {
    $scope.pressures = [];

    $scope.newPressure = {
        datetaken: new Date().getTime(),
        timeofday: 'Morning',
        systolic: null,
        diastolic: null,
        pulse: null
    };

    $scope.setPressures = function(pressures) {
        $scope.pressures = pressures;
    };

    $scope.addNewPressure = function() {
        $http.post('/pressure.json', $scope.newPressure).success(function(data) {
            if(data.pressure) {
                $scope.pressures.push(data.pressure);
                $scope.newPressure.systolic = null;
                $scope.newPressure.diastolic = null;
                $scope.newPressure.pulse = null;
            } else {
                alert(JSON.stringify(data));
            }
        });
    };

    $scope.timeOptions = [
        { name: 'Morning', value: 'Morning' },
        { name: 'Evening', value: 'Evening' }
    ];

    $scope.pressure = { timeofday :
        $scope.timeOptions[0].value};

    $scope.selection = function() {
        console.log($scope.pressure);
    };
}
<|endoftext|>


<commit_before>var React = require('react');
var ReactPropTypes = React.PropTypes;
var DatasetActions = require('../actions/DatasetActions');

var CodesTable = React.createClass({

  // This React class only works if a list of 'codes' is passed through its properties.
  propTypes: {
    codes: ReactPropTypes.array.isRequired
  },

  /**
   * @return {object}
   */
  render: function() {
    // This section should be hidden by default
    // and shown when we do have variables in our dataset
    if (this.props.codes === undefined || this.props.codes.length < 1) {
      return null;
    }

    var codes = this.props.codes;
    var codes_rows = [];

    for (var key in codes) {
      codes_rows.push(
 { codes[key].id }  { codes[key].count }
);
    }

    return (

            {codes_rows}

    );
  }
});

module.exports = CodesTable;
<commit_msg>Show/hide codes table<commit_after>var React = require('react');
var ReactPropTypes = React.PropTypes;
var PillSelector = require('./PillSelector.react');

var CodesTable = React.createClass({

  // This React class only works if a list of 'codes' is passed through its properties.
  propTypes: {
    codes: ReactPropTypes.array.isRequired
  },

  getInitialState: function() {
    return {
      'visible': true
    };
  },

  /**
   * @return {object}
   */
  render: function() {
    // This section should be hidden by default
    // and shown when we do have variables in our dataset
    if (this.props.codes === undefined || this.props.codes.length < 1) {
      return null;
    }

    var caret;
    if (this.state.visible){
      caret = ;
    } else {
      caret = ;
    }

    var table;
    if (this.state.visible) {
      var codes = this.props.codes;
      var codes_rows = [];

      for (var key in codes) {
        codes_rows.push(

                           { codes[key].id }
                            { codes[key].count }
);
      }

      table =

                    {codes_rows}

;
    }

    return (

Frequency Table {caret}

        {table}

    );
  },

  _filter: function(option){
    return (option.label.search(regexp) > -1) ? '': (option.uri.search(regexp) > -1) ? '': 'none';
  },

  /**
   * Event handler for the visible/invisible click
   */
  _onToggle: function() {
    var new_state = this.state;
    new_state.visible = !this.state.visible;
    this.setState(new_state);
  },
});

module.exports = CodesTable;
<|endoftext|>


<commit_before>(function() {
  'use strict';
  angular.module('civic.activity')
    .directive('activityGrid', activityGrid)
    .controller('ActivityGridController', ActivityGridController);

  // @ngInject
  function activityGrid() {
    var directive = {
      restrict: 'E',
      replace: true,
      scope: {
      },
      templateUrl: 'app/views/activity/directives/activityGrid.tpl.html',
      controller: 'ActivityGridController'
    };
    return directive;
  }

  // @ngInject
  function ActivityGridController($log,
                                  $scope,
                                  $state,
                                  $location,
                                  uiGridConstants,
                                  _,
                                  Events) {
    var ctrl = $scope.ctrl = {};

    var maxRows = ctrl.maxRows = 20;

    ctrl.events = $scope.events;

    ctrl.totalItems = Number();
    ctrl.page = $scope.page || 1;
    ctrl.count= maxRows;

    ctrl.filters = [];
    ctrl.sorting = [];

    ctrl.isFiltered = ctrl.filters.length > 0;

    $scope.$watch('ctrl.totalItems', function() {
      ctrl.totalPages = Math.ceil(ctrl.totalItems / maxRows);
    });

    ctrl.gridOptions = {
      enablePaginationControls: false,

      useExternalFiltering: true,
      useExternalSorting: true,
      useExternalPaging: true,

      paginationPageSizes: [maxRows],
      paginationPageSize: maxRows,
      minRowsToShow: maxRows-1,

      enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,

      enableFiltering: false,
      enableColumnMenus: false,
      enableSorting: true,
      enableRowSelection: true,
      enableRowHeaderSelection: false,
      multiSelect: false,
      modifierKeysToMultiSelect: false,
      noUnselect: true,
      columnDefs: [
        { name: 'user',
          displayName: 'User',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          enableSorting: false,
          width: '15%',
          cellTemplate: '
<user-block user="row.entity[col.field]"
',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        { name: 'role',
          field: 'user.role',
          displayName: 'Role',
          enableFiltering: true,
          allowCellFocus: false,
          enableSorting: false,
          type: 'string',
          width: '8%',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        { name: 'event_type',
          displayName: 'Event Type',
          enableFiltering: true,
          allowCellFocus: false,
          enableSorting: false,
          type: 'string',
          width: '20%',
          cellTemplate: '
' +
          '{{row.entity[col.field]}}' +
          ' (unlinkable)' +
          '
',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'gene',
          field: 'state_params.gene.name',
          displayName: 'Gene',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variant',
          field: 'state_params.variant.name',
          displayName: 'Variant',
          type: 'string',
          width: '15%',
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item',
          field: 'state_params.evidence_item.name',
          displayName: 'Item',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'timestamp',
          field: 'timestamp',
          displayName: 'Timestamp',
          type: 'date',
          sort: {direction: uiGridConstants.DESC},
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: true,
          cellTemplate: '

',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }

      ]
    };
    ctrl.gridOptions.onRegisterApi = function(gridApi){
      ctrl.gridApi = gridApi;

      // called from pagination directive when page changes
      ctrl.pageChanged = function() {
        $log.info('page changed: ' + ctrl.page);
        $location.search('page', ctrl.page);
        updateData();
      };

      // reset paging and do some other stuff on filter changes
      gridApi.core.on.filterChanged($scope, function() {
        $log.info('filter changed.');
        // updateData with new filters
        var filteredCols = _.filter(this.grid.columns, function(col) {
          return _.has(col.filter, 'term') && !_.isEmpty(col.filter.term) && _.isString(col.filter.term);
        });
        if (filteredCols.length > 0) {
          ctrl.filters = _.map(filteredCols, function(col) {
            return {
              'field': col.field,
              'term': col.filter.term
            };
          });
        } else {
          ctrl.filters = [];
        }
        ctrl.page = 1;
        updateData();
      });

      gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
        $log.info('sort changed.');
        if (sortColumns.length > 0) {
          ctrl.sorting = _.map(sortColumns, function(col) {
            return {
              'field': col.field,
              'direction': col.sort.direction
            };
          });
        } else {
          ctrl.sorting = [];
        }
        updateData();
      });

      // called when user clicks on a row
      gridApi.selection.on.rowSelectionChanged($scope, function(row){
        var event = row.entity;
        var subjectStates = {
          genes: 'events.genes',
          variants: 'events.genes.summary.variants',
          variantgroups: 'events.genes.summary.variantGroups',
          evidenceitems: 'events.genes.summary.variants.summary.evidence',
          sources: 'sources'
        };

        // revision comments require some more logic to determine the proper state
        if(event.subject_type === 'suggestedchanges') {
          var state;
          var type = event.state_params.suggested_change.subject_type;
          if(type === 'evidenceitems') {
            state = 'events.genes.summary.variants.summary.evidence';
          } else if (type === 'variantgroups') {
            state = 'events.genes.summary.variantGroups';
          } else if (type === 'variants') {
            state = 'events.genes.summary.variants';
          } else if (type === 'genes') {
            state = 'events.genes';
          }
          subjectStates.suggestedchanges = state;
        }

        var stateExtension = {
          'commented': '.talk.comments',
          'submitted': '.summary',
          'accepted': '.summary',
          'rejected': '.summary',
          'publication suggested': '.summary',
          'change suggested': '.talk.revisions.list.summary',
          'change accepted': '.talk.revisions.list.summary',
          'change rejected': '.talk.revisions.list.summary'
        };

        // revision comments are shown in their revision's summary view, override commented extension
        if(event.subject_type === 'suggestedchanges') {
          stateExtension.commented = '.talk.revisions.list.summary';
        }

        var stateParams = {};
        _.each(event.state_params, function(obj, entity) {
          var entityId;
          if(entity === 'suggested_change') {
            entityId = 'revisionId';
          } else if (entity === 'evidence_item') {
            entityId = 'evidenceId';
          } else if (entity === 'variant_group') {
            entityId = 'variantGroupId';
          } else if (entity === 'source') {
            entityId = 'sourceId';
          } else {
            entityId = entity + 'Id';
          }
          stateParams[entityId] = obj.id;
        });

        if (event.unlinkable === false) {
          $state.go(subjectStates[event.subject_type] + stateExtension[event.event_type], stateParams);
        }
      });
    };

    function updateData() {
      fetchData(ctrl.count, ctrl.page, ctrl.sorting, ctrl.filters)
        .then(function(data){
          ctrl.gridOptions.data = data.result;
          ctrl.totalItems = data.total;
        });
    }

    function fetchData(count, page, sorting, filters) {
      var request;

      request= {
        count: count,
        page: page
      };

      if (filters.length > 0) {
        _.each(filters, function(filter) {
          request['filter[' + filter.field + ']'] = filter.term;
        });
      }

      if (sorting.length > 0) {
        _.each(sorting, function(sort) {
          request['sorting[' + sort.field + ']'] = sort.direction;
        });
      }
      return Events.query(request);
    }

    updateData();

  }

})();
<commit_msg>activity grid rows for source comments now use the correct state sref<commit_after>(function() {
  'use strict';
  angular.module('civic.activity')
    .directive('activityGrid', activityGrid)
    .controller('ActivityGridController', ActivityGridController);

  // @ngInject
  function activityGrid() {
    var directive = {
      restrict: 'E',
      replace: true,
      scope: {
      },
      templateUrl: 'app/views/activity/directives/activityGrid.tpl.html',
      controller: 'ActivityGridController'
    };
    return directive;
  }

  // @ngInject
  function ActivityGridController($log,
                                  $scope,
                                  $state,
                                  $location,
                                  uiGridConstants,
                                  _,
                                  Events) {
    var ctrl = $scope.ctrl = {};

    var maxRows = ctrl.maxRows = 20;

    ctrl.events = $scope.events;

    ctrl.totalItems = Number();
    ctrl.page = $scope.page || 1;
    ctrl.count= maxRows;

    ctrl.filters = [];
    ctrl.sorting = [];

    ctrl.isFiltered = ctrl.filters.length > 0;

    $scope.$watch('ctrl.totalItems', function() {
      ctrl.totalPages = Math.ceil(ctrl.totalItems / maxRows);
    });

    ctrl.gridOptions = {
      enablePaginationControls: false,

      useExternalFiltering: true,
      useExternalSorting: true,
      useExternalPaging: true,

      paginationPageSizes: [maxRows],
      paginationPageSize: maxRows,
      minRowsToShow: maxRows-1,

      enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
      enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,

      enableFiltering: false,
      enableColumnMenus: false,
      enableSorting: true,
      enableRowSelection: true,
      enableRowHeaderSelection: false,
      multiSelect: false,
      modifierKeysToMultiSelect: false,
      noUnselect: true,
      columnDefs: [
        { name: 'user',
          displayName: 'User',
          type: 'string',
          enableFiltering: true,
          allowCellFocus: false,
          enableSorting: false,
          width: '15%',
          cellTemplate: '
<user-block user="row.entity[col.field]"
',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        { name: 'role',
          field: 'user.role',
          displayName: 'Role',
          enableFiltering: true,
          allowCellFocus: false,
          enableSorting: false,
          type: 'string',
          width: '8%',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        { name: 'event_type',
          displayName: 'Event Type',
          enableFiltering: true,
          allowCellFocus: false,
          enableSorting: false,
          type: 'string',
          width: '20%',
          cellTemplate: '
' +
          '{{row.entity[col.field]}}' +
          ' (unlinkable)' +
          '
',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'gene',
          field: 'state_params.gene.name',
          displayName: 'Gene',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'variant',
          field: 'state_params.variant.name',
          displayName: 'Variant',
          type: 'string',
          width: '15%',
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'evidence_item',
          field: 'state_params.evidence_item.name',
          displayName: 'Item',
          type: 'string',
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: false,
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        },
        {
          name: 'timestamp',
          field: 'timestamp',
          displayName: 'Timestamp',
          type: 'date',
          sort: {direction: uiGridConstants.DESC},
          allowCellFocus: false,
          enableFiltering: false,
          enableSorting: true,
          cellTemplate: '

',
          filter: {
            condition: uiGridConstants.filter.CONTAINS
          }
        }

      ]
    };
    ctrl.gridOptions.onRegisterApi = function(gridApi){
      ctrl.gridApi = gridApi;

      // called from pagination directive when page changes
      ctrl.pageChanged = function() {
        $log.info('page changed: ' + ctrl.page);
        $location.search('page', ctrl.page);
        updateData();
      };

      // reset paging and do some other stuff on filter changes
      gridApi.core.on.filterChanged($scope, function() {
        $log.info('filter changed.');
        // updateData with new filters
        var filteredCols = _.filter(this.grid.columns, function(col) {
          return _.has(col.filter, 'term') && !_.isEmpty(col.filter.term) && _.isString(col.filter.term);
        });
        if (filteredCols.length > 0) {
          ctrl.filters = _.map(filteredCols, function(col) {
            return {
              'field': col.field,
              'term': col.filter.term
            };
          });
        } else {
          ctrl.filters = [];
        }
        ctrl.page = 1;
        updateData();
      });

      gridApi.core.on.sortChanged($scope, function(grid, sortColumns) {
        $log.info('sort changed.');
        if (sortColumns.length > 0) {
          ctrl.sorting = _.map(sortColumns, function(col) {
            return {
              'field': col.field,
              'direction': col.sort.direction
            };
          });
        } else {
          ctrl.sorting = [];
        }
        updateData();
      });

      // called when user clicks on a row
      gridApi.selection.on.rowSelectionChanged($scope, function(row){
        var event = row.entity;
        var subjectStates = {
          genes: 'events.genes',
          variants: 'events.genes.summary.variants',
          variantgroups: 'events.genes.summary.variantGroups',
          evidenceitems: 'events.genes.summary.variants.summary.evidence',
          sources: 'sources'
        };

        // revision comments require some more logic to determine the proper state
        if(event.subject_type === 'suggestedchanges') {
          var state;
          var type = event.state_params.suggested_change.subject_type;
          if(type === 'evidenceitems') {
            state = 'events.genes.summary.variants.summary.evidence';
          } else if (type === 'variantgroups') {
            state = 'events.genes.summary.variantGroups';
          } else if (type === 'variants') {
            state = 'events.genes.summary.variants';
          } else if (type === 'genes') {
            state = 'events.genes';
          }
          subjectStates.suggestedchanges = state;
        }

        var stateExtension = {
          'commented': '.talk.comments',
          'submitted': '.summary',
          'accepted': '.summary',
          'rejected': '.summary',
          'publication suggested': '.summary',
          'change suggested': '.talk.revisions.list.summary',
          'change accepted': '.talk.revisions.list.summary',
          'change rejected': '.talk.revisions.list.summary'
        };

        // revision comments are shown in their revision's summary view, override commented extension
        if(event.subject_type === 'suggestedchanges') {
          stateExtension.commented = '.talk.revisions.list.summary';
        }

        // sources display comments right on their summary page
        if(event.subject_type === 'sources') {
          stateExtension.commented = '.summary';
        }

        var stateParams = {};
        _.each(event.state_params, function(obj, entity) {
          var entityId;
          if(entity === 'suggested_change') {
            entityId = 'revisionId';
          } else if (entity === 'evidence_item') {
            entityId = 'evidenceId';
          } else if (entity === 'variant_group') {
            entityId = 'variantGroupId';
          } else if (entity === 'source') {
            entityId = 'sourceId';
          } else {
            entityId = entity + 'Id';
          }
          stateParams[entityId] = obj.id;
        });

        if (event.unlinkable === false) {
          $state.go(subjectStates[event.subject_type] + stateExtension[event.event_type], stateParams);
        }
      });
    };

    function updateData() {
      fetchData(ctrl.count, ctrl.page, ctrl.sorting, ctrl.filters)
        .then(function(data){
          ctrl.gridOptions.data = data.result;
          ctrl.totalItems = data.total;
        });
    }

    function fetchData(count, page, sorting, filters) {
      var request;

      request= {
        count: count,
        page: page
      };

      if (filters.length > 0) {
        _.each(filters, function(filter) {
          request['filter[' + filter.field + ']'] = filter.term;
        });
      }

      if (sorting.length > 0) {
        _.each(sorting, function(sort) {
          request['sorting[' + sort.field + ']'] = sort.direction;
        });
      }
      return Events.query(request);
    }

    updateData();

  }

})();
<|endoftext|>


<commit_before>import config from '../config/config'
import loadscript from './loadscript'
import Timeline from '../group/timeline'
import debug from './debug'
import { isFunction } from './is'
import { isBrowser } from './context'

/**
 * Check on GSAP presence
 *
 * @returns {boolean}
 */
export function has() {
  return isFunction(config.gsap.tween) && isFunction(config.gsap.timeline)
}

/**
 * Ensure GSAP is loaded
 * Auto inject
 *
 * @returns {Promise<void>}
 */
export function ensure() {
  if (has()) {
    return Promise.resolve()
  }

  // has gsap on window object?
  const wTween = window.TweenMax || window.TweenLite
  const wTimeline = window.TimelineMax || window.TimelineLite

  if (isBrowser() && isFunction(wTween) && isFunction(wTimeline)) {
    config.gsap.tween = wTween
    config.gsap.timeline = wTimeline

    return Promise.resolve()
  }

  // load from cdn
  if (!config.gsap.autoInject) {
    if (debug()) {
      console.warn(`

        It seems that you've disabled autoInject. GSAP cannot be found or loaded by Spirit.
        Please make sure you provide the tween and timeline to Spirit:

        spirit.setup({
          tween: TweenMax,
          timeline: TimelineMax
        })

        Or enable the autoInject "spirit.config.gsap.autoInject = true".

      `)
    }

    return Promise.reject(new Error('GSAP not found.'))
  }

  if (debug()) {
    console.warn(`

      GSAP is being fetched from CDN: ${config.gsap.autoInjectUrl}.
      If you already have GSAP installed, please provide it to Spirit:

        spirit.setup({
          tween: TweenMax,
          timeline: TimelineMax
        })

      You want to use another cdn? Change it here:

        spirit.config.gsap.autoInjectUrl = 'https://cdn.xxx'

    `)
  }

  return this.loadFromCDN()
}

/**
 * Load GSAP from CDN based on autoInjectUrl
 *
 * @return {Promise<void>}
 */
export function loadFromCDN() {
  return loadscript(config.gsap.autoInjectUrl)
    .then(() => {
      config.gsap.tween = window.TweenMax
      config.gsap.timeline = window.TimelineMax

      return Promise.resolve()
    }).catch(err => {
      return Promise.reject(err)
    })
}

/**
 * Get transform origins for timeline
 *
 * @param {Timeline} timeline
 * @return {Function}
 */
export function transformOrigins(timeline) {
  const prop = timeline.props.get('transformOrigin')
  let origins = (prop && prop.keyframes.list.map(k => ({ time: k.time, value: k.value }))) || []

  // add start 50% 50% ?
  if (origins.length > 0 && origins[0].time !== 0 || origins.length === 0) {
    origins.unshift({ time: 0, value: '50% 50%' })
  }

  let current = origins.shift()

  let next, getVal

  getVal = () => ({ current, next })

  next = () => {
    current = (origins && origins.length > 0 && origins.shift()) || null
    return getVal()
  }

  return getVal()
}

/**
 * Generate timeline from data
 *
 * @param {Timeline} timeline
 * @returns {TimelineMax|TimelineLite}
 */
export function generateTimeline(timeline) {
  if (!timeline || !(timeline instanceof Timeline)) {
    throw new Error('Need valid timeline data to generate GSAP timeline from')
  }

  if (!config.gsap.timeline) {
    throw new Error('GSAP not set. Please make sure GSAP is available.')
  }

  if (timeline.type !== 'dom') {
    throw new Error('Timeline invalid. Needs a timeline with type of dom.')
  }

  const tl = new config.gsap.timeline({ paused: true }) // eslint-disable-line new-cap

  const origins = transformOrigins(timeline)
  let origin = origins.current

  timeline.props.each(prop => {
    if (prop.keyframes.length === 0 || prop.name === 'transformOrigin' || prop.name === 'svgOrigin') {
      return
    }

    let keyframe = prop.keyframes.at(0)

    while (keyframe) {
      const { value, ease, time } = keyframe
      const prev = keyframe.prev()

      const start = prev ? prev.time : 0
      const duration = prev ? time - prev.time : time

      let props = { ease: ease || 'Linear.easeNone' }
      let property = { [prop.name]: value }

      // parse dots into recursive object
      if (/\./.test(prop.name)) {
        let segments = prop.name.split('.')
        let last = segments.pop()
        let obj = {}
        let o = obj

        while (segments.length > 0) {
          let segment = segments.shift()

          obj[segment] = {}
          obj = obj[segment]
        }

        obj[last] = value
        property = o
      }

      props = { ...props, ...property }

      if (time === 0) {
        props.immediateRender = true
      }

      if (prop.isCSSTransform() && origin && time >= origin.time) {
        props.transformOrigin = origin.value
        origin = origins.next().current
      }

      tl.to(timeline.transformObject, duration, props, start)

      keyframe = keyframe.next()
    }
  })

  return tl
}

/**
 * Recursively kill timeline
 * Reset props on targets
 *
 * @param {TimelineMax|TimelineLite} gsapTimeline
 */
export function killTimeline(gsapTimeline) {
  if (gsapTimeline && gsapTimeline instanceof config.gsap.timeline) {
    gsapTimeline.eventCallback('onComplete', null)
    gsapTimeline.eventCallback('onUpdate', null)
    gsapTimeline.eventCallback('onStart', null)

    const targets = gsapTimeline.getChildren()
    gsapTimeline.kill()

    for (let i = 0; i < targets.length; i++) {
      if (targets[i] && targets[i] instanceof config.gsap.timeline) {
        killTimeline(targets[i])
        continue
      }

      if (targets[i].target !== null) {
        config.gsap.tween.set(targets[i].target, { clearProps: 'all' })
      }
    }
    gsapTimeline.clear()
  }
}
<commit_msg>Kill timeline if timeline instance exists<commit_after>import config from '../config/config'
import loadscript from './loadscript'
import Timeline from '../group/timeline'
import debug from './debug'
import { isFunction } from './is'
import { isBrowser } from './context'

/**
 * Check on GSAP presence
 *
 * @returns {boolean}
 */
export function has() {
  return isFunction(config.gsap.tween) && isFunction(config.gsap.timeline)
}

/**
 * Ensure GSAP is loaded
 * Auto inject
 *
 * @returns {Promise<void>}
 */
export function ensure() {
  if (has()) {
    return Promise.resolve()
  }

  // has gsap on window object?
  const wTween = window.TweenMax || window.TweenLite
  const wTimeline = window.TimelineMax || window.TimelineLite

  if (isBrowser() && isFunction(wTween) && isFunction(wTimeline)) {
    config.gsap.tween = wTween
    config.gsap.timeline = wTimeline

    return Promise.resolve()
  }

  // load from cdn
  if (!config.gsap.autoInject) {
    if (debug()) {
      console.warn(`

        It seems that you've disabled autoInject. GSAP cannot be found or loaded by Spirit.
        Please make sure you provide the tween and timeline to Spirit:

        spirit.setup({
          tween: TweenMax,
          timeline: TimelineMax
        })

        Or enable the autoInject "spirit.config.gsap.autoInject = true".

      `)
    }

    return Promise.reject(new Error('GSAP not found.'))
  }

  if (debug()) {
    console.warn(`

      GSAP is being fetched from CDN: ${config.gsap.autoInjectUrl}.
      If you already have GSAP installed, please provide it to Spirit:

        spirit.setup({
          tween: TweenMax,
          timeline: TimelineMax
        })

      You want to use another cdn? Change it here:

        spirit.config.gsap.autoInjectUrl = 'https://cdn.xxx'

    `)
  }

  return this.loadFromCDN()
}

/**
 * Load GSAP from CDN based on autoInjectUrl
 *
 * @return {Promise<void>}
 */
export function loadFromCDN() {
  return loadscript(config.gsap.autoInjectUrl)
    .then(() => {
      config.gsap.tween = window.TweenMax
      config.gsap.timeline = window.TimelineMax

      return Promise.resolve()
    }).catch(err => {
      return Promise.reject(err)
    })
}

/**
 * Get transform origins for timeline
 *
 * @param {Timeline} timeline
 * @return {Function}
 */
export function transformOrigins(timeline) {
  const prop = timeline.props.get('transformOrigin')
  let origins = (prop && prop.keyframes.list.map(k => ({ time: k.time, value: k.value }))) || []

  // add start 50% 50% ?
  if (origins.length > 0 && origins[0].time !== 0 || origins.length === 0) {
    origins.unshift({ time: 0, value: '50% 50%' })
  }

  let current = origins.shift()

  let next, getVal

  getVal = () => ({ current, next })

  next = () => {
    current = (origins && origins.length > 0 && origins.shift()) || null
    return getVal()
  }

  return getVal()
}

/**
 * Generate timeline from data
 *
 * @param {Timeline} timeline
 * @returns {TimelineMax|TimelineLite}
 */
export function generateTimeline(timeline) {
  if (!timeline || !(timeline instanceof Timeline)) {
    throw new Error('Need valid timeline data to generate GSAP timeline from')
  }

  if (!config.gsap.timeline) {
    throw new Error('GSAP not set. Please make sure GSAP is available.')
  }

  if (timeline.type !== 'dom') {
    throw new Error('Timeline invalid. Needs a timeline with type of dom.')
  }

  const tl = new config.gsap.timeline({ paused: true }) // eslint-disable-line new-cap

  const origins = transformOrigins(timeline)
  let origin = origins.current

  timeline.props.each(prop => {
    if (prop.keyframes.length === 0 || prop.name === 'transformOrigin' || prop.name === 'svgOrigin') {
      return
    }

    let keyframe = prop.keyframes.at(0)

    while (keyframe) {
      const { value, ease, time } = keyframe
      const prev = keyframe.prev()

      const start = prev ? prev.time : 0
      const duration = prev ? time - prev.time : time

      let props = { ease: ease || 'Linear.easeNone' }
      let property = { [prop.name]: value }

      // parse dots into recursive object
      if (/\./.test(prop.name)) {
        let segments = prop.name.split('.')
        let last = segments.pop()
        let obj = {}
        let o = obj

        while (segments.length > 0) {
          let segment = segments.shift()

          obj[segment] = {}
          obj = obj[segment]
        }

        obj[last] = value
        property = o
      }

      props = { ...props, ...property }

      if (time === 0) {
        props.immediateRender = true
      }

      if (prop.isCSSTransform() && origin && time >= origin.time) {
        props.transformOrigin = origin.value
        origin = origins.next().current
      }

      tl.to(timeline.transformObject, duration, props, start)

      keyframe = keyframe.next()
    }
  })

  return tl
}

/**
 * Recursively kill timeline
 * Reset props on targets
 *
 * @param {TimelineMax|TimelineLite} gsapTimeline
 */
export function killTimeline(gsapTimeline) {
  if (gsapTimeline && isFunction(config.gsap.timeline) && gsapTimeline instanceof config.gsap.timeline) {
    gsapTimeline.eventCallback('onComplete', null)
    gsapTimeline.eventCallback('onUpdate', null)
    gsapTimeline.eventCallback('onStart', null)

    const targets = gsapTimeline.getChildren()
    gsapTimeline.kill()

    for (let i = 0; i < targets.length; i++) {
      if (targets[i] && targets[i] instanceof config.gsap.timeline) {
        killTimeline(targets[i])
        continue
      }

      if (targets[i].target !== null) {
        config.gsap.tween.set(targets[i].target, { clearProps: 'all' })
      }
    }
    gsapTimeline.clear()
  }
}
<|endoftext|>


<commit_before>var drawingManager;
var selectedShape;
var colors = ['#1E90FF', '#FF1493', '#32CD32', '#FF8C00', '#4B0082'];
var selectedColor;
var colorButtons = {};

var polygon;
var map;
var polygon_options = {
            strokeWeight: 0,
            fillOpacity: 0.45,
            editable: true,
            draggable: true
        };

function initialize () {
    map = new google.maps.Map(document.getElementById('map'), {
        zoom: 18,
        center: new google.maps.LatLng(33.444892, -118.484664),
        mapTypeId: google.maps.MapTypeId.HYBRID,
        disableDefaultUI: false,
        zoomControl: true,
        scaleControl: true
    });

    // Creates a drawing manager attached to the map that allows the user to draw
    // markers, lines, and shapes.
    drawingManager = new google.maps.drawing.DrawingManager({
        drawingMode: google.maps.drawing.OverlayType.POLYGON,
        markerOptions: {
            draggable: true
        },
        polygonOptions: polygon_options,
        map: map
    });

    google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {

        if (e.type !== google.maps.drawing.OverlayType.MARKER) {
            // Switch back to non-drawing mode after drawing a shape.
            drawingManager.setDrawingMode(null);
        }
    });

    // save the polygon out
    google.maps.event.addListener(drawingManager, 'polygoncomplete', function (e) {

        polygon = e.getPath();
        polygon.forEach(function(vert, index) { console.log(vert.toString())})
    });
}

function savePolygon() {

    var csvRows = ["Latitude,Longitude"];

    polygon.forEach(function(vert, index)
        {
            var cRow = vert.toString();

            csvRows.push(cRow.substring(1, cRow.length - 1));

        })

    console.log(csvRows);

    var csvString = csvRows.join("\r\n");
    var a         = document.createElement('a');
    a.href        = 'data:attachment/csv,' +  encodeURIComponent(csvString);
    a.target      = '_blank';
    a.download    = 'path.csv';

    document.body.appendChild(a);
    a.click();

}

function readCSVPolygonFile (evt) {

    if (polygon != null)
    {
        polygon.setMap(null);
    }

    var files = evt.target.files;
    var file = files[0];
    var reader = new FileReader();
    reader.onload = function() {

    console.log(this.result);

    var data = d3.csvParse(this.result);

    var latlngArray = [];

    for (var i = 0; i < data.length; i++) {
        console.log(data[i].Latitude, data[i].Longitude);
        if (data[i].Latitude != 0 && data[i].Longitude != 0)
        {
            latlngArray.push(new google.maps.LatLng(data[i].Latitude, data[i].Longitude))
        }

    }

    // draw polygon
    polygon = new google.maps.Polygon({
        paths: latlngArray,
        strokeColor: '#FF0000',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: '#FF0000',
        fillOpacity: 0.35
    });
    polygon.setMap(map);

    }

    reader.readAsText(file);
}

google.maps.event.addDomListener(window, 'load', initialize);
document.getElementById('csvfile').addEventListener('change', readCSVPolygonFile, false);
<commit_msg>allow multiple polygons to be drawn<commit_after>var drawingManager;
var selectedShape;
var colors = ['#1E90FF', '#FF1493', '#32CD32', '#FF8C00', '#4B0082'];
var selectedColor;
var colorButtons = {};

var polygon = [];
var map;
var polygon_options = {
            strokeWeight: 0,
            fillOpacity: 0.45,
            editable: true,
            draggable: true
        };

function initialize () {
    map = new google.maps.Map(document.getElementById('map'), {
        zoom: 18,
        center: new google.maps.LatLng(33.444892, -118.484664),
        mapTypeId: google.maps.MapTypeId.HYBRID,
        disableDefaultUI: false,
        zoomControl: true,
        scaleControl: true
    });

    // Creates a drawing manager attached to the map that allows the user to draw
    // markers, lines, and shapes.
    drawingManager = new google.maps.drawing.DrawingManager({
        drawingMode: google.maps.drawing.OverlayType.POLYGON,
        markerOptions: {
            draggable: true
        },
        polygonOptions: polygon_options,
        map: map
    });

    google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {

        if (e.type !== google.maps.drawing.OverlayType.MARKER) {
            // Switch back to non-drawing mode after drawing a shape.
            drawingManager.setDrawingMode(null);
        }
    });

    // save the polygon out
    google.maps.event.addListener(drawingManager, 'polygoncomplete', function (e) {

        cpolygon = e.getPath();
        polygon.push(cpolygon);
        cpolygon.forEach(function(vert, index) { console.log(vert.toString())})
    });
}

function savePolygon() {

    for (i = 0; i < polygon.length; i++)
    {
        var csvRows = ["Latitude,Longitude"];

            polygon[i].forEach(function(vert, index)
                {
                    var cRow = vert.toString();

                    csvRows.push(cRow.substring(1, cRow.length - 1));

                })

            console.log(csvRows);

            var csvString = csvRows.join("\r\n");
            var a         = document.createElement('a');
            a.href        = 'data:attachment/csv,' +  encodeURIComponent(csvString);
            a.target      = '_blank';
            a.download    = 'path.csv';

            document.body.appendChild(a);
            a.click();
    }

}

function readCSVPolygonFile (evt) {

    if (polygon != null)
    {
        polygon.setMap(null);
    }

    var files = evt.target.files;
    var file = files[0];
    var reader = new FileReader();
    reader.onload = function() {

    console.log(this.result);

    var data = d3.csvParse(this.result);

    var latlngArray = [];

    for (var i = 0; i < data.length; i++) {
        console.log(data[i].Latitude, data[i].Longitude);
        if (data[i].Latitude != 0 && data[i].Longitude != 0)
        {
            latlngArray.push(new google.maps.LatLng(data[i].Latitude, data[i].Longitude))
        }

    }

    // draw polygon
    polygon = new google.maps.Polygon({
        paths: latlngArray,
        strokeColor: '#FF0000',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: '#FF0000',
        fillOpacity: 0.35
    });
    polygon.setMap(map);

    }

    reader.readAsText(file);
}

google.maps.event.addDomListener(window, 'load', initialize);
document.getElementById('csvfile').addEventListener('change', readCSVPolygonFile, false);
<|endoftext|>