<commit_before>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CoursesTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CoursesHeader");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    gvm.addAvailableLocations = function(id, name) {
        var selectObject = {id: id, locationName: name};
        gvm.availableLocations.push(selectObject);
    }
    gvm.addAvailableTrainings = function(id, name) {
        var selectObject = {id: id, trainingName: name};
        gvm.availableTrainings.push(selectObject);
    }

    gvm.addAvailableCourses = function(id, name) {
        var selectObject = {id: id, courseName: name};
        gvm.availableCourses.push(selectObject);
    }

    gvm.clearAll = function() {
        gvm.availableLocations.removeAll();
        gvm.availableTrainings.removeAll();
        gvm.availableCourses.removeAll();
    }
}

function loadAllSelects($locationid, $trainingid)
{
    $.getJSON('/api/courses/' + $locationid + '/' +  $trainingid, function(data) {
        $.each(data[1],function(i, item) {
            viewModel.addAvailableLocations(item.id, item.name);
        });
        $.each(data[2], function(i, item) {
            viewModel.addAvailableTrainings(item.id, item.name);
        });
        $.each(data[3], function(i, item) {
            viewModel.addAvailableCourses(item.id, item.name);
        });
    });
    bindEvents();
}

function bindEvents() {
    $("#location").on("change", function() {
        $("#location").unbind("change");
        $("#training").unbind("change");
        loadAllSelects($("#location").val(), $("#training").val());
    });
    $("#training").on("change", function() {
        $("#location").unbind("change");
        $("#training").unbind("change");
        loadAllSelects($("#location").val(), $("#training").val());
    });
}

function initPage() {
    loadAllSelects(1, 1);
}<commit_msg>courses<commit_after>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CoursesTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CoursesHeader");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    gvm.addAvailableLocations = function(id, name) {
        var selectObject = {id: id, locationName: name};
        gvm.availableLocations.push(selectObject);
    }
    gvm.addAvailableTrainings = function(id, name) {
        var selectObject = {id: id, trainingName: name};
        gvm.availableTrainings.push(selectObject);
    }

    gvm.addAvailableCourses = function(id, name) {
        var selectObject = {id: id, courseName: name};
        gvm.availableCourses.push(selectObject);
    }

    gvm.clearAll = function() {
        gvm.availableLocations.removeAll();
        gvm.availableTrainings.removeAll();
        gvm.availableCourses.removeAll();
    }
}

function loadAllSelects($locationid, $trainingid)
{
    $.getJSON('/api/courses/' + $locationid + '/' +  $trainingid, function(data) {
        $.each(data[1],function(i, item) {
            viewModel.addAvailableLocations(item.id, item.name);
        });
        $.each(data[2], function(i, item) {
            viewModel.addAvailableTrainings(item.id, item.name);
        });
        $.each(data[3], function(i, item) {
            viewModel.addAvailableCourses(item.id, item.name);
        });
    });
    bindEvents();
}

function bindEvents() {
    $("#location").on("change", function() {
        $("#location").unbind("change");
        $("#training").unbind("change");
        viewModel.clearAll();
        loadAllSelects($("#location").val(), $("#training").val());
    });
    $("#training").on("change", function() {
        $("#location").unbind("change");
        $("#training").unbind("change");
        viewModel.clearAll();
        loadAllSelects($("#location").val(), $("#training").val());
    });
}

function initPage() {
    loadAllSelects(1, 1);
}<|endoftext|>


<commit_before>define('app/controllers/machine_add', ['ember'],
    /**
     *  Machine Add Controller
     *
     *  @returns Class
     */
    function() {
        return Ember.Object.extend({

            /**
             *  Properties
             */

            callback: null,
            formReady: null,

            newMachineKey: null,
            newMachineName: null,
            newMachineSize: null,
            newMachineImage: null,
            newMachineScript: null,
            newMachineLocation: null,
            newMachineProvider: null,

            /**
             *
             *  Methods
             *
             */

            open: function(callback) {
                // In case page is scrolled, opening the
                // panel introduces an unpleasant view.
                // Scrolling to top fixes that
                $('.ui-page-active').animate({scrollTop:0}, 'slow');
                $('#create-machine-panel .ui-panel-inner').animate({scrollTop:0}, 'slow');
                $('#create-machine-panel').panel('open');
                $('.ui-panel-dismiss-position-right').css('right',($('.ui-panel-position-right.ui-panel-open').width()));
                Ember.run.next(function(){
                    var panelHeight = $('.ui-panel-open').height(),
                        pageHeight = $('.ui-page-active').height();
                    if ( panelHeight > pageHeight) {
                        $('.ui-page-active').height(panelHeight);
                    }
                });
               $('#create-machine-location').addClass('ui-state-disabled');
               $('#create-machine-image').addClass('ui-state-disabled');
               $('#create-machine-size').addClass('ui-state-disabled');
               $('#create-machine-key').addClass('ui-state-disabled');

                this._clear();
                this._updateFormReady();
                this.set('callback', callback);
            },

            close: function() {
                $('#create-machine-panel').panel('close');
                this._clear();
            },

            add: function() {

                var providerName = this.newMachineProvider.title;
                var machineSize = this.newMachineSize.name;
                var machineImage = this.newMachineImage.name;
                var machineName = this.newMachineName;

                // Validate machine name
                // TODO: This thing is ugly. Move regex and strings into a dict

                if (providerName == 'NephoScale') {
                    var re = /^[0-9a-zA-Z-_]*$/;
                    if ( machineName.length > 64 || !re.test(machineName)) {

                        Mist.notificationController.timeNotify(
                            'Server name in NephoScale must start with a letter, can contain mixed alpha-numeric ' +
                            'characters, hyphen (\'-\') and underscore (\'_\') characters, cannot exceed 64 ' +
                            'characters, and can end with a letter or a number.', 7000);
                        return;
                    }
                    if (machineSize.indexOf('CS025') > -1) {
                        if ((machineImage != 'Linux Ubuntu Server 10.04 LTS 64-bit') &&
                            (machineImage !='Linux CentOS 6.2 64-bit')) {

                                Mist.notificationController.timeNotify(
                                    'On CS025 size you can only create one of the two images: ' +
                                    'Linux Ubuntu Server 10.04 LTS 64-bit or Linux CentOS 6.2 64-bit', 7000);
                                return;
                        }
                    }
                }
                if (providerName == 'DigitalOcean') {
                    var re = /^[0-9a-zA-Z-.]*$/;
                    if (!re.test(machineName)) {
                        Mist.notificationController.timeNotify('Characters allowed are a-z, A-Z, 0-9, . and -', 7000);
                        return;
                    }
                }
                if (providerName == 'Linode') {
                    var re = /^[0-9a-zA-Z-_]*$/;
                    if (!re.test(machineName)) {
                        Mist.notificationController.timeNotify(
                            'A Linode label may only contain ASCII letters or numbers, dashes and underscores. Must ' +
                            'begin and end with letters or numbers, and be at least 3 characters long', 7000);
                        return;
                    }
                }
                if (providerName == 'SoftLayer') {
                    var re = /^[0-9a-zA-Z.-]*$/;
                    if (machineName.length > 253 || !re.test(machineName)) {
                        Mist.notificationController.timeNotify(
                            'Server name in Softlayer must be an alphanumeric string,' +
                            ' that may contain period (\'.\') and dash (\'-\') special characters.', 7000);
                        return;
                    }
                }

                var that = this;
                this.newMachineProvider.machines.newMachine(
                        this.newMachineName,
                        this.newMachineImage,
                        this.newMachineSize,
                        this.newMachineLocation,
                        this.newMachineKey,
                        this.newMachineScript,
                        function(success, machine) {
                            that._giveCallback(success, machine);
                        }
                );

                this.close();
            },

            /**
             *
             *  Pseudo-Private Methods
             *
             */

             _clear: function() {
                this.set('callback', null)
                    .set('newMachineName', '')
                    .set('newMachineScript', '')
                    .set('newMachineKey', {'id' : 'Select Key'})
                    .set('newMachineSize', {'name' : 'Select Size'})
                    .set('newMachineImage', {'name' : 'Select Image'})
                    .set('newMachineLocation', {'name' : 'Select Location'})
                    .set('newMachineProvider', {'title' : 'Select Provider'});
             },

            _updateFormReady: function() {
                var formReady = false;
                if (this.newMachineName &&
                    this.newMachineSize.id &&
                    this.newMachineImage.id &&
                    this.newMachineLocation.id &&
                    this.newMachineProvider.id &&
                    Mist.keysController.keyExists(this.newMachineKey.id)) {
                        formReady = true;
                }
                this.set('formReady', formReady);
            },

            _giveCallback: function(success, machine) {
                if (this.callback) this.callback(success, machine);
            },

            /**
             *
             *  Observers
             *
             */

            formObserver: function() {
                Ember.run.once(this, '_updateFormReady');
            }.observes('newMachineKey',
                       'newMachineName',
                       'newMachineSize',
                       'newMachineImage',
                       'newMachineScript',
                       'newMachineLocation',
                       'newMachineProvider')
        });
    }
);
<commit_msg>Redirect user to machine list view after launch machine from image list view<commit_after>define('app/controllers/machine_add', ['ember'],
    /**
     *  Machine Add Controller
     *
     *  @returns Class
     */
    function() {
        return Ember.Object.extend({

            /**
             *  Properties
             */

            callback: null,
            formReady: null,

            newMachineKey: null,
            newMachineName: null,
            newMachineSize: null,
            newMachineImage: null,
            newMachineScript: null,
            newMachineLocation: null,
            newMachineProvider: null,

            /**
             *
             *  Methods
             *
             */

            open: function(callback) {
                // In case page is scrolled, opening the
                // panel introduces an unpleasant view.
                // Scrolling to top fixes that
                $('.ui-page-active').animate({scrollTop:0}, 'slow');
                $('#create-machine-panel .ui-panel-inner').animate({scrollTop:0}, 'slow');
                $('#create-machine-panel').panel('open');
                $('.ui-panel-dismiss-position-right').css('right',($('.ui-panel-position-right.ui-panel-open').width()));
                Ember.run.next(function(){
                    var panelHeight = $('.ui-panel-open').height(),
                        pageHeight = $('.ui-page-active').height();
                    if ( panelHeight > pageHeight) {
                        $('.ui-page-active').height(panelHeight);
                    }
                });
               $('#create-machine-location').addClass('ui-state-disabled');
               $('#create-machine-image').addClass('ui-state-disabled');
               $('#create-machine-size').addClass('ui-state-disabled');
               $('#create-machine-key').addClass('ui-state-disabled');

                this._clear();
                this._updateFormReady();
                this.set('callback', callback);
            },

            close: function() {
                $('#create-machine-panel').panel('close');
                this._clear();
            },

            add: function() {

                var providerName = this.newMachineProvider.title;
                var machineSize = this.newMachineSize.name;
                var machineImage = this.newMachineImage.name;
                var machineName = this.newMachineName;

                // Validate machine name
                // TODO: This thing is ugly. Move regex and strings into a dict

                if (providerName == 'NephoScale') {
                    var re = /^[0-9a-zA-Z-_]*$/;
                    if ( machineName.length > 64 || !re.test(machineName)) {

                        Mist.notificationController.timeNotify(
                            'Server name in NephoScale must start with a letter, can contain mixed alpha-numeric ' +
                            'characters, hyphen (\'-\') and underscore (\'_\') characters, cannot exceed 64 ' +
                            'characters, and can end with a letter or a number.', 7000);
                        return;
                    }
                    if (machineSize.indexOf('CS025') > -1) {
                        if ((machineImage != 'Linux Ubuntu Server 10.04 LTS 64-bit') &&
                            (machineImage !='Linux CentOS 6.2 64-bit')) {

                                Mist.notificationController.timeNotify(
                                    'On CS025 size you can only create one of the two images: ' +
                                    'Linux Ubuntu Server 10.04 LTS 64-bit or Linux CentOS 6.2 64-bit', 7000);
                                return;
                        }
                    }
                }
                if (providerName == 'DigitalOcean') {
                    var re = /^[0-9a-zA-Z-.]*$/;
                    if (!re.test(machineName)) {
                        Mist.notificationController.timeNotify('Characters allowed are a-z, A-Z, 0-9, . and -', 7000);
                        return;
                    }
                }
                if (providerName == 'Linode') {
                    var re = /^[0-9a-zA-Z-_]*$/;
                    if (!re.test(machineName)) {
                        Mist.notificationController.timeNotify(
                            'A Linode label may only contain ASCII letters or numbers, dashes and underscores. Must ' +
                            'begin and end with letters or numbers, and be at least 3 characters long', 7000);
                        return;
                    }
                }
                if (providerName == 'SoftLayer') {
                    var re = /^[0-9a-zA-Z.-]*$/;
                    if (machineName.length > 253 || !re.test(machineName)) {
                        Mist.notificationController.timeNotify(
                            'Server name in Softlayer must be an alphanumeric string,' +
                            ' that may contain period (\'.\') and dash (\'-\') special characters.', 7000);
                        return;
                    }
                }

                var that = this;
                this.newMachineProvider.machines.newMachine(
                        this.newMachineName,
                        this.newMachineImage,
                        this.newMachineSize,
                        this.newMachineLocation,
                        this.newMachineKey,
                        this.newMachineScript,
                        function(success, machine) {
                            that._giveCallback(success, machine);
                        }
                );

                this.close();

                // Redirect to machine list view if user is in image list view
                if ($('#image-list-page').length) {
                    Mist.Router.router.transitionTo('machines');
                }
            },

            /**
             *
             *  Pseudo-Private Methods
             *
             */

             _clear: function() {
                this.set('callback', null)
                    .set('newMachineName', '')
                    .set('newMachineScript', '')
                    .set('newMachineKey', {'id' : 'Select Key'})
                    .set('newMachineSize', {'name' : 'Select Size'})
                    .set('newMachineImage', {'name' : 'Select Image'})
                    .set('newMachineLocation', {'name' : 'Select Location'})
                    .set('newMachineProvider', {'title' : 'Select Provider'});
             },

            _updateFormReady: function() {
                var formReady = false;
                if (this.newMachineName &&
                    this.newMachineSize.id &&
                    this.newMachineImage.id &&
                    this.newMachineLocation.id &&
                    this.newMachineProvider.id &&
                    Mist.keysController.keyExists(this.newMachineKey.id)) {
                        formReady = true;
                }
                this.set('formReady', formReady);
            },

            _giveCallback: function(success, machine) {
                if (this.callback) this.callback(success, machine);
            },

            /**
             *
             *  Observers
             *
             */

            formObserver: function() {
                Ember.run.once(this, '_updateFormReady');
            }.observes('newMachineKey',
                       'newMachineName',
                       'newMachineSize',
                       'newMachineImage',
                       'newMachineScript',
                       'newMachineLocation',
                       'newMachineProvider')
        });
    }
);
<|endoftext|>


<commit_before>(function() {

  var dash = angular.module("zingTwit", []);

  dash.controller('ChartController', ['$scope', '$http', function($scope, $http) {
    this.panel = 0;

    this.barChart = barChart;
    this.pieChart = pieChart;
    this.gaugeChart = gaugeChart;
    this.pianoChart = pianoChart;
    this.pieThreeDChart = pieThreeDChart;

    this.charts = [this.barChart, this.pieChart, this.gaugeChart, this.pianoChart, this.pieThreeDChart];

    this.twitterQueries = [];
    this.userQuery; //each user/search will be assigned to this string, have to break it up

// THINGS TO FIX:::

    // Top left of Donut chart has what looks like legend info clumped together
    // Center graphs in Div
    // chart Axis labels
    // Before you search, the header has a grey background color(like the ".well" class)

    this.assignData = function(userData) {
        this.barChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.followers_count]
         });   // barChart ====== Followers

        this.pianoChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.followers_count, userData.friends_count, userData.statuses_count, userData.status_retweets]
        });

        this.pieChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.friends_count]
        });

        this.gaugeChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.statuses_count]
        });

        this.pieThreeDChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.status_retweets]
        });
    }

    this.renderChart = function(chart) {
      zingchart.render({
        id: chart.divId,
        data: chart.data,
        height: 400,
        width: "80%"
      });
    },

    this.queryTwitter = function() {
      this.postDB(this.userQuery);
      this.userQuery = ""; //reset text field.

    },

    this.postDB = function(userQuery) {
      var dashScope = this
      $http.put('/search', { query : userQuery })

        .success(function(data) {
          dashScope.twitterQueries.push(data)
          dashScope.assignData(data);
          dashScope.panel === 0 ? dashScope.panel = 1 : dashScope.panel;
          console.log("Successful Query::DashController::postDb()");
        })
        .error(function(err) {
          console.log("Request to /search did no work: " + err);
        });
    },

    this.clearData = function() {
      console.log("CLEARING DATA")
      for (var index = 0;index < this.charts.length; index++) {
        this.charts[index].data.series = [];
      }
      this.panel = 0;
    },

    this.selectPanel = function(newPanel) {
      this.panel = newPanel;
    };
    this.isSelected = function(checkPanel) {
      return this.panel === checkPanel;
    }

  }]); // END of Chart Controller

/////////////////////////////////////
///////     Chart Objects     ///////
/////////////////////////////////////

  function Chart(data, divId) {
    this.data = data;
    this.divId = divId;
  }

  var barData = {
    "type":"bar",
    "title": {
      "text":"Number of Followers"
    },
    "chart" : {
      "marginLeft" : "50px"
    },
    "scale-x" : {
      "values" : ["User(s)"]
    },
    "legend" : {},
    "plot": {
        "valueBox": {
            "type": "all",
            "placement": "top"
        }
    },
    "series": []
  }

  var pieData = {
    "type":"pie",
    "title": {
      "text":"Number of Friends"
    },
    "series": []
  }

  var pieThreeD = {
    "type":"pie",
    "title": {
      "text":"Number of Retweets"
    },
    "plot" : {
       "slice" : 45
    },
    "series": []
  }

  var gaugeData = {
    "type":"gauge",
    "title": {
      "text":"Number of Tweets"
    },
    "legend" : {},
    "plot": {
        "valueBox": {
            "type": "all",
            "placement": "top"
        }
    },
    "series": []
  }
  var pianoData = {
    "type":"piano",
    "title": {
      "text":"User Data"
    },
    "scale-x" : {
        "values" : ["Followers", "Friends", "Tweets", "Retweets"]
    },
    "legend" : {},
    "chart" : {
      "marginLeft" : "100px"
    },
    "series": []
  }

  var barChart = new Chart(barData, 'barChart');
  var pieChart = new Chart(pieData, 'pieChart');
  var gaugeChart = new Chart(gaugeData, 'gaugeChart');
  var pianoChart = new Chart(pianoData, 'pianoChart');
  var pieThreeDChart = new Chart(pieThreeD, 'pieThreeDChart')
})();<commit_msg>widened charts to evenly fit in div<commit_after>(function() {

  var dash = angular.module("zingTwit", []);

  dash.controller('ChartController', ['$scope', '$http', function($scope, $http) {
    this.panel = 0;

    this.barChart = barChart;
    this.pieChart = pieChart;
    this.gaugeChart = gaugeChart;
    this.pianoChart = pianoChart;
    this.pieThreeDChart = pieThreeDChart;

    this.charts = [this.barChart, this.pieChart, this.gaugeChart, this.pianoChart, this.pieThreeDChart];

    this.twitterQueries = [];
    this.userQuery; //each user/search will be assigned to this string, have to break it up

// THINGS TO FIX:::

    // Top left of Donut chart has what looks like legend info clumped together
    // Center graphs in Div
    // chart Axis labels
    // Before you search, the header has a grey background color(like the ".well" class)

    this.assignData = function(userData) {
        this.barChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.followers_count]
         });   // barChart ====== Followers

        this.pianoChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.followers_count, userData.friends_count, userData.statuses_count, userData.status_retweets]
        });

        this.pieChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.friends_count]
        });

        this.gaugeChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.statuses_count]
        });

        this.pieThreeDChart.data.series.push({
          "text" : "@" + userData.screen_name,
          "values" : [userData.status_retweets]
        });
    }

    this.renderChart = function(chart) {
      zingchart.render({
        id: chart.divId,
        data: chart.data,
        height: 400,
        width: "97%"
      });
    },

    this.queryTwitter = function() {
      this.postDB(this.userQuery);
      this.userQuery = ""; //reset text field.

    },

    this.postDB = function(userQuery) {
      var dashScope = this
      $http.put('/search', { query : userQuery })

        .success(function(data) {
          dashScope.twitterQueries.push(data)
          dashScope.assignData(data);
          dashScope.panel === 0 ? dashScope.panel = 1 : dashScope.panel;
          console.log("Successful Query::DashController::postDb()");
        })
        .error(function(err) {
          console.log("Request to /search did no work: " + err);
        });
    },

    this.clearData = function() {
      console.log("CLEARING DATA")
      for (var index = 0;index < this.charts.length; index++) {
        this.charts[index].data.series = [];
      }
      this.panel = 0;
    },

    this.selectPanel = function(newPanel) {
      this.panel = newPanel;
    };
    this.isSelected = function(checkPanel) {
      return this.panel === checkPanel;
    }

  }]); // END of Chart Controller

/////////////////////////////////////
///////     Chart Objects     ///////
/////////////////////////////////////

  function Chart(data, divId) {
    this.data = data;
    this.divId = divId;
  }

  var barData = {
    "type":"bar",
    "title": {
      "text":"Number of Followers"
    },
    "chart" : {
      "marginLeft" : "50px"
    },
    "scale-x" : {
      "values" : ["User(s)"]
    },
    "legend" : {},
    "plot": {
        "valueBox": {
            "type": "all",
            "placement": "top"
        }
    },
    "series": []
  }

  var pieData = {
    "type":"pie",
    "title": {
      "text":"Number of Friends"
    },
    "series": []
  }

  var pieThreeD = {
    "type":"pie",
    "title": {
      "text":"Number of Retweets"
    },
    "plot" : {
       "slice" : 45
    },
    "series": []
  }

  var gaugeData = {
    "type":"gauge",
    "title": {
      "text":"Number of Tweets"
    },
    "legend" : {},
    "plot": {
        "valueBox": {
            "type": "all",
            "placement": "top"
        }
    },
    "series": []
  }
  var pianoData = {
    "type":"piano",
    "title": {
      "text":"User Data"
    },
    "scale-x" : {
        "values" : ["Followers", "Friends", "Tweets", "Retweets"]
    },
    "legend" : {},
    "chart" : {
      "marginLeft" : "100px"
    },
    "series": []
  }

  var barChart = new Chart(barData, 'barChart');
  var pieChart = new Chart(pieData, 'pieChart');
  var gaugeChart = new Chart(gaugeData, 'gaugeChart');
  var pianoChart = new Chart(pianoData, 'pianoChart');
  var pieThreeDChart = new Chart(pieThreeD, 'pieThreeDChart')
})();<|endoftext|>


<commit_before><<<<<<< Updated upstream

function TimesheetDb() {
    this.month = 0;
    this.month_data = null;

    this.load = function(date) {
        var ret = null;

        chrome.storage.sync.get(date.toString(), function(item) {
            console.log("Got item: ", item);
            ret = item;
        });

        return item;
    }

    this.load_month = function(month) {

    }

    this.update = function(date_map) {
        chrome.storage.sync.set(date_map);
    }
}

function dateFromString(dateStr) {
    var d = new Date();
    var year = d.getFullYear();
    var dateStr = dateStr.slice(3);

    if (dateStr.length >= 3) {
        var datePrts = dateStr.split("/");
        if (datePrts.length == 2) {
            // Subtract one from month b/c indexed at 0
            return new Date(year, (parseInt(datePrts[0]) - 1), parseInt(datePrts[1]));
        } else {
            return null;
        }
    } else {
        return null;
    }
}

function parseTimesheet(appBody) {
    var timesheet = [];

    console.log("Getting charge numbers...");
    appBody.find("#udtColumn0").children().each(function(index, item) {
        var title = $(item).attr("title");
        var charge_number = appBody.find("#udt" + index + "_1").text();
        if (title && charge_number) {
            timesheet.push({title:title, charge_number:charge_number, hours:[]});
        }
    });

    console.log("Getting dates...");
    appBody.find("#hrsHeader").children().each(function(index, item) {
        for (var i = 0; i < timesheet.length; i++) {
            var date = dateFromString($(item).text());
            if (date) {
                timesheet[i].hours.push({date:date, value:0});
            }
        }
    });

    console.log("Getting hours...");
    for (var i = 0; i < timesheet.length; i++) {
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var id = "#hrs" + i + "_" + j;
            var hours = appBody.find(id).text();
            hours = parseFloat(hours);
            if (isNaN(hours)) {
                hours = 0;
            }
            timesheet[i].hours[j].value = hours;
        }
    }

    console.log("Converting...");
    date_map_timesheet = {};
    for (var i = 0; i < timesheet.length; i++) {
        var charge_str = timesheet[i].title;
        var charge_number = timesheet[i].charge_number;
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var key = timesheet[i].hours[j].date.toString();

            if (!(key in date_map_timesheet)) {
                date_map_timesheet[key] = [];
            }

            date_map_timesheet[key].push({
                title: charge_str,
                charge_number:charge_number,
                value: timesheet[i].hours[j].value
            });
        }
    }

    return date_map_timesheet;
}

function setTimesheetChangeHook(appBody, db) {
    console.log("Setting timesheet change hooks...");

    appBody.find("#editor").on("blur", function(event) {
        var parent = event.currentTarget.parentNode;
        var id = $(parent).attr("id");

        if (id && id.startsWith("hrs")) {
            var hours = parseFloat($(this).val());
            if (isNaN(hours)) {
                hours = 0.0;
            }

            ts = parseTimesheet(appBody);

            var row_col_str = id.slice(3);
            var row_col = row_col_str.split("_");
            var col = 0;
            var row = 0;
            var date = null;

            if (row_col.length != 2) {
                console.log("ERROR: Could not get column for current hours entry");
                return;
            } else {
                row = row_col[0];
                col = row_col[1];
            }

            var dateStr = appBody.find("#hrsHeaderText"+col).text();

            date = dateFromString(dateStr);

            if (date) {
                ts[date][row].value = hours;
                console.log("Updated TS: ", ts);
                db.update(ts);
            }
        }
    });
}

$(document).ready(function() {
    console.log("Deltrek Activated. On Deltek page.");

    var db = new TimesheetDb();

    $("#unitFrame").on("load", function(){
        console.log("Iframe loaded. Scanning for timesheet application...");
        appBody = $("#unitFrame").contents().find("body");

        if (appBody.find("#appTitle").text() == "Timesheet") {
            console.log("Timesheet found!");

            ts = parseTimesheet(appBody);
            console.log("Parsed: ", ts);
            db.update(ts);

            setTimesheetChangeHook(appBody, db);
        } else {
            console.log("Not on timesheet page. App title: ", appBody.find("#appTitle").text());
        }
    });
});<commit_msg>Remove Git merge comment<commit_after>function TimesheetDb() {
    this.month = 0;
    this.month_data = null;

    this.load = function(date) {
        var ret = null;

        chrome.storage.sync.get(date.toString(), function(item) {
            console.log("Got item: ", item);
            ret = item;
        });

        return item;
    }

    this.load_month = function(month) {

    }

    this.update = function(date_map) {
        chrome.storage.sync.set(date_map);
    }
}

function dateFromString(dateStr) {
    var d = new Date();
    var year = d.getFullYear();
    var dateStr = dateStr.slice(3);

    if (dateStr.length >= 3) {
        var datePrts = dateStr.split("/");
        if (datePrts.length == 2) {
            // Subtract one from month b/c indexed at 0
            return new Date(year, (parseInt(datePrts[0]) - 1), parseInt(datePrts[1]));
        } else {
            return null;
        }
    } else {
        return null;
    }
}

function parseTimesheet(appBody) {
    var timesheet = [];

    console.log("Getting charge numbers...");
    appBody.find("#udtColumn0").children().each(function(index, item) {
        var title = $(item).attr("title");
        var charge_number = appBody.find("#udt" + index + "_1").text();
        if (title && charge_number) {
            timesheet.push({title:title, charge_number:charge_number, hours:[]});
        }
    });

    console.log("Getting dates...");
    appBody.find("#hrsHeader").children().each(function(index, item) {
        for (var i = 0; i < timesheet.length; i++) {
            var date = dateFromString($(item).text());
            if (date) {
                timesheet[i].hours.push({date:date, value:0});
            }
        }
    });

    console.log("Getting hours...");
    for (var i = 0; i < timesheet.length; i++) {
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var id = "#hrs" + i + "_" + j;
            var hours = appBody.find(id).text();
            hours = parseFloat(hours);
            if (isNaN(hours)) {
                hours = 0;
            }
            timesheet[i].hours[j].value = hours;
        }
    }

    console.log("Converting...");
    date_map_timesheet = {};
    for (var i = 0; i < timesheet.length; i++) {
        var charge_str = timesheet[i].title;
        var charge_number = timesheet[i].charge_number;
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var key = timesheet[i].hours[j].date.toString();

            if (!(key in date_map_timesheet)) {
                date_map_timesheet[key] = [];
            }

            date_map_timesheet[key].push({
                title: charge_str,
                charge_number:charge_number,
                value: timesheet[i].hours[j].value
            });
        }
    }

    return date_map_timesheet;
}

function setTimesheetChangeHook(appBody, db) {
    console.log("Setting timesheet change hooks...");

    appBody.find("#editor").on("blur", function(event) {
        var parent = event.currentTarget.parentNode;
        var id = $(parent).attr("id");

        if (id && id.startsWith("hrs")) {
            var hours = parseFloat($(this).val());
            if (isNaN(hours)) {
                hours = 0.0;
            }

            ts = parseTimesheet(appBody);

            var row_col_str = id.slice(3);
            var row_col = row_col_str.split("_");
            var col = 0;
            var row = 0;
            var date = null;

            if (row_col.length != 2) {
                console.log("ERROR: Could not get column for current hours entry");
                return;
            } else {
                row = row_col[0];
                col = row_col[1];
            }

            var dateStr = appBody.find("#hrsHeaderText"+col).text();

            date = dateFromString(dateStr);

            if (date) {
                ts[date][row].value = hours;
                console.log("Updated TS: ", ts);
                db.update(ts);
            }
        }
    });
}

$(document).ready(function() {
    console.log("Deltrek Activated. On Deltek page.");

    var db = new TimesheetDb();

    $("#unitFrame").on("load", function(){
        console.log("Iframe loaded. Scanning for timesheet application...");
        appBody = $("#unitFrame").contents().find("body");

        if (appBody.find("#appTitle").text() == "Timesheet") {
            console.log("Timesheet found!");

            ts = parseTimesheet(appBody);
            console.log("Parsed: ", ts);
            db.update(ts);

            setTimesheetChangeHook(appBody, db);
        } else {
            console.log("Not on timesheet page. App title: ", appBody.find("#appTitle").text());
        }
    });
});<|endoftext|>


<commit_before>/**
 * Special case for drija, as they clone askubuntu, serverfault etc
 * questions as well as SO. Regex on the source question is thus a
 * little sloppier and more prone to false positives, so it's spun
 * out separate to the regex for the other sites to focus on drija alone.
 */
var soResults = document.querySelectorAll('a[href*=".com/questions/"]');
document.location = soResults.item(0).href;<commit_msg>Prevent js errors on non-q pages on djira<commit_after>/**
 * Special case for drija, as they clone askubuntu, serverfault etc
 * questions as well as SO. Regex on the source question is thus a
 * little sloppier and more prone to false positives, so it's spun
 * out separate to the regex for the other sites to focus on drija alone.
 *
 * Two options here: Url regex to determine if we're on q page (of form
 * djira.com/TOPIC-WORDS/ID/TITLE) or attempt the queryselector and just
 * see if we've a result. Going with the latter here..
 */
var soResults = document.querySelectorAll('a[href*=".com/questions/"]');
if(soResults.item(0))
{
    document.location = soResults.item(0).href;
}<|endoftext|>


<commit_before>( function( mw, $ ) {"use strict";
	mw.PluginManager.add( 'largePlayBtn', mw.KBaseComponent.extend({
		//indicates we were explicitly asked to show the button (will be used when re-enabling the button)
		shouldShow : false,
		isDisabled: false,
		defaultConfig: {
			'parent': 'videoHolder',
			'togglePause': true,
			'order': 1
		},
		setup: function() {
			this.addBindings();
		},
		/**
		 * Checks if the play button should stay on screen during playback,
		 * cases where a native player is dipalyed such as iPhone.
		 */
		isPersistantPlayBtn: function(){
			return (mw.isAndroid2() || this.getPlayer().isLinkPlayer() || ( mw.isIphone() && mw.getConfig( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' )) && !mw.isWindowsPhone() );
		},
		addBindings: function() {
			var _this = this;
			this.bind('showInlineDownloadLink', function(e, linkUrl){
				_this.getComponent().attr({
					'href': linkUrl.replace('playSessionId=','playSessionId=noev-'),
					'target': '_blank'
				});
			});

			this.bind('onChangeMediaDone playerReady onpause onEndedDone onRemovePlayerSpinner showPlayerControls showLargePlayBtn', function(e){
				if( !_this.embedPlayer.isPlaying() && !_this.embedPlayer.isInSequence() && !_this.embedPlayer.isPauseLoading ){
					_this.getComponent().removeClass("icon-pause").addClass("icon-play");
					_this.show();
				}
			});

			this.bind('onShowControlBar', function(){
				if( !mw.isIE8() && _this.getConfig("togglePause") && _this.embedPlayer.isPlaying() && !_this.embedPlayer.isInSequence() ){
					_this.getComponent().removeClass("icon-play").addClass("icon-pause");
					_this.show();
				}
			});
			this.bind('playing AdSupport_StartAdPlayback onHideControlBar onChangeMedia', function(e){
				_this.hide();
			});
			this.bind('onAddPlayerSpinner showScreen', function(e){
				_this.hide(true);
			});
			this.bind('onPlayerStateChange', function(e, newState, oldState){
				if( newState == 'load' || newState == 'play' ){
					_this.hide(true);
				}
				if( newState == 'pause' && _this.getPlayer().isPauseLoading ){
					_this.hide();
				}
			});
			this.bind( 'hideScreen', function(){
				if (mw.isMobileDevice() && _this.getPlayer().paused){
					_this.show();
				}
			});
            this.bind('liveOnline', function(){
                if( _this.getPlayer().isLive && !_this.getPlayer().isDVR() ) {
                    _this.hide();
                }
            });
		},
		show: function(){
			if ( !this.isDisabled && !this.embedPlayer.layoutBuilder.displayOptionsMenuFlag ) {
				if (this.embedPlayer.isMobileSkin() && (this.embedPlayer.changeMediaStarted || this.embedPlayer.buffering)){
					return; // prevent showing large play button on top of the spinner when using mobile skin and changing media
				}

				if (this.embedPlayer.isMobileSkin()){
					this.getComponent().fadeIn('fast').css('display', "flex");
				} else {
					this.getComponent().css('display', "block");
				}
			}
			this.shouldShow = true;
		},
		hide: function( force ){
			this.hideComponent( force );
			this.shouldShow = false;
		},
		hideComponent: function( force ) {
			if( force || !this.isPersistantPlayBtn() ) {
				this.getComponent().hide();
			}
		},
		clickButton: function( event ){
			// If link player, only trigger events
			if( this.getPlayer().isLinkPlayer() ) {
				this.getPlayer().triggerHelper( 'firstPlay' ); // To send stats event for play
				this.getPlayer().triggerHelper( 'playing' );
				return;
			}

			event.preventDefault();
			event.stopPropagation();
			if ( this.getConfig("togglePause") && this.getPlayer().isPlaying() ){
				this.getPlayer().sendNotification('doPause',{'userInitiated': true});
			}else{
				this.getPlayer().triggerHelper( 'goingtoplay' );
				this.getPlayer().sendNotification('doPlay',{'userInitiated': true});
			}
		},
		onEnable: function(){
			this.isDisabled = false;
			if ( this.shouldShow ) {
				this.show();
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.hideComponent();
		},
		getComponent: function() {
			var _this = this;
			var eventName = 'click';
			if ( mw.isAndroid() ){
				eventName += ' touchstart';
			}
			if( !this.$el ) {
				this.$el = $( '<a />' )
							.attr( {
								'tabindex': '-1',
								'href' : '#',
								'title' : gM( 'mwe-embedplayer-play_clip' ),
								'class'	: "icon-play " + this.getCssClass()
							} )
							.hide()
							// Add play hook:
							.on(eventName, function(e) {
								_this.clickButton(e);
							} );
				if ( !mw.isWindowsPhone() ){
					this.$el.addClass("largePlayBtnBorder");
				}
			}
			return this.$el;
		}
	})
	);

} )( window.mw, window.jQuery );<commit_msg>FEC-5728 #comment show playPauseBtn when closing a menu overlay if in pause state (#2861)<commit_after>( function( mw, $ ) {"use strict";
	mw.PluginManager.add( 'largePlayBtn', mw.KBaseComponent.extend({
		//indicates we were explicitly asked to show the button (will be used when re-enabling the button)
		shouldShow : false,
		isDisabled: false,
		defaultConfig: {
			'parent': 'videoHolder',
			'togglePause': true,
			'order': 1
		},
		setup: function() {
			this.addBindings();
		},
		/**
		 * Checks if the play button should stay on screen during playback,
		 * cases where a native player is dipalyed such as iPhone.
		 */
		isPersistantPlayBtn: function(){
			return (mw.isAndroid2() || this.getPlayer().isLinkPlayer() || ( mw.isIphone() && mw.getConfig( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' )) && !mw.isWindowsPhone() );
		},
		addBindings: function() {
			var _this = this;
			this.bind('showInlineDownloadLink', function(e, linkUrl){
				_this.getComponent().attr({
					'href': linkUrl.replace('playSessionId=','playSessionId=noev-'),
					'target': '_blank'
				});
			});

			this.bind('onChangeMediaDone playerReady onpause onEndedDone onRemovePlayerSpinner showPlayerControls showLargePlayBtn', function(e){
				if( !_this.embedPlayer.isPlaying() && !_this.embedPlayer.isInSequence() && !_this.embedPlayer.isPauseLoading ){
					_this.getComponent().removeClass("icon-pause").addClass("icon-play");
					_this.show();
				}
			});

			this.bind('onShowControlBar', function(){
				if( !mw.isIE8() && _this.getConfig("togglePause") && _this.embedPlayer.isPlaying() && !_this.embedPlayer.isInSequence() ){
					_this.getComponent().removeClass("icon-play").addClass("icon-pause");
					_this.show();
				}
			});
			this.bind('playing AdSupport_StartAdPlayback onHideControlBar onChangeMedia', function(e){
				_this.hide();
			});
			this.bind('onAddPlayerSpinner showScreen', function(e){
				_this.hide(true);
			});
			this.bind('onPlayerStateChange', function(e, newState, oldState){
				if( newState == 'load' || newState == 'play' ){
					_this.hide(true);
				}
				if( newState == 'pause' && _this.getPlayer().isPauseLoading ){
					_this.hide();
				}
			});
			this.bind( 'hideScreen closeMenuOverlay', function(){
				if (mw.isMobileDevice() && _this.getPlayer().paused){
					_this.show();
				}
			});
            this.bind('liveOnline', function(){
                if( _this.getPlayer().isLive && !_this.getPlayer().isDVR() ) {
                    _this.hide();
                }
            });
		},
		show: function(){
			if ( !this.isDisabled && !this.embedPlayer.layoutBuilder.displayOptionsMenuFlag ) {
				if (this.embedPlayer.isMobileSkin() && (this.embedPlayer.changeMediaStarted || this.embedPlayer.buffering)){
					return; // prevent showing large play button on top of the spinner when using mobile skin and changing media
				}

				if (this.embedPlayer.isMobileSkin()){
					this.getComponent().fadeIn('fast').css('display', "flex");
				} else {
					this.getComponent().css('display', "block");
				}
			}
			this.shouldShow = true;
		},
		hide: function( force ){
			this.hideComponent( force );
			this.shouldShow = false;
		},
		hideComponent: function( force ) {
			if( force || !this.isPersistantPlayBtn() ) {
				this.getComponent().hide();
			}
		},
		clickButton: function( event ){
			// If link player, only trigger events
			if( this.getPlayer().isLinkPlayer() ) {
				this.getPlayer().triggerHelper( 'firstPlay' ); // To send stats event for play
				this.getPlayer().triggerHelper( 'playing' );
				return;
			}

			event.preventDefault();
			event.stopPropagation();
			if ( this.getConfig("togglePause") && this.getPlayer().isPlaying() ){
				this.getPlayer().sendNotification('doPause',{'userInitiated': true});
			}else{
				this.getPlayer().triggerHelper( 'goingtoplay' );
				this.getPlayer().sendNotification('doPlay',{'userInitiated': true});
			}
		},
		onEnable: function(){
			this.isDisabled = false;
			if ( this.shouldShow ) {
				this.show();
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.hideComponent();
		},
		getComponent: function() {
			var _this = this;
			var eventName = 'click';
			if ( mw.isAndroid() ){
				eventName += ' touchstart';
			}
			if( !this.$el ) {
				this.$el = $( '<a />' )
							.attr( {
								'tabindex': '-1',
								'href' : '#',
								'title' : gM( 'mwe-embedplayer-play_clip' ),
								'class'	: "icon-play " + this.getCssClass()
							} )
							.hide()
							// Add play hook:
							.on(eventName, function(e) {
								_this.clickButton(e);
							} );
				if ( !mw.isWindowsPhone() ){
					this.$el.addClass("largePlayBtnBorder");
				}
			}
			return this.$el;
		}
	})
	);

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


<commit_before>/**
 * Pie
 *
 * Formats the pies labels.
 * @param {Object} slice - Slice object
 * @return {String} Formatted pie label string
 */
(function () {

var
  _ = Flotr._;

Flotr.defaultPieLabelFormatter = function (total, value) {
  return (100 * value / total).toFixed(2)+'%';
};

Flotr.addType('pie', {
  options: {
    show: false,           // => setting to true will show bars, false will hide
    lineWidth: 1,          // => in pixels
    fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill
    fillColor: null,       // => fill color
    fillOpacity: 0.6,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
    explode: 6,            // => the number of pixels the splices will be far from the center
    sizeRatio: 0.6,        // => the size ratio of the pie relative to the plot
    startAngle: Math.PI/4, // => the first slice start angle
    labelFormatter: Flotr.defaultPieLabelFormatter,
    pie3D: false,          // => whether to draw the pie in 3 dimenstions or not (ineffective)
    pie3DviewAngle: (Math.PI/2 * 0.8),
    pie3DspliceThickness: 20,
    epsilon: 0.1           // => how close do you have to get to hit empty slice
  },

  draw : function (options) {

    // TODO 3D charts what?

    var
      data          = options.data,
      context       = options.context,
      canvas        = context.canvas,
      lineWidth     = options.lineWidth,
      shadowSize    = options.shadowSize,
      sizeRatio     = options.sizeRatio,
      height        = options.height,
      width         = options.width,
      explode       = options.explode,
      color         = options.color,
      fill          = options.fill,
      fillStyle     = options.fillStyle,
      radius        = Math.min(canvas.width, canvas.height) * sizeRatio / 2,
      value         = data[0][1],
      html          = [],
      vScale        = 1,//Math.cos(series.pie.viewAngle);
      measure       = Math.PI * 2 * value / this.total,
      startAngle    = this.startAngle || (2 * Math.PI * options.startAngle), // TODO: this initial startAngle is already in radians (fixing will be test-unstable)
      endAngle      = startAngle + measure,
      bisection     = startAngle + measure / 2,
      label         = options.labelFormatter(this.total, value),
      //plotTickness  = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;
      explodeCoeff  = explode + radius + 4,
      distX         = Math.cos(bisection) * explodeCoeff,
      distY         = Math.sin(bisection) * explodeCoeff,
      textAlign     = distX < 0 ? 'right' : 'left',
      textBaseline  = distY > 0 ? 'top' : 'bottom',
      style,
      x, y;

    context.save();
    context.translate(width / 2, height / 2);
    context.scale(1, vScale);

    x = Math.cos(bisection) * explode;
    y = Math.sin(bisection) * explode;

    // Shadows
    if (shadowSize > 0) {
      this.plotSlice(x + shadowSize, y + shadowSize, radius, startAngle, endAngle, context);
      if (fill) {
        context.fillStyle = 'rgba(0,0,0,0.1)';
        context.fill();
      }
    }

    this.plotSlice(x, y, radius, startAngle, endAngle, context);
    if (fill) {
      context.fillStyle = fillStyle;
      context.fill();
    }
    context.lineWidth = lineWidth;
    context.strokeStyle = color;
    context.stroke();

    style = {
      size : options.fontSize * 1.2,
      color : options.fontColor,
      weight : 1.5
    };

    if (label) {
      if (options.htmlText || !options.textEnabled) {
        divStyle = 'position:absolute;' + textBaseline + ':' + (height / 2 + (textBaseline === 'top' ? distY : -distY)) + 'px;';
        divStyle += textAlign + ':' + (width / 2 + (textAlign === 'right' ? -distX : distX)) + 'px;';
        html.push('
', label, '
');
      }
      else {
        style.textAlign = textAlign;
        style.textBaseline = textBaseline;
        Flotr.drawText(context, label, distX, distY, style);
      }
    }

    if (options.htmlText || !options.textEnabled) {
      var div = Flotr.DOM.node('

');
      Flotr.DOM.insert(div, html.join(''));
      Flotr.DOM.insert(options.element, div);
    }

    context.restore();

    // New start angle
    this.startAngle = endAngle;
    this.slices = this.slices || [];
    this.slices.push({
      radius : Math.min(canvas.width, canvas.height) * sizeRatio / 2,
      x : x,
      y : y,
      explode : explode,
      start : startAngle,
      end : endAngle
    });
  },
  plotSlice : function (x, y, radius, startAngle, endAngle, context) {
    context.beginPath();
    context.moveTo(x, y);
    context.arc(x, y, radius, startAngle, endAngle, false);
    context.lineTo(x, y);
    context.closePath();
  },
  hit : function (options) {

    var
      data      = options.data[0],
      args      = options.args,
      index     = options.index,
      mouse     = args[0],
      n         = args[1],
      slice     = this.slices[index],
      x         = mouse.relX - options.width / 2,
      y         = mouse.relY - options.height / 2,
      r         = Math.sqrt(x * x + y * y),
      theta     = Math.atan(y / x),
      circle    = Math.PI * 2,
      explode   = slice.explode || options.explode,
      start     = slice.start % circle,
      end       = slice.end % circle,
	  epsilon   = options.epsilon;

    if (x < 0) {
      theta += Math.PI;
    } else if (x > 0 && y < 0) {
      theta += circle;
    }

    if (r < slice.radius + explode && r > explode) {
      if ((start > end && (theta < end || theta > start)) ||
        (theta > start && theta < end) ||
		(start === end && Math.abs(theta - start) < epsilon)) {

        // TODO Decouple this from hit plugin (chart shouldn't know what n means)
         n.x = data[0];
         n.y = data[1];
         n.sAngle = start;
         n.eAngle = end;
         n.index = 0;
         n.seriesIndex = index;
         n.fraction = data[1] / this.total;
      }
    }
  },
  drawHit: function (options) {
    var
      context = options.context,
      slice = this.slices[options.args.seriesIndex];

    context.save();
    context.translate(options.width / 2, options.height / 2);
    this.plotSlice(slice.x, slice.y, slice.radius, slice.start, slice.end, context);
    context.stroke();
    context.restore();
  },
  clearHit : function (options) {
    var
      context = options.context,
      slice = this.slices[options.args.seriesIndex],
      padding = 2 * options.lineWidth,
      radius = slice.radius + padding;

    context.save();
    context.translate(options.width / 2, options.height / 2);
    context.clearRect(
      slice.x - radius,
      slice.y - radius,
      2 * radius + padding,
      2 * radius + padding
    );
    context.restore();
  },
  extendYRange : function (axis, data) {
    this.total = (this.total || 0) + data[0][1];
  }
});
})();
<commit_msg>Another pie hit fix<commit_after>/**
 * Pie
 *
 * Formats the pies labels.
 * @param {Object} slice - Slice object
 * @return {String} Formatted pie label string
 */
(function () {

var
  _ = Flotr._;

Flotr.defaultPieLabelFormatter = function (total, value) {
  return (100 * value / total).toFixed(2)+'%';
};

Flotr.addType('pie', {
  options: {
    show: false,           // => setting to true will show bars, false will hide
    lineWidth: 1,          // => in pixels
    fill: true,            // => true to fill the area from the line to the x axis, false for (transparent) no fill
    fillColor: null,       // => fill color
    fillOpacity: 0.6,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
    explode: 6,            // => the number of pixels the splices will be far from the center
    sizeRatio: 0.6,        // => the size ratio of the pie relative to the plot
    startAngle: Math.PI/4, // => the first slice start angle
    labelFormatter: Flotr.defaultPieLabelFormatter,
    pie3D: false,          // => whether to draw the pie in 3 dimenstions or not (ineffective)
    pie3DviewAngle: (Math.PI/2 * 0.8),
    pie3DspliceThickness: 20,
    epsilon: 0.1           // => how close do you have to get to hit empty slice
  },

  draw : function (options) {

    // TODO 3D charts what?

    var
      data          = options.data,
      context       = options.context,
      canvas        = context.canvas,
      lineWidth     = options.lineWidth,
      shadowSize    = options.shadowSize,
      sizeRatio     = options.sizeRatio,
      height        = options.height,
      width         = options.width,
      explode       = options.explode,
      color         = options.color,
      fill          = options.fill,
      fillStyle     = options.fillStyle,
      radius        = Math.min(canvas.width, canvas.height) * sizeRatio / 2,
      value         = data[0][1],
      html          = [],
      vScale        = 1,//Math.cos(series.pie.viewAngle);
      measure       = Math.PI * 2 * value / this.total,
      startAngle    = this.startAngle || (2 * Math.PI * options.startAngle), // TODO: this initial startAngle is already in radians (fixing will be test-unstable)
      endAngle      = startAngle + measure,
      bisection     = startAngle + measure / 2,
      label         = options.labelFormatter(this.total, value),
      //plotTickness  = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;
      explodeCoeff  = explode + radius + 4,
      distX         = Math.cos(bisection) * explodeCoeff,
      distY         = Math.sin(bisection) * explodeCoeff,
      textAlign     = distX < 0 ? 'right' : 'left',
      textBaseline  = distY > 0 ? 'top' : 'bottom',
      style,
      x, y;

    context.save();
    context.translate(width / 2, height / 2);
    context.scale(1, vScale);

    x = Math.cos(bisection) * explode;
    y = Math.sin(bisection) * explode;

    // Shadows
    if (shadowSize > 0) {
      this.plotSlice(x + shadowSize, y + shadowSize, radius, startAngle, endAngle, context);
      if (fill) {
        context.fillStyle = 'rgba(0,0,0,0.1)';
        context.fill();
      }
    }

    this.plotSlice(x, y, radius, startAngle, endAngle, context);
    if (fill) {
      context.fillStyle = fillStyle;
      context.fill();
    }
    context.lineWidth = lineWidth;
    context.strokeStyle = color;
    context.stroke();

    style = {
      size : options.fontSize * 1.2,
      color : options.fontColor,
      weight : 1.5
    };

    if (label) {
      if (options.htmlText || !options.textEnabled) {
        divStyle = 'position:absolute;' + textBaseline + ':' + (height / 2 + (textBaseline === 'top' ? distY : -distY)) + 'px;';
        divStyle += textAlign + ':' + (width / 2 + (textAlign === 'right' ? -distX : distX)) + 'px;';
        html.push('
', label, '
');
      }
      else {
        style.textAlign = textAlign;
        style.textBaseline = textBaseline;
        Flotr.drawText(context, label, distX, distY, style);
      }
    }

    if (options.htmlText || !options.textEnabled) {
      var div = Flotr.DOM.node('

');
      Flotr.DOM.insert(div, html.join(''));
      Flotr.DOM.insert(options.element, div);
    }

    context.restore();

    // New start angle
    this.startAngle = endAngle;
    this.slices = this.slices || [];
    this.slices.push({
      radius : Math.min(canvas.width, canvas.height) * sizeRatio / 2,
      x : x,
      y : y,
      explode : explode,
      start : startAngle,
      end : endAngle
    });
  },
  plotSlice : function (x, y, radius, startAngle, endAngle, context) {
    context.beginPath();
    context.moveTo(x, y);
    context.arc(x, y, radius, startAngle, endAngle, false);
    context.lineTo(x, y);
    context.closePath();
  },
  hit : function (options) {

    var
      data      = options.data[0],
      args      = options.args,
      index     = options.index,
      mouse     = args[0],
      n         = args[1],
      slice     = this.slices[index],
      x         = mouse.relX - options.width / 2,
      y         = mouse.relY - options.height / 2,
      r         = Math.sqrt(x * x + y * y),
      theta     = Math.atan(y / x),
      circle    = Math.PI * 2,
      explode   = slice.explode || options.explode,
      start     = slice.start % circle,
      end       = slice.end % circle,
	  epsilon   = options.epsilon;

    if (x < 0) {
      theta += Math.PI;
    } else if (x > 0 && y < 0) {
      theta += circle;
    }

    if (r < slice.radius + explode && r > explode) {
      if ((start > end && (theta < end || theta > start)) ||
        (theta > start && theta < end) ||
		(start === end && ((slice.start === slice.end && Math.abs(theta - start) < epsilon) || (slice.start !== slice.end && Math.abs(theta-start) > epsilon)))) {

        // TODO Decouple this from hit plugin (chart shouldn't know what n means)
         n.x = data[0];
         n.y = data[1];
         n.sAngle = start;
         n.eAngle = end;
         n.index = 0;
         n.seriesIndex = index;
         n.fraction = data[1] / this.total;
      }
    }
  },
  drawHit: function (options) {
    var
      context = options.context,
      slice = this.slices[options.args.seriesIndex];

    context.save();
    context.translate(options.width / 2, options.height / 2);
    this.plotSlice(slice.x, slice.y, slice.radius, slice.start, slice.end, context);
    context.stroke();
    context.restore();
  },
  clearHit : function (options) {
    var
      context = options.context,
      slice = this.slices[options.args.seriesIndex],
      padding = 2 * options.lineWidth,
      radius = slice.radius + padding;

    context.save();
    context.translate(options.width / 2, options.height / 2);
    context.clearRect(
      slice.x - radius,
      slice.y - radius,
      2 * radius + padding,
      2 * radius + padding
    );
    context.restore();
  },
  extendYRange : function (axis, data) {
    this.total = (this.total || 0) + data[0][1];
  }
});
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
    Text,
    View,
    Image,
    StyleSheet,
    TouchableOpacity,
    processColor,
    Platform,
} from 'react-native';
import {
    CombinedChart,
    ScatterChart,
    BarChart,
    LineChart,
} from 'react-native-charts-wrapper';
import * as Device from 'app/utility/Device';
import { SETTINGS_PANEL_STYLES } from 'app/appearance/styles/GlobalStyles';
import OneRMEditSetScreen from '../edit_set/OneRMEditSetScreen';

class OneRMChartView extends Component {

    constructor(props) {
        super(props);

        this.state = {
            setID: null,
            workoutID: null,
            touching: false,
        };
    }

    // TOUCHES

    _handleSelect(event) {
        const nativeEvent = event.nativeEvent;
        if (nativeEvent.hasOwnProperty('data')) {
            const data = nativeEvent.data;
            if (data.hasOwnProperty('setID') && data.hasOwnProperty('workoutID')) {
                if (Platform.OS === 'ios') {
                    if (!this.state.touching) {
                        this.props.tappedSet(data.setID, data.workoutID);
                    }
                } else {
                    this.setState({setID: data.setID, workoutID: data.workoutID});
                }
            } else if (Platform.OS !== 'ios') {
                this.setState({setID: null, workoutID: null});
            }
        }
    }

    _handleTouchStart() {
        if (Platform.OS === 'ios') {
            this.setState({touching: true});
        }
    }

    _handleTouchEndCapture() {
        if (Platform.OS === 'ios') {
            this.setState({touching: false});
        } else {
            if (this.state.setID && this.state.workoutID) {
                this.props.tappedSet(this.state.setID, this.state.workoutID);
                this.setState({setID: null, workoutID: null});
            }
        }
    };

    _handleTouchMove() {
        if (Platform.OS !== 'ios') {
            this.setState({setID: null, workoutID: null});
        }
    }

    // RENDER

    _render1RM(r2) {
        if (this.props.isR2HighEnough) {
            let e1RM = this.props.e1RM ? this.props.e1RM : "---";
            let velocity = this.props.velocity ? this.props.velocity : "---";

            return (
                <View>
                    <Text style={styles.oneRMText}>e1RM: <Text style={{fontWeight: 'bold'}}>{e1RM}</Text> {this.props.metric}</Text>
                    <Text style={{ textAlign: 'center', fontSize: 15, marginBottom: 20 }}>@ <Text style={{ fontWeight: 'bold' }}> {velocity} m/s</Text></Text>
                    <Text style={styles.r2Text}>r² : {this.props.r2} %</Text>
                </View>
            );
        } else {
            return (
                <View>
                    <Text style={styles.errorText}>
                        R² is too low, please clean up or log more data
                    </Text>
                </View>
            );
        }
    }

    _render1RMBar() {
        if (this.props.isR2HighEnough && this.props.e1RM) {
            return (
                <VictoryBar
                    data={[
                        { x: this.props.e1RM, y: 20, y0: 0, width: 20, fill: "#ffe5e5" },
                    ]}
                />
            )
        }
    }

    _renderRegressionLine() {
        if (this.props.isR2HighEnough) {
            return (
                <VictoryLine
                    style={{
                        data: { stroke: "#368fff" },
                        parent: { border: "1px solid #ccc"}
                    }}
                    data={[
                        this.props.regLeftPoint,
                        this.props.regRightPoint,
                    ]}
                />
            );
        }
    }

    _renderChartArea() {
        // TODO: need to check against ALL points rather than just active points to render a chart
        // NOTE: using > 1 for now as for active chart, I need that in order to get a domain
        if (this.props.activeChartData && this.props.activeChartData.length > 1) {
            return (
                <View>
                    {this._renderChart()}
                </View>
            );
        } else {
            const size = Device.isSmallDevice() ? 250 : 300;
            return <Image style={{width: size, height: size, marginTop: 20}} source={require('app/appearance/images/grayed_chart.png')} />
        }
    }

    _renderChart() {
        // set the data
        // NOTE: Android crashes if the data is length 0, so ONLY add it if data exists
        let data = {
            scatterData: {
                dataSets: []
            }
        };
        const dotMultiplier = Platform.OS === 'ios' ? 1 : 4;
        if (this.props.e1RM) {
            data.scatterData.dataSets.push({
                values: [{x: this.props.e1RM, y: this.props.velocity}],
                label: '1RM',

                config: {
                    drawValues: false,
                    colors: [processColor('green')],
                    highlightEnabled: false,
                    normalizeSizeEnabled: false,
                    scatterShape: 'CROSS',
                    scatterShapeSize: 25 * dotMultiplier,
                }

            });
        }
        if (this.props.unusedChartData && this.props.unusedChartData.length > 0) {
            data.scatterData.dataSets.push({
                values: this.props.unusedChartData,
                label: 'Unused Points',
                config: {
                    colors: [processColor('rgba(47, 128, 237, 0.2)')],
                    drawValues: false,
                    highlightEnabled: false,
                    normalizeSizeEnabled: false,
                    scatterShape: 'CIRCLE',
                    drawHighlightIndicators: false,
                    scatterShapeSize: 12 * dotMultiplier,
                }
            });
        }
        if (this.props.errorChartData && this.props.errorChartData.length > 0) {
            data.scatterData.dataSets.push({
                values: this.props.errorChartData,
                label: 'Error Points',
                config: {
                    colors: [processColor('red')],
                    drawValues: false,
                    highlightEnabled: true,
                    normalizeSizeEnabled: false,
                    highlightCircleWidth: 5,
                    scatterShape: 'CIRCLE',
                    drawHighlightIndicators: false,
                    scatterShapeSize: 12 * dotMultiplier,
                }
            });
        }
        if (this.props.activeChartData && this.props.activeChartData.length > 0) {
            data.scatterData.dataSets.push({
                values: this.props.activeChartData,
                label: 'Active Points',
                config: {
                    colors: [processColor('rgba(47, 128, 237, 1)')],
                    drawValues: false,
                    highlightEnabled: true,
                    normalizeSizeEnabled: false,
                    highlightCircleWidth: 5,
                    scatterShape: 'CIRCLE',
                    drawHighlightIndicators: false,
                    scatterShapeSize: 12 * dotMultiplier,
                }
            });
        }
        if (this.props.regLeftPoint && this.props.regRightPoint) {
            data.lineData = {
                dataSets: [{
                    values: [this.props.regLeftPoint, this.props.regRightPoint],
                    label: 'Regression line',

                    config: {
                        drawValues: false,
                        colors: [processColor('green')],
                        drawCircles: false,
                        lineWidth: 2,
                        highlightEnabled: false,
                    }
                }]
            };
        }

        return (
            <View style={styles.chartContainer}>
                <CombinedChart
                    data={data}
                    xAxis={{
                        position: 'BOTTOM',
                        axisMinimum: this.props.minX,
                        axisMaximum: this.props.maxX,
                    }}
                    yAxis={{
                        right: {
                            drawLabels: false,
                            drawAxisLine: false,
                            drawGridLines: false,
                        },
                        left: {
                            axisMinimum: 0,
                            axisMaximum: this.props.maxY,
                        }
                    }}
                    marker={{enabled: true,
                        markerColor: processColor('#F0C0FF8C'),
                        textColor: processColor('white'),
                        markerFontSize: 14,
                    }}
                    pinchZoom={true}
                    maxVisibleValueCount={9001} // Assuming we'll never have this many sets
                    legend={{enabled: false}}
                    onSelect={this._handleSelect.bind(this)}
                    onTouchStart={this._handleTouchStart.bind(this)}
                    onTouchEndCapture={this._handleTouchEndCapture.bind(this)}
                    onTouchMove={this._handleTouchMove.bind(this)}
                    chartDescription={{text: ''}}
                    onChange={(event) => console.log(event.nativeEvent)}
                    style={styles.chart}/>
                    <OneRMEditSetScreen />
            </View>
        );
    }

    render() {
        return (
            <View style={ [SETTINGS_PANEL_STYLES.panel, { borderBottomWidth: 0, flexDirection: 'column', alignItems: 'center' }] }>
                <Text style={[styles.titleText, {marginBottom: 10}]}>Results</Text>
                {this._render1RM(this.props.r2)}
                <Text style={{textAlign: 'center', fontStyle: 'italic', fontWeight: 'bold', color: 'rgba(77, 77, 77, 1)'}}>Tap a point to view and edit the data</Text>
                {this._renderChartArea()}
            </View>
        );
    }
}

const styles = StyleSheet.create({
    oneRMText: {
        color: 'rgba(77, 77, 77, 1)',
        marginTop: 10,
        marginBottom: 5,
        fontSize: 32,
        textAlign: 'center'
    },
    r2Text: {
        color: 'rgba(77, 77, 77, 1)',
        marginBottom: 20,
        fontSize: 18,
        textAlign: 'center',
        fontWeight: 'bold',
    },
    errorText: {
        color: 'rgba(77, 77, 77, 1)',
        marginBottom: 20,
        fontSize: 20,
        textAlign: 'center',
        fontWeight: 'bold'
    },
    titleText: {
        color: 'rgba(77, 77, 77, 1)',
        textAlign: 'center',
        fontSize: 16,
        fontWeight: 'bold',
    },
    chartContainer: {
        alignItems: 'center',
        width: 300,
        height: 400,
    },
    chart: {
        width: 300,
        height: 400,
        justifyContent: 'center',
        alignItems: 'stretch',
        backgroundColor: 'lightgray',
    },
});

export default OneRMChartView;
<commit_msg>Legend now shows for 1rm chart<commit_after>import React, { Component } from 'react';
import {
    Text,
    View,
    Image,
    StyleSheet,
    TouchableOpacity,
    processColor,
    Platform,
} from 'react-native';
import {
    CombinedChart,
    ScatterChart,
    BarChart,
    LineChart,
} from 'react-native-charts-wrapper';
import * as Device from 'app/utility/Device';
import { SETTINGS_PANEL_STYLES } from 'app/appearance/styles/GlobalStyles';
import OneRMEditSetScreen from '../edit_set/OneRMEditSetScreen';

class OneRMChartView extends Component {

    constructor(props) {
        super(props);

        this.state = {
            setID: null,
            workoutID: null,
            touching: false,
        };
    }

    // TOUCHES

    _handleSelect(event) {
        const nativeEvent = event.nativeEvent;
        if (nativeEvent.hasOwnProperty('data')) {
            const data = nativeEvent.data;
            if (data.hasOwnProperty('setID') && data.hasOwnProperty('workoutID')) {
                if (Platform.OS === 'ios') {
                    if (!this.state.touching) {
                        this.props.tappedSet(data.setID, data.workoutID);
                    }
                } else {
                    this.setState({setID: data.setID, workoutID: data.workoutID});
                }
            } else if (Platform.OS !== 'ios') {
                this.setState({setID: null, workoutID: null});
            }
        }
    }

    _handleTouchStart() {
        if (Platform.OS === 'ios') {
            this.setState({touching: true});
        }
    }

    _handleTouchEndCapture() {
        if (Platform.OS === 'ios') {
            this.setState({touching: false});
        } else {
            if (this.state.setID && this.state.workoutID) {
                this.props.tappedSet(this.state.setID, this.state.workoutID);
                this.setState({setID: null, workoutID: null});
            }
        }
    };

    _handleTouchMove() {
        if (Platform.OS !== 'ios') {
            this.setState({setID: null, workoutID: null});
        }
    }

    // RENDER

    _render1RM(r2) {
        if (this.props.isR2HighEnough) {
            let e1RM = this.props.e1RM ? this.props.e1RM : "---";
            let velocity = this.props.velocity ? this.props.velocity : "---";

            return (
                <View>
                    <Text style={styles.oneRMText}>e1RM: <Text style={{fontWeight: 'bold'}}>{e1RM}</Text> {this.props.metric}</Text>
                    <Text style={{ textAlign: 'center', fontSize: 15, marginBottom: 20 }}>@ <Text style={{ fontWeight: 'bold' }}> {velocity} m/s</Text></Text>
                    <Text style={styles.r2Text}>r² : {this.props.r2} %</Text>
                </View>
            );
        } else {
            return (
                <View>
                    <Text style={styles.errorText}>
                        R² is too low, please clean up or log more data
                    </Text>
                </View>
            );
        }
    }

    _render1RMBar() {
        if (this.props.isR2HighEnough && this.props.e1RM) {
            return (
                <VictoryBar
                    data={[
                        { x: this.props.e1RM, y: 20, y0: 0, width: 20, fill: "#ffe5e5" },
                    ]}
                />
            )
        }
    }

    _renderRegressionLine() {
        if (this.props.isR2HighEnough) {
            return (
                <VictoryLine
                    style={{
                        data: { stroke: "#368fff" },
                        parent: { border: "1px solid #ccc"}
                    }}
                    data={[
                        this.props.regLeftPoint,
                        this.props.regRightPoint,
                    ]}
                />
            );
        }
    }

    _renderChartArea() {
        // TODO: need to check against ALL points rather than just active points to render a chart
        // NOTE: using > 1 for now as for active chart, I need that in order to get a domain
        if (this.props.activeChartData && this.props.activeChartData.length > 1) {
            return (
                <View>
                    {this._renderChart()}
                </View>
            );
        } else {
            const size = Device.isSmallDevice() ? 250 : 300;
            return <Image style={{width: size, height: size, marginTop: 20}} source={require('app/appearance/images/grayed_chart.png')} />
        }
    }

    _renderChart() {
        // set the data
        // NOTE: Android crashes if the data is length 0, so ONLY add it if data exists
        let data = {
            scatterData: {
                dataSets: []
            }
        };
        const dotMultiplier = Platform.OS === 'ios' ? 1 : 4;
        if (this.props.e1RM) {
            data.scatterData.dataSets.push({
                values: [{x: this.props.e1RM, y: this.props.velocity}],
                label: '1 Rep Max',

                config: {
                    drawValues: false,
                    colors: [processColor('black')],
                    highlightEnabled: false,
                    normalizeSizeEnabled: false,
                    scatterShape: 'CROSS',
                    scatterShapeSize: 25 * dotMultiplier,
                }

            });
        }
        if (this.props.unusedChartData && this.props.unusedChartData.length > 0) {
            data.scatterData.dataSets.push({
                values: this.props.unusedChartData,
                label: 'Unused Sets',
                config: {
                    colors: [processColor('rgba(47, 128, 237, 0.2)')],
                    drawValues: false,
                    highlightEnabled: false,
                    normalizeSizeEnabled: false,
                    scatterShape: 'CIRCLE',
                    drawHighlightIndicators: false,
                    scatterShapeSize: 12 * dotMultiplier,
                }
            });
        }
        if (this.props.errorChartData && this.props.errorChartData.length > 0) {
            data.scatterData.dataSets.push({
                values: this.props.errorChartData,
                label: 'Errors',
                config: {
                    colors: [processColor('red')],
                    drawValues: false,
                    highlightEnabled: true,
                    normalizeSizeEnabled: false,
                    highlightCircleWidth: 5,
                    scatterShape: 'CIRCLE',
                    drawHighlightIndicators: false,
                    scatterShapeSize: 12 * dotMultiplier,
                }
            });
        }
        if (this.props.activeChartData && this.props.activeChartData.length > 0) {
            data.scatterData.dataSets.push({
                values: this.props.activeChartData,
                label: 'Active Sets',
                config: {
                    colors: [processColor('rgba(47, 128, 237, 1)')],
                    drawValues: false,
                    highlightEnabled: true,
                    normalizeSizeEnabled: false,
                    highlightCircleWidth: 5,
                    scatterShape: 'CIRCLE',
                    drawHighlightIndicators: false,
                    scatterShapeSize: 12 * dotMultiplier,
                }
            });
        }
        if (this.props.regLeftPoint && this.props.regRightPoint) {
            data.lineData = {
                dataSets: [{
                    values: [this.props.regLeftPoint, this.props.regRightPoint],
                    label: 'Regression',

                    config: {
                        drawValues: false,
                        colors: [processColor('green')],
                        drawCircles: false,
                        lineWidth: 2,
                        highlightEnabled: false,
                    }
                }]
            };
        }

        return (
            <View style={styles.chartContainer}>
                <CombinedChart
                    data={data}
                    xAxis={{
                        position: 'BOTTOM',
                        axisMinimum: this.props.minX,
                        axisMaximum: this.props.maxX,
                    }}
                    yAxis={{
                        right: {
                            drawLabels: false,
                            drawAxisLine: false,
                            drawGridLines: false,
                        },
                        left: {
                            axisMinimum: 0,
                            axisMaximum: this.props.maxY,
                        }
                    }}
                    marker={{enabled: true,
                        markerColor: processColor('#F0C0FF8C'),
                        textColor: processColor('white'),
                        markerFontSize: 14,
                    }}
                    pinchZoom={true}
                    maxVisibleValueCount={9001} // Assuming we'll never have this many sets
                    legend={{enabled: true}}
                    onSelect={this._handleSelect.bind(this)}
                    onTouchStart={this._handleTouchStart.bind(this)}
                    onTouchEndCapture={this._handleTouchEndCapture.bind(this)}
                    onTouchMove={this._handleTouchMove.bind(this)}
                    chartDescription={{text: ''}}
                    onChange={(event) => console.log(event.nativeEvent)}
                    style={styles.chart}/>
                    <OneRMEditSetScreen />
            </View>
        );
    }

    render() {
        return (
            <View style={ [SETTINGS_PANEL_STYLES.panel, { borderBottomWidth: 0, flexDirection: 'column', alignItems: 'center' }] }>
                <Text style={[styles.titleText, {marginBottom: 10}]}>Results</Text>
                {this._render1RM(this.props.r2)}
                <Text style={{textAlign: 'center', fontStyle: 'italic', fontWeight: 'bold', color: 'rgba(77, 77, 77, 1)'}}>Tap a point to view and edit the data</Text>
                {this._renderChartArea()}
            </View>
        );
    }
}

const styles = StyleSheet.create({
    oneRMText: {
        color: 'rgba(77, 77, 77, 1)',
        marginTop: 10,
        marginBottom: 5,
        fontSize: 32,
        textAlign: 'center'
    },
    r2Text: {
        color: 'rgba(77, 77, 77, 1)',
        marginBottom: 20,
        fontSize: 18,
        textAlign: 'center',
        fontWeight: 'bold',
    },
    errorText: {
        color: 'rgba(77, 77, 77, 1)',
        marginBottom: 20,
        fontSize: 20,
        textAlign: 'center',
        fontWeight: 'bold'
    },
    titleText: {
        color: 'rgba(77, 77, 77, 1)',
        textAlign: 'center',
        fontSize: 16,
        fontWeight: 'bold',
    },
    chartContainer: {
        alignItems: 'center',
        width: 300,
        height: 400,
    },
    chart: {
        width: 300,
        height: 400,
        justifyContent: 'center',
        alignItems: 'stretch',
        backgroundColor: 'transparent',
    },
});

export default OneRMChartView;
<|endoftext|>


<commit_before>/* globals module, require */
/**
 * Dialog for displaying maps in full screen mode.
 *
 * See [OO.ui.Dialog](https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.Dialog)
 * documentation for more details.
 *
 * @class Kartographer.Dialog.DialogClass
 * @extends OO.ui.Dialog
 */
module.Dialog = ( function ( $, mw, CloseFullScreenControl, router ) {

	/**
	 * @constructor
	 * @type {Kartographer.Dialog.DialogClass}
	 */
	var MapDialog = function () {
			// Parent method
			MapDialog.super.apply( this, arguments );
		},
		// Opens the sidebar when the screen is wide enough (greater than 1024px)
		isWideScreen = $( document ).width() > 1024,
		FOOTER_HEIGHT = 58,
		SIDEBAR_WIDTH = 320;

	/* Inheritance */

	OO.inheritClass( MapDialog, OO.ui.Dialog );

	/* Static Properties */

	MapDialog.static.name = 'mapDialog';
	MapDialog.static.size = 'full';

	/* Methods */

	MapDialog.prototype.initialize = function () {
		this.$mapDetailsButton = null;

		// Parent method
		MapDialog.super.prototype.initialize.apply( this, arguments );

		this.$body
			.append( '

' );
		this.$foot
			.addClass( 'mw-kartographer-mapDialog-foot' );

		this.map = null;
	};

	MapDialog.prototype.addFooterButton = function () {
		var dialog = this;
		mw.loader.using( 'oojs-ui-widgets' ).done( function () {
			$( function () {

				// Create footer toggle button
				var button = dialog.$mapDetailsButton = new OO.ui.ToggleButtonWidget( {
						label: mw.msg( 'kartographer-sidebar-togglebutton' ),
						icon: 'info',
						iconTitle: mw.msg( 'kartographer-sidebar-togglebutton' )
					} ),
					$captionContainer = dialog.$captionContainer = $( '
' ),
					$buttonContainer = $( '
' ),
					$inlineContainer = $( '
' )
						.append( $buttonContainer, $captionContainer );

				if ( dialog.map ) {
					$captionContainer
						.attr( 'title', dialog.map.captionText )
						.text( dialog.map.captionText );
				}

				$buttonContainer.append( button.$element );

				// Add the button to the footer
				dialog.$foot.append( $inlineContainer );

				button.on( 'change', dialog.toggleSideBar, null, dialog );

				if ( isWideScreen ) {
					dialog.map.doWhenReady( function () {
						dialog.offsetMap( true );
						dialog.toggleSideBar( true );
					} );
				}
			} );
		} );
	};

	MapDialog.prototype.toggleSideBar = function ( open ) {
		var dialog = this;
		mw.loader.using( 'ext.kartographer.dialog.sidebar' ).done( function () {
			var SideBar;
			if ( !dialog.sideBar ) {
				SideBar = mw.loader.require( 'ext.kartographer.dialog.sidebar' );
				dialog.sideBar = new SideBar( { dialog: dialog } );
			}

			open = ( typeof open === 'undefined' ) ? !dialog.$mapDetailsButton.value : open;

			if ( dialog.$mapDetailsButton.value !== open ) {
				dialog.$mapDetailsButton.setValue( open );
				// This `change` event callback is fired again, so skip here.
				return;
			}

			dialog.$body.toggleClass( 'mw-kartographer-mapDialog-sidebar-opened', open );

			mw.track( 'mediawiki.kartographer', {
				action: open ? 'sidebar-show' : 'sidebar-hide',
				isFullScreen: true,
				feature: dialog.map.parentMap || dialog.map.parentLink
			} );
			dialog.sideBar.toggle( open );
		} );
	};

	MapDialog.prototype.getActionProcess = function ( action ) {
		var dialog = this;

		if ( !action ) {
			return new OO.ui.Process( function () {
				if ( dialog.map ) {
					dialog.map.closeFullScreen();
					dialog.map.remove();
					dialog.map = null;
				}
			} );
		}
		return MapDialog.super.prototype.getActionProcess.call( this, action );
	};

	/**
	 * Adds an offset to the center of the map.
	 *
	 * @param {boolean} isSidebarOpen Whether the sidebar is open.
	 */
	MapDialog.prototype.offsetMap = function ( isSidebarOpen ) {
		var map = this.map,
			offsetX = isSidebarOpen ? SIDEBAR_WIDTH / -2 : 0,
			targetPoint = map.project( map.getCenter(), map.getZoom() ).subtract( [ offsetX, -1 * FOOTER_HEIGHT ] ),
			targetLatLng = map.unproject( targetPoint, map.getZoom() );

		map.setView( targetLatLng, map.getZoom() );
	};

	/**
	 * Tells the router to navigate to the current full screen map route.
	 */
	MapDialog.prototype.updateHash = function () {
		var hash = this.map.getHash();

		// Avoid extra operations
		if ( this.lastHash !== hash ) {
			/* eslint-disable no-underscore-dangle */
			this.map._updatingHash = true;
			/* eslint-enable no-underscore-dangle */
			router.navigate( hash );
			this.lastHash = hash;
		}
	};

	/**
	 * Listens to `moveend` event and calls {@link #updateHash}.
	 *
	 * This method is throttled, meaning the method will be called at most once per
	 * every 250 milliseconds.
	 */
	MapDialog.prototype.onMapMove = OO.ui.throttle( function () {
		// Stop listening to `moveend` event while we're
		// manually moving the map (updating from a hash),
		// or if the map is not yet loaded.
		/* eslint-disable no-underscore-dangle */
		if ( this.movingMap || !this.map || !this.map._loaded ) {
			return false;
		}
		/* eslint-enable no-underscore-dangle */
		this.updateHash();
	}, 250 );

	MapDialog.prototype.getSetupProcess = function ( options ) {
		return MapDialog.super.prototype.getSetupProcess.call( this, options )
			.next( function () {
				var dialog = this;

				if ( options.map && options.map !== dialog.map ) {

					if ( dialog.map ) {
						dialog.map.remove();
					}

					dialog.map = options.map;

					dialog.map.closeFullScreenControl = new CloseFullScreenControl( { position: 'topright' } )
						.addTo( dialog.map );

					dialog.$body.append(
						dialog.map.$container.css( 'position', '' )
					);

					if ( dialog.$captionContainer ) {
						dialog.$captionContainer
							.attr( 'title', dialog.map.captionText )
							.text( dialog.map.captionText );
					}

					if ( !dialog.$mapDetailsButton ) {
						// The button does not exist yet, add it
						dialog.addFooterButton();

					} else if ( dialog.sideBar ) {
						// The button exists, the sidebar was open, call `tearDown` and reopen it.
						dialog.sideBar.tearDown();
						dialog.map.doWhenReady( function () {
							dialog.offsetMap( true );
							dialog.toggleSideBar( true );
						} );

					} else {
						// The button exists, the sidebar was not open, simply run `offsetMap`
						dialog.map.doWhenReady( function () {
							dialog.offsetMap( false );
						} );
					}
				}
			}, this );
	};

	MapDialog.prototype.getReadyProcess = function ( data ) {
		return MapDialog.super.prototype.getReadyProcess.call( this, data )
			.next( function () {

				if ( !this.map ) {
					return;
				}
				this.map.doWhenReady( function () {
					mw.hook( 'wikipage.maps' ).fire( this.map, true /* isFullScreen */ );
				}, this );
			}, this );
	};

	MapDialog.prototype.getTeardownProcess = function ( data ) {
		return MapDialog.super.prototype.getTeardownProcess.call( this, data )
			.next( function () {
				if ( this.map ) {
					this.map.remove();
					this.map = null;
				}
				this.$body.empty();
			}, this );
	};

	return function () {
		return new MapDialog();
	};

}(
	jQuery,
	mediaWiki,
	module.CloseFullScreenControl,
	require( 'mediawiki.router' )
) );
<commit_msg>Fix Y offset not being applied correctly<commit_after>/* globals module, require */
/**
 * Dialog for displaying maps in full screen mode.
 *
 * See [OO.ui.Dialog](https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.Dialog)
 * documentation for more details.
 *
 * @class Kartographer.Dialog.DialogClass
 * @extends OO.ui.Dialog
 */
module.Dialog = ( function ( $, mw, CloseFullScreenControl, router ) {

	/**
	 * @constructor
	 * @type {Kartographer.Dialog.DialogClass}
	 */
	var MapDialog = function () {
			// Parent method
			MapDialog.super.apply( this, arguments );
		},
		// Opens the sidebar when the screen is wide enough (greater than 1024px)
		isWideScreen = $( document ).width() > 1024,
		FOOTER_HEIGHT = 58,
		SIDEBAR_WIDTH = 320;

	/* Inheritance */

	OO.inheritClass( MapDialog, OO.ui.Dialog );

	/* Static Properties */

	MapDialog.static.name = 'mapDialog';
	MapDialog.static.size = 'full';

	/* Methods */

	MapDialog.prototype.initialize = function () {
		this.$mapDetailsButton = null;

		// Parent method
		MapDialog.super.prototype.initialize.apply( this, arguments );

		this.$body
			.append( '

' );
		this.$foot
			.addClass( 'mw-kartographer-mapDialog-foot' );

		this.map = null;
	};

	MapDialog.prototype.addFooterButton = function () {
		var dialog = this;
		mw.loader.using( 'oojs-ui-widgets' ).done( function () {
			$( function () {

				// Create footer toggle button
				var button = dialog.$mapDetailsButton = new OO.ui.ToggleButtonWidget( {
						label: mw.msg( 'kartographer-sidebar-togglebutton' ),
						icon: 'info',
						iconTitle: mw.msg( 'kartographer-sidebar-togglebutton' )
					} ),
					$captionContainer = dialog.$captionContainer = $( '
' ),
					$buttonContainer = $( '
' ),
					$inlineContainer = $( '
' )
						.append( $buttonContainer, $captionContainer );

				if ( dialog.map ) {
					$captionContainer
						.attr( 'title', dialog.map.captionText )
						.text( dialog.map.captionText );
				}

				$buttonContainer.append( button.$element );

				// Add the button to the footer
				dialog.$foot.append( $inlineContainer );

				button.on( 'change', dialog.toggleSideBar, null, dialog );

				if ( isWideScreen ) {
					dialog.map.doWhenReady( function () {
						dialog.offsetMap( true );
						dialog.toggleSideBar( true );
					} );
				}
			} );
		} );
	};

	MapDialog.prototype.toggleSideBar = function ( open ) {
		var dialog = this;
		mw.loader.using( 'ext.kartographer.dialog.sidebar' ).done( function () {
			var SideBar;
			if ( !dialog.sideBar ) {
				SideBar = mw.loader.require( 'ext.kartographer.dialog.sidebar' );
				dialog.sideBar = new SideBar( { dialog: dialog } );
			}

			open = ( typeof open === 'undefined' ) ? !dialog.$mapDetailsButton.value : open;

			if ( dialog.$mapDetailsButton.value !== open ) {
				dialog.$mapDetailsButton.setValue( open );
				// This `change` event callback is fired again, so skip here.
				return;
			}

			dialog.$body.toggleClass( 'mw-kartographer-mapDialog-sidebar-opened', open );

			mw.track( 'mediawiki.kartographer', {
				action: open ? 'sidebar-show' : 'sidebar-hide',
				isFullScreen: true,
				feature: dialog.map.parentMap || dialog.map.parentLink
			} );
			dialog.sideBar.toggle( open );
		} );
	};

	MapDialog.prototype.getActionProcess = function ( action ) {
		var dialog = this;

		if ( !action ) {
			return new OO.ui.Process( function () {
				if ( dialog.map ) {
					dialog.map.closeFullScreen();
					dialog.map.remove();
					dialog.map = null;
				}
			} );
		}
		return MapDialog.super.prototype.getActionProcess.call( this, action );
	};

	/**
	 * Adds an offset to the center of the map.
	 *
	 * @param {boolean} isSidebarOpen Whether the sidebar is open.
	 */
	MapDialog.prototype.offsetMap = function ( isSidebarOpen ) {
		var map = this.map,
			offsetX = isSidebarOpen ? SIDEBAR_WIDTH / -2 : 0,
			offsetY = FOOTER_HEIGHT / -2,
			targetPoint = map.project( map.getCenter(), map.getZoom() ).subtract( [ offsetX, offsetY ] ),
			targetLatLng = map.unproject( targetPoint, map.getZoom() );

		map.setView( targetLatLng, map.getZoom() );
	};

	/**
	 * Tells the router to navigate to the current full screen map route.
	 */
	MapDialog.prototype.updateHash = function () {
		var hash = this.map.getHash();

		// Avoid extra operations
		if ( this.lastHash !== hash ) {
			/* eslint-disable no-underscore-dangle */
			this.map._updatingHash = true;
			/* eslint-enable no-underscore-dangle */
			router.navigate( hash );
			this.lastHash = hash;
		}
	};

	/**
	 * Listens to `moveend` event and calls {@link #updateHash}.
	 *
	 * This method is throttled, meaning the method will be called at most once per
	 * every 250 milliseconds.
	 */
	MapDialog.prototype.onMapMove = OO.ui.throttle( function () {
		// Stop listening to `moveend` event while we're
		// manually moving the map (updating from a hash),
		// or if the map is not yet loaded.
		/* eslint-disable no-underscore-dangle */
		if ( this.movingMap || !this.map || !this.map._loaded ) {
			return false;
		}
		/* eslint-enable no-underscore-dangle */
		this.updateHash();
	}, 250 );

	MapDialog.prototype.getSetupProcess = function ( options ) {
		return MapDialog.super.prototype.getSetupProcess.call( this, options )
			.next( function () {
				var dialog = this,
					isFirstTimeOpen = !dialog.$mapDetailsButton,
					isSideBarVisible = dialog.sideBar;

				if ( options.map && options.map !== dialog.map ) {

					if ( dialog.map ) {
						dialog.map.remove();
					}

					dialog.map = options.map;

					dialog.map.closeFullScreenControl = new CloseFullScreenControl( { position: 'topright' } )
						.addTo( dialog.map );

					dialog.$body.append(
						dialog.map.$container.css( 'position', '' )
					);

					if ( dialog.$captionContainer ) {
						dialog.$captionContainer
							.attr( 'title', dialog.map.captionText )
							.text( dialog.map.captionText );
					}

					if ( isFirstTimeOpen ) {
						// The button does not exist yet, add it
						dialog.addFooterButton();
					} else if ( isSideBarVisible ) {
						// The button exists, the sidebar was open, call `tearDown` and reopen it.
						dialog.sideBar.tearDown();
						dialog.map.doWhenReady( function () {
							dialog.offsetMap( true );
							dialog.toggleSideBar( true );
						} );
						return;
					}
					// The button exists, the sidebar was not open, simply run `offsetMap`
					dialog.map.doWhenReady( function () {
						dialog.offsetMap( false );
					} );
				}
			}, this );
	};

	MapDialog.prototype.getReadyProcess = function ( data ) {
		return MapDialog.super.prototype.getReadyProcess.call( this, data )
			.next( function () {

				if ( !this.map ) {
					return;
				}
				this.map.doWhenReady( function () {
					mw.hook( 'wikipage.maps' ).fire( this.map, true /* isFullScreen */ );
				}, this );
			}, this );
	};

	MapDialog.prototype.getTeardownProcess = function ( data ) {
		return MapDialog.super.prototype.getTeardownProcess.call( this, data )
			.next( function () {
				if ( this.map ) {
					this.map.remove();
					this.map = null;
				}
				this.$body.empty();
			}, this );
	};

	return function () {
		return new MapDialog();
	};

}(
	jQuery,
	mediaWiki,
	module.CloseFullScreenControl,
	require( 'mediawiki.router' )
) );
<|endoftext|>