<commit_before>//By Rajeshwar Patlolla
//https://github.com/rajeshwarpatlolla

angular.module('ionic-datepicker', ['ionic', 'ionic-datepicker.templates'])

.directive('ionicDatepicker', ['$ionicPopup', '$filter', function($ionicPopup, $filter) {
    return {
        restrict: 'AE',
        replace: true,
        scope: {
            date: '=',
            minDate: '=',
            maxDate: '=',
            popupTitle: '@',
            btnSetText: '@',
            btnSetType: '@',
            btnCloseText: '@',
            btnCloseType: '@',
            btnTodayShow: '@',
            btnTodayText: '@',
            btnTodayType: '@'
        },
        link: function(scope, element, attrs) {

            element.on("click", function() {

                scope.datePicker = {
                    date: new Date(scope.date.getTime()),
                    minDate: null,
                    maxDate: null,
                    popupTitle: angular.isDefined(scope.popupTitle) ? scope.popupTitle : 'Select date',
                    btnCloseText: angular.isDefined(scope.btnCloseText) ? scope.btnCloseText : 'Close',
                    btnSetText: angular.isDefined(scope.btnSetText) ? scope.btnSetText : 'Set',
                    btnTodayText: angular.isDefined(scope.btnTodayText) ? scope.btnTodayText : 'Today',
                    btnCloseType: angular.isDefined(scope.btnCloseType) ? scope.btnCloseType : 'button-default',
                    btnSetType: angular.isDefined(scope.btnSetType) ? scope.btnSetType : 'button-positive',
                    btnTodayType: angular.isDefined(scope.btnTodayType) ? scope.btnTodayType : 'button-default',
                    btnTodayShow: angular.isDefined(scope.btnTodayShow) ? scope.btnTodayShow === "true" : true
                }

                function normalizeTime(dt) {
                    dt.setHours(0);
                    dt.setMinutes(0);
                    dt.setSeconds(0);
                    dt.setMilliseconds(0);
                }

                scope.datePicker.today = new Date();

                normalizeTime(scope.datePicker.date);
                normalizeTime(scope.datePicker.today);

                if (angular.isDefined(scope.minDate)) {
                    scope.datePicker.minDate = new Date(scope.minDate.getTime());
                    normalizeTime(scope.datePicker.minDate);
                }

                if (angular.isDefined(scope.maxDate)) {
                    scope.datePicker.maxDate = new Date(scope.maxDate.getTime());
                    normalizeTime(scope.datePicker.maxDate);
                }

                scope.datePicker.dateSelected = new Date(scope.datePicker.date.getTime());

                scope.datePicker.weekNames = [];

                var weekNamesGen = new Date('October 12, 2019 22:45:00');
                for (var weekDay = 0; weekDay < 7; weekDay++) {
                    weekNamesGen.setDate(weekNamesGen.getDate() + 1);
                    var weekDayName = $filter('date')(weekNamesGen, 'EEE');
                    scope.datePicker.weekNames.push(weekDayName);
                }

                scope.updateWeeks = function() {

                    scope.datePicker.weeks = [];
                    var datePickerMonth = new Date(scope.datePicker.date.getTime());

                    datePickerMonth.setDate(1);

                    var firstDayMonthWeekName = $filter('date')(datePickerMonth, 'EEE');
                    var days = [];
                    var daysFillingComplete = false;
                    for (var i = 0; i < scope.datePicker.weekNames.length && !daysFillingComplete; i++) {
                        if (scope.datePicker.weekNames[i] == firstDayMonthWeekName) {
                            daysFillingComplete = true;
                        } else {
                            days.push(null);
                        }
                    }

                    var currentDatePickerMonth = datePickerMonth.getMonth();
                    while (currentDatePickerMonth == datePickerMonth.getMonth()) {
                        if (days.length == scope.datePicker.weekNames.length) {
                            scope.datePicker.weeks.push(days.slice());
                            days = [];
                        }

                        days.push(new Date(datePickerMonth.getTime()));
                        datePickerMonth.setDate(datePickerMonth.getDate() + 1);
                    }

                    if (days.length > 0) {
                        for (var i = days.length; i < scope.datePicker.weekNames.length; i++) {
                            days.push(null);
                        }
                        scope.datePicker.weeks.push(days);
                    }
                }

                scope.updateWeeks();

                scope.isToday = function(day) {
                    return day != null && day.getTime() == scope.datePicker.today.getTime();
                }

                scope.isSelected = function(day) {
                    return day != null && day.getTime() == scope.datePicker.dateSelected.getTime();
                }

                scope.prevMonthAllowed = function() {
                    var prevMonthAllowed = true;
                    if (scope.datePicker.minDate != null && scope.datePicker.date.getMonth() <= scope.datePicker.minDate.getMonth()) {
                        prevMonthAllowed = false;
                    }
                    return prevMonthAllowed;
                }

                scope.nextMonthAllowed = function() {
                    var nextMonthAllowed = true;
                    if (scope.datePicker.maxDate != null && scope.datePicker.date.getMonth() >= scope.datePicker.maxDate.getMonth()) {
                        nextMonthAllowed = false;
                    }
                    return nextMonthAllowed;
                }

                scope.dayAllowed = function(day) {
                    var dayAllowed = true;

                    if (day != null) {
                        if (scope.datePicker.minDate != null && day.getTime() < scope.datePicker.minDate.getTime()) {
                            dayAllowed = false;
                        } else if (scope.datePicker.maxDate != null && day.getTime() > scope.datePicker.maxDate.getTime()) {
                            dayAllowed = false;
                        }
                    }

                    return dayAllowed;
                }

                scope.prevMonth = function() {
                    scope.datePicker.date.setMonth(scope.datePicker.date.getMonth() - 1);
                    scope.updateWeeks();
                }

                scope.nextMonth = function() {
                    scope.datePicker.date.setMonth(scope.datePicker.date.getMonth() + 1);
                    scope.updateWeeks();
                }

                scope.selectDate = function(day) {
                    if (day != null && scope.dayAllowed(day)) {
                        scope.datePicker.dateSelected = day;

                        var updateWeeks = scope.datePicker.date.getMonth() != day.getMonth();

                        if (updateWeeks) {
                            scope.datePicker.date = new Date(day.getTime());
                            scope.updateWeeks();
                        }
                    }
                }

                var popupButtons = [];

                popupButtons.push({
                    text: scope.datePicker.btnCloseText,
                    type: scope.datePicker.btnCloseType
                });

                if (scope.datePicker.btnTodayShow) {
                    popupButtons.push({
                        text: scope.datePicker.btnTodayText,
                        type: scope.datePicker.btnTodayType,

                        onTap: function(e) {

                            e.preventDefault();

                            scope.datePicker.today = new Date();

                            normalizeTime(scope.datePicker.today);

                            scope.selectDate(new Date(scope.datePicker.today.getTime()));
                        }
                    });
                }

                popupButtons.push({
                    text: scope.datePicker.btnSetText,
                    type: scope.datePicker.btnSetType,
                    onTap: function(e) {
                        scope.date = scope.datePicker.dateSelected;
                    }
                });

                $ionicPopup.show({
                    templateUrl: 'date-picker-modal.html',
                    title: '' + scope.datePicker.popupTitle + '',
                    subTitle: '',
                    scope: scope,
                    buttons: popupButtons
                })
            });
        }
    }
}]);
<commit_msg>Bugfix: validation prevMonth and nextMonth.<commit_after>//By Rajeshwar Patlolla
//https://github.com/rajeshwarpatlolla

angular.module('ionic-datepicker', ['ionic', 'ionic-datepicker.templates'])

.directive('ionicDatepicker', ['$ionicPopup', '$filter', function($ionicPopup, $filter) {
    return {
        restrict: 'AE',
        replace: true,
        scope: {
            date: '=',
            minDate: '=',
            maxDate: '=',
            popupTitle: '@',
            btnSetText: '@',
            btnSetType: '@',
            btnCloseText: '@',
            btnCloseType: '@',
            btnTodayShow: '@',
            btnTodayText: '@',
            btnTodayType: '@'
        },
        link: function(scope, element, attrs) {

            element.on("click", function() {

                scope.datePicker = {
                    date: new Date(scope.date.getTime()),
                    minDate: null,
                    maxDate: null,
                    popupTitle: angular.isDefined(scope.popupTitle) ? scope.popupTitle : 'Select date',
                    btnCloseText: angular.isDefined(scope.btnCloseText) ? scope.btnCloseText : 'Close',
                    btnSetText: angular.isDefined(scope.btnSetText) ? scope.btnSetText : 'Set',
                    btnTodayText: angular.isDefined(scope.btnTodayText) ? scope.btnTodayText : 'Today',
                    btnCloseType: angular.isDefined(scope.btnCloseType) ? scope.btnCloseType : 'button-default',
                    btnSetType: angular.isDefined(scope.btnSetType) ? scope.btnSetType : 'button-positive',
                    btnTodayType: angular.isDefined(scope.btnTodayType) ? scope.btnTodayType : 'button-default',
                    btnTodayShow: angular.isDefined(scope.btnTodayShow) ? scope.btnTodayShow === "true" : true
                }

                function normalizeTime(dt) {
                    dt.setHours(0);
                    dt.setMinutes(0);
                    dt.setSeconds(0);
                    dt.setMilliseconds(0);
                }

                scope.datePicker.today = new Date();

                normalizeTime(scope.datePicker.date);
                normalizeTime(scope.datePicker.today);

                if (angular.isDefined(scope.minDate)) {
                    scope.datePicker.minDate = new Date(scope.minDate.getTime());
                    normalizeTime(scope.datePicker.minDate);
                }

                if (angular.isDefined(scope.maxDate)) {
                    scope.datePicker.maxDate = new Date(scope.maxDate.getTime());
                    normalizeTime(scope.datePicker.maxDate);
                }

                scope.datePicker.dateSelected = new Date(scope.datePicker.date.getTime());

                scope.datePicker.weekNames = [];

                var weekNamesGen = new Date('October 12, 2019 22:45:00');
                for (var weekDay = 0; weekDay < 7; weekDay++) {
                    weekNamesGen.setDate(weekNamesGen.getDate() + 1);
                    var weekDayName = $filter('date')(weekNamesGen, 'EEE');
                    scope.datePicker.weekNames.push(weekDayName);
                }

                scope.updateWeeks = function() {

                    scope.datePicker.weeks = [];
                    var datePickerMonth = new Date(scope.datePicker.date.getTime());

                    datePickerMonth.setDate(1);

                    var firstDayMonthWeekName = $filter('date')(datePickerMonth, 'EEE');
                    var days = [];
                    var daysFillingComplete = false;
                    for (var i = 0; i < scope.datePicker.weekNames.length && !daysFillingComplete; i++) {
                        if (scope.datePicker.weekNames[i] == firstDayMonthWeekName) {
                            daysFillingComplete = true;
                        } else {
                            days.push(null);
                        }
                    }

                    var currentDatePickerMonth = datePickerMonth.getMonth();
                    while (currentDatePickerMonth == datePickerMonth.getMonth()) {
                        if (days.length == scope.datePicker.weekNames.length) {
                            scope.datePicker.weeks.push(days.slice());
                            days = [];
                        }

                        days.push(new Date(datePickerMonth.getTime()));
                        datePickerMonth.setDate(datePickerMonth.getDate() + 1);
                    }

                    if (days.length > 0) {
                        for (var i = days.length; i < scope.datePicker.weekNames.length; i++) {
                            days.push(null);
                        }
                        scope.datePicker.weeks.push(days);
                    }
                }

                scope.updateWeeks();

                scope.isToday = function(day) {
                    return day != null && day.getTime() == scope.datePicker.today.getTime();
                }

                scope.isSelected = function(day) {
                    return day != null && day.getTime() == scope.datePicker.dateSelected.getTime();
                }

                scope.prevMonthAllowed = function() {
                    var prevMonthAllowed = true;
                    if (scope.datePicker.minDate != null && scope.datePicker.date.getFullYear() <= scope.datePicker.minDate.getFullYear() && scope.datePicker.date.getMonth() <= scope.datePicker.minDate.getMonth()) {
                        prevMonthAllowed = false;
                    }
                    return prevMonthAllowed;
                }

                scope.nextMonthAllowed = function() {
                    var nextMonthAllowed = true;
                    if (scope.datePicker.maxDate != null && scope.datePicker.date.getFullYear() >= scope.datePicker.maxDate.getFullYear() && scope.datePicker.date.getMonth() >= scope.datePicker.maxDate.getMonth()) {
                        nextMonthAllowed = false;
                    }
                    return nextMonthAllowed;
                }

                scope.dayAllowed = function(day) {
                    var dayAllowed = true;

                    if (day != null) {
                        if (scope.datePicker.minDate != null && day.getTime() < scope.datePicker.minDate.getTime()) {
                            dayAllowed = false;
                        } else if (scope.datePicker.maxDate != null && day.getTime() > scope.datePicker.maxDate.getTime()) {
                            dayAllowed = false;
                        }
                    }

                    return dayAllowed;
                }

                scope.prevMonth = function() {
                    scope.datePicker.date.setMonth(scope.datePicker.date.getMonth() - 1);
                    scope.updateWeeks();
                }

                scope.nextMonth = function() {
                    scope.datePicker.date.setMonth(scope.datePicker.date.getMonth() + 1);
                    scope.updateWeeks();
                }

                scope.selectDate = function(day) {
                    if (day != null && scope.dayAllowed(day)) {
                        scope.datePicker.dateSelected = day;

                        var updateWeeks = scope.datePicker.date.getMonth() != day.getMonth();

                        if (updateWeeks) {
                            scope.datePicker.date = new Date(day.getTime());
                            scope.updateWeeks();
                        }
                    }
                }

                var popupButtons = [];

                popupButtons.push({
                    text: scope.datePicker.btnCloseText,
                    type: scope.datePicker.btnCloseType
                });

                if (scope.datePicker.btnTodayShow) {
                    popupButtons.push({
                        text: scope.datePicker.btnTodayText,
                        type: scope.datePicker.btnTodayType,

                        onTap: function(e) {

                            e.preventDefault();

                            scope.datePicker.today = new Date();

                            normalizeTime(scope.datePicker.today);

                            scope.selectDate(new Date(scope.datePicker.today.getTime()));
                        }
                    });
                }

                popupButtons.push({
                    text: scope.datePicker.btnSetText,
                    type: scope.datePicker.btnSetType,
                    onTap: function(e) {
                        scope.date = scope.datePicker.dateSelected;
                    }
                });

                $ionicPopup.show({
                    templateUrl: 'date-picker-modal.html',
                    title: '' + scope.datePicker.popupTitle + '',
                    subTitle: '',
                    scope: scope,
                    buttons: popupButtons
                })
            });
        }
    }
}]);
<|endoftext|>


<commit_before>#! /usr/bin/env node

const shell = require('shelljs');

const docsDir = './docs/gaiden-css';
const sourceDocsDir = './docs/demo/gaiden-css/scss';
const sourceDir = './src/scss';
const minifiedDocsFile = `${docsDir}/ninja-demo.css`;

const timestamp = new Date().getTime();

const options = {
  sass: ` --include-path ${sourceDocsDir} \
    --include-path ${sourceDir} \
    --output-style expanded \
    --sourceComments true \
    -o ${docsDir} \
    --recursive `
}

shell.exec('git checkout -B gh-pages');
shell.exec('git pull origin gh-pages --no-commit');

shell.exec(`node-sass ${sourceDocsDir} ${options.sass} ${minifiedDocsFile}`);
shell.exec(`documentjs`);

shell.cp('./dist/gaiden.min.css', './');

shell.cp('-R', `${docsDir}/`, './');

shell.ls('./docs/demo/*.html').forEach(function(file) {
  shell.sed('-i', 'docs\/demo\/', 'demo', file);
  shell.sed('-i', '\/gaiden-css\/gaiden.css', '\/gaiden.css', file);
});

shell.mkdir('-p', './demo/gaiden-css');
shell.cp('-Rf', './docs/demo/gaiden-css', './demo/gaiden-css');

const gaidenLastTag = shell.exec('git describe');

shell.exec('git add .');
shell.exec(`git commit -am '${timestamp}: Updating docs ${gaidenLastTag}'`);
shell.exec('git push origin gh-pages');
shell.exec('git checkout -');
<commit_msg>Using output key from shell.exec command<commit_after>#! /usr/bin/env node

const shell = require('shelljs');

const docsDir = './docs/gaiden-css';
const sourceDocsDir = './docs/demo/gaiden-css/scss';
const sourceDir = './src/scss';
const minifiedDocsFile = `${docsDir}/ninja-demo.css`;

const timestamp = new Date().getTime();

const options = {
  sass: ` --include-path ${sourceDocsDir} \
    --include-path ${sourceDir} \
    --output-style expanded \
    --sourceComments true \
    -o ${docsDir} \
    --recursive `
}

shell.exec('git checkout -B gh-pages');
shell.exec('git pull origin gh-pages --no-commit');

shell.exec(`node-sass ${sourceDocsDir} ${options.sass} ${minifiedDocsFile}`);
shell.exec(`documentjs`);

shell.cp('./dist/gaiden.min.css', './');

shell.cp('-R', `${docsDir}/`, './');

shell.ls('./docs/demo/*.html').forEach(function(file) {
  shell.sed('-i', 'docs\/demo\/', 'demo', file);
  shell.sed('-i', '\/gaiden-css\/gaiden.css', '\/gaiden.css', file);
});

shell.mkdir('-p', './demo/gaiden-css');
shell.cp('-Rf', './docs/demo/gaiden-css', './demo/gaiden-css');

const gaidenLastTag = shell.exec('git describe');

shell.exec('git add .');
shell.exec(`git commit -am '${timestamp}: Updating docs ${gaidenLastTag.output}'`);
shell.exec('git push origin gh-pages');
shell.exec('git checkout -');
<|endoftext|>


<commit_before>/**
 * Add a barogram.
 *
 * Note: _time, _enl, and _height MUST have the same number
 *   of elements when decoded.
 *
 * @param {DOMElement} placeholder DOM element for the barogram.
 * @param {int} sfid SkyLines flight ID.
 * @param {String} _time Google polyencoded string of time values.
 * @param {String} _height Google polyencoded string of height values.
 * @param {String} _enl Google polyencoded string of engine noise levels.
 * @param {String} _elevations_h Google polyencoded string of elevations.
 * @param {int} takeoff_time Time of takeoff.
 * @param {int} scoring_start_time Time of scoring start.
 * @param {int} scoring_end_time Time of scoring end.
 * @param {int} landing_time Time of landing.
 * @return {Object} Barogram.
 */
function initBaro(placeholder, sfid, _time, _height, _enl,
                  _elevations_h, takeoff_time, scoring_start_time,
                  scoring_end_time, landing_time) {
  var height = ol.format.Polyline.decodeDeltas(_height, 1, 1);
  var time = ol.format.Polyline.decodeDeltas(_time, 1, 1);
  var enl = ol.format.Polyline.decodeDeltas(_enl, 1, 1);
  var _elev_h = ol.format.Polyline.decodeDeltas(_elevations_h, 1, 1);

  var flot_h = [], flot_enl = [];
  var flot_elev = [], elev_h = [];
  var timeLength = time.length;
  for (var i = 0; i < timeLength; ++i) {
    var timestamp = time[i] * 1000;
    flot_h.push([timestamp, slUnits.convertAltitude(height[i])]);
    flot_enl.push([timestamp, enl[i]]);

    var e = _elev_h[i];
    if (e < -500)
      e = null;

    elev_h.push(e);
    flot_elev.push([timestamp, e ? slUnits.convertAltitude(e) : null]);
  }

  var color = '#004bbd';

  var data = {
    data: flot_h,
    color: color
  };

  var enl_data = {
    data: flot_enl,
    color: color
  };

  var baro_opts = {
    selection: {
      mode: 'x'
    },
    crosshair: {
      mode: null
    }
  };

  var baro = slBarogram(placeholder, baro_opts);
  baro.setActiveTraces([data]);
  baro.setENLData([enl_data]);
  baro.setElevations(flot_elev);

  baro.setFlightTimes(
      takeoff_time,
      scoring_start_time,
      scoring_end_time,
      landing_time
  );

  baro.draw();

  return baro;
}

/**
* Update the timepicker values.
*
* @param {number} prefix Prefix of uploaded flight.
* @param {number} flight_date Unix timestamp of takeoff date.
* @param {Object} values Values of the current markers.
*/
function updateTimePicker(prefix, flight_date, values) {
  var takeOffTimePicker = $('#' + prefix + '-takeoff_time-datetimepicker');
  if (takeOffTimePicker.data('DateTimePicker').getDate().unix() !=
      parseInt(values.takeoff / 1000)) {
    var datetime = flight_date.clone().add('ms', values.takeoff);

    takeOffTimePicker.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-takeoff_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }

  var scoringStartTimePicket = $('#' + prefix + '-scoring_start_time-datetimepicker');
  if (scoringStartTimePicket.data('DateTimePicker').getDate().unix() !=
      parseInt(values.scoring_start / 1000)) {
    var datetime = flight_date.clone().add('ms', values.scoring_start);

    scoringStartTimePicket.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-scoring_start_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }

  var scoringEndTimePicker = $('#' + prefix + '-scoring_end_time-datetimepicker');
  if (scoringEndTimePicker.data('DateTimePicker').getDate().unix() !=
      parseInt(values.scoring_end / 1000)) {
    var datetime = flight_date.clone().add('ms', values.scoring_end);

    scoringEndTimePicker.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-scoring_end_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }

  var landingTimePicker = $('#' + prefix + '-landing_time-datetimepicker');
  if (landingTimePicker.data('DateTimePicker').getDate().unix() !=
      parseInt(values.landing / 1000)) {
    var datetime = flight_date.clone().add('ms', values.landing);

    landingTimePicker.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-landing_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }
}
<commit_msg>js/upload: Fixed line-to-long issues<commit_after>/**
 * Add a barogram.
 *
 * Note: _time, _enl, and _height MUST have the same number
 *   of elements when decoded.
 *
 * @param {DOMElement} placeholder DOM element for the barogram.
 * @param {int} sfid SkyLines flight ID.
 * @param {String} _time Google polyencoded string of time values.
 * @param {String} _height Google polyencoded string of height values.
 * @param {String} _enl Google polyencoded string of engine noise levels.
 * @param {String} _elevations_h Google polyencoded string of elevations.
 * @param {int} takeoff_time Time of takeoff.
 * @param {int} scoring_start_time Time of scoring start.
 * @param {int} scoring_end_time Time of scoring end.
 * @param {int} landing_time Time of landing.
 * @return {Object} Barogram.
 */
function initBaro(placeholder, sfid, _time, _height, _enl,
                  _elevations_h, takeoff_time, scoring_start_time,
                  scoring_end_time, landing_time) {
  var height = ol.format.Polyline.decodeDeltas(_height, 1, 1);
  var time = ol.format.Polyline.decodeDeltas(_time, 1, 1);
  var enl = ol.format.Polyline.decodeDeltas(_enl, 1, 1);
  var _elev_h = ol.format.Polyline.decodeDeltas(_elevations_h, 1, 1);

  var flot_h = [], flot_enl = [];
  var flot_elev = [], elev_h = [];
  var timeLength = time.length;
  for (var i = 0; i < timeLength; ++i) {
    var timestamp = time[i] * 1000;
    flot_h.push([timestamp, slUnits.convertAltitude(height[i])]);
    flot_enl.push([timestamp, enl[i]]);

    var e = _elev_h[i];
    if (e < -500)
      e = null;

    elev_h.push(e);
    flot_elev.push([timestamp, e ? slUnits.convertAltitude(e) : null]);
  }

  var color = '#004bbd';

  var data = {
    data: flot_h,
    color: color
  };

  var enl_data = {
    data: flot_enl,
    color: color
  };

  var baro_opts = {
    selection: {
      mode: 'x'
    },
    crosshair: {
      mode: null
    }
  };

  var baro = slBarogram(placeholder, baro_opts);
  baro.setActiveTraces([data]);
  baro.setENLData([enl_data]);
  baro.setElevations(flot_elev);

  baro.setFlightTimes(
      takeoff_time,
      scoring_start_time,
      scoring_end_time,
      landing_time
  );

  baro.draw();

  return baro;
}

/**
* Update the timepicker values.
*
* @param {number} prefix Prefix of uploaded flight.
* @param {number} flight_date Unix timestamp of takeoff date.
* @param {Object} values Values of the current markers.
*/
function updateTimePicker(prefix, flight_date, values) {
  var takeOffTimePicker = $('#' + prefix + '-takeoff_time-datetimepicker');
  if (takeOffTimePicker.data('DateTimePicker').getDate().unix() !=
      parseInt(values.takeoff / 1000)) {
    var datetime = flight_date.clone().add('ms', values.takeoff);

    takeOffTimePicker.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-takeoff_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }

  var scoringStartTimePicket =
      $('#' + prefix + '-scoring_start_time-datetimepicker');
  if (scoringStartTimePicket.data('DateTimePicker').getDate().unix() !=
      parseInt(values.scoring_start / 1000)) {
    var datetime = flight_date.clone().add('ms', values.scoring_start);

    scoringStartTimePicket.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-scoring_start_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }

  var scoringEndTimePicker =
      $('#' + prefix + '-scoring_end_time-datetimepicker');
  if (scoringEndTimePicker.data('DateTimePicker').getDate().unix() !=
      parseInt(values.scoring_end / 1000)) {
    var datetime = flight_date.clone().add('ms', values.scoring_end);

    scoringEndTimePicker.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-scoring_end_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }

  var landingTimePicker = $('#' + prefix + '-landing_time-datetimepicker');
  if (landingTimePicker.data('DateTimePicker').getDate().unix() !=
      parseInt(values.landing / 1000)) {
    var datetime = flight_date.clone().add('ms', values.landing);

    landingTimePicker.data('DateTimePicker').setValue(datetime);
    $('#' + prefix + '-landing_time')
        .val(datetime.format('YYYY-MM-DD HH:mm:ss'));
  }
}
<|endoftext|>


<commit_before>#! /usr/bin/env node

const shell = require('shelljs');

const docsDir = './docs/gaiden-css';
const sourceDocsDir = './docs/demo/gaiden-css/scss';
const sourceDir = './src/scss';
const minifiedDocsFile = `${docsDir}/ninja-demo.css`;

const timestamp = new Date().getTime();

const options = {
  sass: ` --include-path ${sourceDocsDir} \
    --include-path ${sourceDir} \
    --output-style expanded \
    --sourceComments true \
    -o ${docsDir} \
    --recursive `
}

shell.exec(`node-sass ${sourceDocsDir} ${options.sass} ${minifiedDocsFile}`);
shell.exec(`documentjs -f`);

shell.cp('./dist/gaiden.min.css', './');

shell.exec('git checkout -B gh-pages');
shell.exec('git pull origin gh-pages --no-commit');

const filesToFixPath = shell.ls('-R', './docs/demo/').filter(function(file) {
  return file.match(/(\.html$|\.js$)/);
});

filesToFixPath.forEach(function(file) {
  shell.sed('-i', 'docs\/demo\/', 'demo', `./docs/demo/${file}`);
  shell.sed('-i', '\/gaiden-css\/gaiden.css', '\/gaiden.css', `./docs/demo/${file}`);
});

shell.mv('-nf', `${docsDir}/*`, './');

shell.mkdir('-p', './demo/gaiden-css');
shell.cp('-Rf', './docs/demo/gaiden-css', './demo/gaiden-css');

const gaidenLastTag = shell.exec('git describe').stdout.replace(/\n/g, '');

shell.exec('git add . -A');
shell.exec(`git commit -m "${timestamp}: Updating docs ${gaidenLastTag}"`);
shell.exec('git push origin gh-pages --force');
shell.exec('git checkout -');
<commit_msg>Recursive on cp<commit_after>#! /usr/bin/env node

const shell = require('shelljs');

const docsDir = './docs/gaiden-css';
const sourceDocsDir = './docs/demo/gaiden-css/scss';
const sourceDir = './src/scss';
const minifiedDocsFile = `${docsDir}/ninja-demo.css`;

const timestamp = new Date().getTime();

const options = {
  sass: ` --include-path ${sourceDocsDir} \
    --include-path ${sourceDir} \
    --output-style expanded \
    --sourceComments true \
    -o ${docsDir} \
    --recursive `
}

shell.exec(`node-sass ${sourceDocsDir} ${options.sass} ${minifiedDocsFile}`);
shell.exec(`documentjs -f`);

shell.cp('./dist/gaiden.min.css', './');

shell.exec('git checkout -B gh-pages');
shell.exec('git pull origin gh-pages --no-commit');

const filesToFixPath = shell.ls('-R', './docs/demo/').filter(function(file) {
  return file.match(/(\.html$|\.js$)/);
});

filesToFixPath.forEach(function(file) {
  shell.sed('-i', 'docs\/demo\/', 'demo', `./docs/demo/${file}`);
  shell.sed('-i', '\/gaiden-css\/gaiden.css', '\/gaiden.css', `./docs/demo/${file}`);
});

shell.cp('-nfr', `${docsDir}/`, './');

shell.mkdir('-p', './demo/gaiden-css');
shell.cp('-Rf', './docs/demo/gaiden-css', './demo/gaiden-css');

const gaidenLastTag = shell.exec('git describe').stdout.replace(/\n/g, '');

shell.exec('git add . -A');
shell.exec(`git commit -m "${timestamp}: Updating docs ${gaidenLastTag}"`);
shell.exec('git push origin gh-pages --force');
shell.exec('git checkout -');
<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * Generate `.json` test files.
 * Usage: `./bin/generate-tests.js <syntax name> [<syntax name>]`.
 * Example: `./bin/generate-tests.js scss less`.
 */

var gonzales = require('../lib/gonzales'),
    fs = require('fs'),
    path = require('path'),
    syntaxList = process.argv.slice(2);

syntaxList.forEach(function (s) {
    var syntaxDir = 'test/' + s;
    var extension = '.' + s;

    fs.readdirSync(syntaxDir).forEach(function(testDir) {
        fs.readdirSync(path.join(syntaxDir, testDir)).forEach(function(file) {
            if (path.extname(file) !== extension) return;

            try {
                generateTest(path.join(syntaxDir, testDir, file));
            } catch (e) {
                console.log('*', path.join(syntaxDir, testDir, file));
            }
        });
    });
});

function generateTest(filePath) {
    var testDir = path.dirname(filePath);
    var rule = path.basename(testDir);
    var syntax = path.basename(path.dirname(testDir));
    var fileName = path.basename(filePath, '.' + syntax);

    var inputPath = path.join(testDir, fileName + '.' + syntax);
    var outputPath = path.join(testDir, fileName + '.json');

    var string = fs.readFileSync(inputPath, 'utf-8').trim();
    var ast = gonzales.srcToAST({
        src: string,
        syntax: syntax,
        needInfo: true,
        rule: rule
    });

    ast = gonzales.astToString(ast);

    fs.writeFileSync(outputPath, ast);
}

<commit_msg>[tools] Update `generate-tests.js` to use new API<commit_after>#!/usr/bin/env node

/**
 * Generate `.json` test files.
 * Usage: `./bin/generate-tests.js <syntax name> [<syntax name>]`.
 * Example: `./bin/generate-tests.js scss less`.
 */

var gonzales = require('..'),
    fs = require('fs'),
    path = require('path'),
    syntaxList = process.argv.slice(2);

syntaxList.forEach(function (s) {
    var syntaxDir = 'test/' + s;
    var extension = '.' + s;

    fs.readdirSync(syntaxDir).forEach(function(testDir) {
        fs.readdirSync(path.join(syntaxDir, testDir)).forEach(function(file) {
            if (path.extname(file) !== extension) return;

            try {
                generateTest(path.join(syntaxDir, testDir, file));
            } catch (e) {
                console.log('*', path.join(syntaxDir, testDir, file));
            }
        });
    });
});

function generateTest(filePath) {
    var testDir = path.dirname(filePath);
    var rule = path.basename(testDir);
    var syntax = path.basename(path.dirname(testDir));
    var fileName = path.basename(filePath, '.' + syntax);

    var inputPath = path.join(testDir, fileName + '.' + syntax);
    var outputPath = path.join(testDir, fileName + '.json');

    var string = fs.readFileSync(inputPath, 'utf-8').trim();
    var ast = gonzales.parse(string, {syntax: syntax, rule: rule});

    fs.writeFileSync(outputPath, ast.toString());
}

<|endoftext|>


<commit_before>function mg_add_scale_function(args, scalefcn_name, scale, accessor, inflation) {
  args.scalefns[scalefcn_name] = function(di) {
    if (inflation === undefined) return args.scales[scale](di[accessor]);
    else return args.scales[scale](di[accessor]) + inflation;
  };
}

function mg_position(str, args) {
  if (str === 'bottom' || str === 'top') {
    return [mg_get_plot_left(args), mg_get_plot_right(args)];
  }

  if (str === 'left' || str === 'right') {
    return [mg_get_plot_bottom(args), args.top];
  }
}

function mg_cat_position(str, args) {
  if (str === 'bottom' || str === 'top') {
    return [mg_get_plot_left(args), mg_get_plot_right(args)]
  }

  if (str === 'left' || str === 'right') {
    return [mg_get_plot_bottom(args), mg_get_plot_top(args)];
  }
}

function MGScale(args) {
  // big wrapper around d3 scale that automatically formats & calculates scale bounds
  // according to the data, and handles other niceties.
  var scaleArgs = {}
  scaleArgs.use_inflator = false;
  scaleArgs.zero_bottom = false;
  scaleArgs.scaleType = 'numerical';

  this.namespace = function(_namespace) {
    scaleArgs.namespace = _namespace;
    scaleArgs.namespace_accessor_name = scaleArgs.namespace + '_accessor';
    scaleArgs.scale_name = scaleArgs.namespace.toUpperCase();
    scaleArgs.scalefn_name = scaleArgs.namespace + 'f';
    return this;
  }

  this.scaleName = function(scaleName) {
    scaleArgs.scale_name = scaleName.toUpperCase();
    scaleArgs.scalefn_name = scaleName +'f';
    return this;
  }

  this.inflateDomain = function(tf) {
    scaleArgs.use_inflator = tf;
    return this;
  }

  this.zeroBottom = function(tf) {
    scaleArgs.zero_bottom = tf;
    return this;
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  /// all scale domains are either numerical (number, date, etc.) or categorical (factor, label, etc) /////
  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  // these functions automatically create the d3 scale function and place the domain.

  this.numericalDomainFromData = function() {
    var other_flat_data_arrays = [];

    if (arguments.length > 0) {
      other_flat_data_arrays = arguments;
    }

    // pull out a non-empty array in args.data.
    var illustrative_data;
    for (var i = 0; i < args.data.length; i++) {
      if (args.data[i].length > 0) {
        illustrative_data = args.data[i];
      }
    }
    scaleArgs.is_time_series = mg_is_date(illustrative_data[0][args[scaleArgs.namespace_accessor_name]])
      ? true
      : false;

    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);

    mg_min_max_numerical(args, scaleArgs, other_flat_data_arrays, scaleArgs.use_inflator);

    var time_scale = (args.utc_time)
      ? d3.scaleUtc()
      : d3.scaleTime();

    args.scales[scaleArgs.scale_name] = (scaleArgs.is_time_series)
      ? time_scale
      : (mg_is_function(args[scaleArgs.namespace + '_scale_type']))
        ? args.y_scale_type()
        : (args[scaleArgs.namespace + '_scale_type'] === 'log')
          ? d3.scaleLog()
          : d3.scaleLinear();

    args.scales[scaleArgs.scale_name].domain([args.processed['min_' + scaleArgs.namespace], args.processed['max_' + scaleArgs.namespace]]);
    scaleArgs.scaleType = 'numerical';

    return this;
  }

  this.categoricalDomain = function(domain) {
    args.scales[scaleArgs.scale_name] = d3.scaleOrdinal().domain(domain);
    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);
    return this;
  }

  this.categoricalDomainFromData = function() {
    // make args.categorical_variables.
    // lets make the categorical variables.
    var all_data = mg_flatten_array(args.data)
    //d3.set(data.map(function(d){return d[args.group_accessor]})).values()
    scaleArgs.categoricalVariables = d3.set(all_data.map(function(d) {
      return d[args[scaleArgs.namespace_accessor_name]] })).values();
    args.scales[scaleArgs.scale_name] = d3.scaleBand()
      .domain(scaleArgs.categoricalVariables);

    scaleArgs.scaleType = 'categorical';
    return this;
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////// all scale ranges are either positional (for axes, etc) or arbitrary (colors, size, etc) //////////
  /////////////////////////////////////////////////////////////////////////////////////////////////////////////

  this.numericalRange = function(range) {
    if (typeof range === 'string') {
      args
        .scales[scaleArgs.scale_name]
        .range(mg_position(range, args));
    } else {
      args
        .scales[scaleArgs.scale_name]
        .range(range);
    }

    return this;
  }

  this.categoricalRangeBands = function(range, halfway) {
    if (halfway === undefined) halfway = false;

    var namespace = scaleArgs.namespace;
    var paddingPercentage = args[namespace + '_padding_percentage'];
    var outerPaddingPercentage = args[namespace + '_outer_padding_percentage'];
    if (typeof range === 'string') {
      // if string, it's a location. Place it accordingly.
      args.scales[scaleArgs.scale_name]
        .range(mg_position(range, args))
        .paddingInner(paddingPercentage)
        .paddingOuter(outerPaddingPercentage);
    } else {
      args.scales[scaleArgs.scale_name]
        .range(range)
        .paddingInner(paddingPercentage)
        .paddingOuter(outerPaddingPercentage);
    }

    mg_add_scale_function(
      args,
      scaleArgs.scalefn_name,
      scaleArgs.scale_name,
      args[scaleArgs.namespace_accessor_name],
      halfway
        ? args.scales[scaleArgs.scale_name].bandwidth() / 2
        : 0
    );

    return this;
  }

  this.categoricalRange = function(range) {
    args.scales[scaleArgs.scale_name].range(range);
    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);
    return this;
  }

  this.categoricalColorRange = function() {
    args.scales[scaleArgs.scale_name] = args.scales[scaleArgs.scale_name].domain().length > 10
      ? d3.scaleOrdinal(d3.schemeCategory20)
      : d3.scaleOrdinal(d3.schemeCategory10);

    args
      .scales[scaleArgs.scale_name]
      .domain(scaleArgs.categoricalVariables);

    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);
    return this;
  }

  this.clamp = function(yn) {
    args.scales[scaleArgs.scale_name].clamp(yn);
    return this;
  }

  return this;
}

MG.scale_factory = MGScale;

/////////////////////////////// x, x_accessor, markers, baselines, etc.
function mg_min_max_numerical(args, scaleArgs, additional_data_arrays) {
  // A BIT OF EXPLANATION ABOUT THIS FUNCTION
  // This function pulls out all the accessor values in all the arrays in args.data.
  // We also have this additional argument, additional_data_arrays, which is an array of arrays of raw data values.
  // These values also get concatenated to the data pulled from args.data, and the extents are calculate from that.
  // They are optional.
  //
  // This may seem arbitrary, but it gives us a lot of flexibility. For instance, if we're calculating
  // the min and max for the y axis of a line chart, we're going to want to also factor in baselines (horizontal lines
  // that might potentially be outside of the y value bounds). The easiest way to do this is in the line.js code
  // & scale creation to just flatten the args.baselines array, pull out hte values, and feed it in
  // so it appears in additional_data_arrays.
  var namespace = scaleArgs.namespace;
  var namespace_accessor_name = scaleArgs.namespace_accessor_name;
  var use_inflator = scaleArgs.use_inflator;
  var zero_bottom = scaleArgs.zero_bottom;

  var accessor = args[namespace_accessor_name];

  // add together all relevant data arrays.
  var all_data = mg_flatten_array(args.data)
    .map(function(dp) {
      return dp[accessor] })
    .concat(mg_flatten_array(additional_data_arrays));

  // do processing for log
  if (args[namespace + '_scale_type'] === 'log') {
    all_data = all_data.filter(function(d) {
      return d > 0;
    });
  }

  // use inflator?
  var extents = d3.extent(all_data);
  var min_val = extents[0];
  var max_val = extents[1];

  // bolt scale domain to zero when the right conditions are met:
  // not pulling the bottom of the range from data
  // not zero-bottomed
  // not a time series
  if (zero_bottom && !args['min_' + namespace + '_from_data'] && min_val > 0 && !scaleArgs.is_time_series) {
    min_val = args[namespace + '_scale_type'] === 'log' ? 1 : 0;
  }

  if (args[namespace + '_scale_type'] !== 'log' && min_val < 0 && !scaleArgs.is_time_series) {
    min_val = min_val - (min_val - min_val * args.inflator) * use_inflator;
  }

  if (!scaleArgs.is_time_series) {
    max_val = (max_val < 0) ? max_val + (max_val - max_val * args.inflator) * use_inflator : max_val * (use_inflator ? args.inflator : 1);
  }

  min_val = args['min_' + namespace] || min_val;
  max_val = args['max_' + namespace] || max_val;
  // if there's a single data point, we should custom-set the min and max values.

  if (min_val === max_val && !(args['min_' + namespace] && args['max_' + namespace])) {

    if (mg_is_date(min_val)) {
      max_val = new Date(MG.clone(min_val).setDate(min_val.getDate() + 1));
      min_val = new Date(MG.clone(min_val).setDate(min_val.getDate() - 1));
    } else if (typeof min_val === 'number') {
      min_val = min_val - 1;
      max_val = min_val + 1;
      mg_force_xax_count_to_be_two(args);
    }
  }

  args.processed['min_' + namespace] = min_val;
  args.processed['max_' + namespace] = max_val;

  MG.call_hook('x_axis.process_min_max', args, args.processed.min_x, args.processed.max_x);
  MG.call_hook('y_axis.process_min_max', args, args.processed.min_y, args.processed.max_y);
}

function mg_categorical_group_color_scale(args) {
  if (args.color_accessor !== false) {
    if (args.ygroup_accessor) {
      // add a custom accessor element.
      if (args.color_accessor === null) {
        args.color_accessor = args.y_accessor;
      } else {}
    }
    if (args.color_accessor !== null) {
      new MG.scale_factory(args)
        .namespace('color')
        .categoricalDomainFromData()
        .categoricalColorRange();
    }
  }
}

function mg_add_color_categorical_scale(args, domain, accessor) {
  args.scales.color = d3.scaleOrdinal(d3.schemeCategory20).domain(domain);
  args.scalefns.color = function(d) {
    return args.scales.color(d[accessor]);
  };
}

function mg_get_categorical_domain(data, accessor) {
  return d3.set(data.map(function(d) {
      return d[accessor]; }))
    .values();
}

function mg_get_color_domain(args) {
  var color_domain;
  if (args.color_domain === null) {
    if (args.color_type === 'number') {
      color_domain = d3.extent(args.data[0], function(d) {
        return d[args.color_accessor]; });
    } else if (args.color_type === 'category') {
      color_domain = mg_get_categorical_domain(args.data[0], args.color_accessor);

    }
  } else {
    color_domain = args.color_domain;
  }
  return color_domain;
}

function mg_get_color_range(args) {
  var color_range;
  if (args.color_range === null) {
    if (args.color_type === 'number') {
      color_range = ['blue', 'red'];
    } else {
      color_range = null;
    }
  } else {
    color_range = args.color_range;
  }
  return color_range;
}
<commit_msg>Custom set min_x/min_y if equal only if not overridden by an argument<commit_after>function mg_add_scale_function(args, scalefcn_name, scale, accessor, inflation) {
  args.scalefns[scalefcn_name] = function(di) {
    if (inflation === undefined) return args.scales[scale](di[accessor]);
    else return args.scales[scale](di[accessor]) + inflation;
  };
}

function mg_position(str, args) {
  if (str === 'bottom' || str === 'top') {
    return [mg_get_plot_left(args), mg_get_plot_right(args)];
  }

  if (str === 'left' || str === 'right') {
    return [mg_get_plot_bottom(args), args.top];
  }
}

function mg_cat_position(str, args) {
  if (str === 'bottom' || str === 'top') {
    return [mg_get_plot_left(args), mg_get_plot_right(args)]
  }

  if (str === 'left' || str === 'right') {
    return [mg_get_plot_bottom(args), mg_get_plot_top(args)];
  }
}

function MGScale(args) {
  // big wrapper around d3 scale that automatically formats & calculates scale bounds
  // according to the data, and handles other niceties.
  var scaleArgs = {}
  scaleArgs.use_inflator = false;
  scaleArgs.zero_bottom = false;
  scaleArgs.scaleType = 'numerical';

  this.namespace = function(_namespace) {
    scaleArgs.namespace = _namespace;
    scaleArgs.namespace_accessor_name = scaleArgs.namespace + '_accessor';
    scaleArgs.scale_name = scaleArgs.namespace.toUpperCase();
    scaleArgs.scalefn_name = scaleArgs.namespace + 'f';
    return this;
  }

  this.scaleName = function(scaleName) {
    scaleArgs.scale_name = scaleName.toUpperCase();
    scaleArgs.scalefn_name = scaleName +'f';
    return this;
  }

  this.inflateDomain = function(tf) {
    scaleArgs.use_inflator = tf;
    return this;
  }

  this.zeroBottom = function(tf) {
    scaleArgs.zero_bottom = tf;
    return this;
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  /// all scale domains are either numerical (number, date, etc.) or categorical (factor, label, etc) /////
  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  // these functions automatically create the d3 scale function and place the domain.

  this.numericalDomainFromData = function() {
    var other_flat_data_arrays = [];

    if (arguments.length > 0) {
      other_flat_data_arrays = arguments;
    }

    // pull out a non-empty array in args.data.
    var illustrative_data;
    for (var i = 0; i < args.data.length; i++) {
      if (args.data[i].length > 0) {
        illustrative_data = args.data[i];
      }
    }
    scaleArgs.is_time_series = mg_is_date(illustrative_data[0][args[scaleArgs.namespace_accessor_name]])
      ? true
      : false;

    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);

    mg_min_max_numerical(args, scaleArgs, other_flat_data_arrays, scaleArgs.use_inflator);

    var time_scale = (args.utc_time)
      ? d3.scaleUtc()
      : d3.scaleTime();

    args.scales[scaleArgs.scale_name] = (scaleArgs.is_time_series)
      ? time_scale
      : (mg_is_function(args[scaleArgs.namespace + '_scale_type']))
        ? args.y_scale_type()
        : (args[scaleArgs.namespace + '_scale_type'] === 'log')
          ? d3.scaleLog()
          : d3.scaleLinear();

    args.scales[scaleArgs.scale_name].domain([args.processed['min_' + scaleArgs.namespace], args.processed['max_' + scaleArgs.namespace]]);
    scaleArgs.scaleType = 'numerical';

    return this;
  }

  this.categoricalDomain = function(domain) {
    args.scales[scaleArgs.scale_name] = d3.scaleOrdinal().domain(domain);
    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);
    return this;
  }

  this.categoricalDomainFromData = function() {
    // make args.categorical_variables.
    // lets make the categorical variables.
    var all_data = mg_flatten_array(args.data)
    //d3.set(data.map(function(d){return d[args.group_accessor]})).values()
    scaleArgs.categoricalVariables = d3.set(all_data.map(function(d) {
      return d[args[scaleArgs.namespace_accessor_name]] })).values();
    args.scales[scaleArgs.scale_name] = d3.scaleBand()
      .domain(scaleArgs.categoricalVariables);

    scaleArgs.scaleType = 'categorical';
    return this;
  }

  /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////// all scale ranges are either positional (for axes, etc) or arbitrary (colors, size, etc) //////////
  /////////////////////////////////////////////////////////////////////////////////////////////////////////////

  this.numericalRange = function(range) {
    if (typeof range === 'string') {
      args
        .scales[scaleArgs.scale_name]
        .range(mg_position(range, args));
    } else {
      args
        .scales[scaleArgs.scale_name]
        .range(range);
    }

    return this;
  }

  this.categoricalRangeBands = function(range, halfway) {
    if (halfway === undefined) halfway = false;

    var namespace = scaleArgs.namespace;
    var paddingPercentage = args[namespace + '_padding_percentage'];
    var outerPaddingPercentage = args[namespace + '_outer_padding_percentage'];
    if (typeof range === 'string') {
      // if string, it's a location. Place it accordingly.
      args.scales[scaleArgs.scale_name]
        .range(mg_position(range, args))
        .paddingInner(paddingPercentage)
        .paddingOuter(outerPaddingPercentage);
    } else {
      args.scales[scaleArgs.scale_name]
        .range(range)
        .paddingInner(paddingPercentage)
        .paddingOuter(outerPaddingPercentage);
    }

    mg_add_scale_function(
      args,
      scaleArgs.scalefn_name,
      scaleArgs.scale_name,
      args[scaleArgs.namespace_accessor_name],
      halfway
        ? args.scales[scaleArgs.scale_name].bandwidth() / 2
        : 0
    );

    return this;
  }

  this.categoricalRange = function(range) {
    args.scales[scaleArgs.scale_name].range(range);
    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);
    return this;
  }

  this.categoricalColorRange = function() {
    args.scales[scaleArgs.scale_name] = args.scales[scaleArgs.scale_name].domain().length > 10
      ? d3.scaleOrdinal(d3.schemeCategory20)
      : d3.scaleOrdinal(d3.schemeCategory10);

    args
      .scales[scaleArgs.scale_name]
      .domain(scaleArgs.categoricalVariables);

    mg_add_scale_function(args, scaleArgs.scalefn_name, scaleArgs.scale_name, args[scaleArgs.namespace_accessor_name]);
    return this;
  }

  this.clamp = function(yn) {
    args.scales[scaleArgs.scale_name].clamp(yn);
    return this;
  }

  return this;
}

MG.scale_factory = MGScale;

/////////////////////////////// x, x_accessor, markers, baselines, etc.
function mg_min_max_numerical(args, scaleArgs, additional_data_arrays) {
  // A BIT OF EXPLANATION ABOUT THIS FUNCTION
  // This function pulls out all the accessor values in all the arrays in args.data.
  // We also have this additional argument, additional_data_arrays, which is an array of arrays of raw data values.
  // These values also get concatenated to the data pulled from args.data, and the extents are calculate from that.
  // They are optional.
  //
  // This may seem arbitrary, but it gives us a lot of flexibility. For instance, if we're calculating
  // the min and max for the y axis of a line chart, we're going to want to also factor in baselines (horizontal lines
  // that might potentially be outside of the y value bounds). The easiest way to do this is in the line.js code
  // & scale creation to just flatten the args.baselines array, pull out hte values, and feed it in
  // so it appears in additional_data_arrays.
  var namespace = scaleArgs.namespace;
  var namespace_accessor_name = scaleArgs.namespace_accessor_name;
  var use_inflator = scaleArgs.use_inflator;
  var zero_bottom = scaleArgs.zero_bottom;

  var accessor = args[namespace_accessor_name];

  // add together all relevant data arrays.
  var all_data = mg_flatten_array(args.data)
    .map(function(dp) {
      return dp[accessor] })
    .concat(mg_flatten_array(additional_data_arrays));

  // do processing for log
  if (args[namespace + '_scale_type'] === 'log') {
    all_data = all_data.filter(function(d) {
      return d > 0;
    });
  }

  // use inflator?
  var extents = d3.extent(all_data);
  var min_val = extents[0];
  var max_val = extents[1];

  // bolt scale domain to zero when the right conditions are met:
  // not pulling the bottom of the range from data
  // not zero-bottomed
  // not a time series
  if (zero_bottom && !args['min_' + namespace + '_from_data'] && min_val > 0 && !scaleArgs.is_time_series) {
    min_val = args[namespace + '_scale_type'] === 'log' ? 1 : 0;
  }

  if (args[namespace + '_scale_type'] !== 'log' && min_val < 0 && !scaleArgs.is_time_series) {
    min_val = min_val - (min_val - min_val * args.inflator) * use_inflator;
  }

  if (!scaleArgs.is_time_series) {
    max_val = (max_val < 0) ? max_val + (max_val - max_val * args.inflator) * use_inflator : max_val * (use_inflator ? args.inflator : 1);
  }

  min_val = args['min_' + namespace] || min_val;
  max_val = args['max_' + namespace] || max_val;
  // if there's a single data point, we should custom-set the min and max values.
  if (min_val === max_val && args['min_' + namespace] === undefined &&
      args['max_' + namespace] === undefined) {
    if (mg_is_date(min_val)) {
      max_val = new Date(MG.clone(min_val).setDate(min_val.getDate() + 1));
      min_val = new Date(MG.clone(min_val).setDate(min_val.getDate() - 1));
    } else if (typeof min_val === 'number') {
      min_val = min_val - 1;
      max_val = min_val + 1;
      mg_force_xax_count_to_be_two(args);
    }
  }

  args.processed['min_' + namespace] = min_val;
  args.processed['max_' + namespace] = max_val;

  MG.call_hook('x_axis.process_min_max', args, args.processed.min_x, args.processed.max_x);
  MG.call_hook('y_axis.process_min_max', args, args.processed.min_y, args.processed.max_y);
}

function mg_categorical_group_color_scale(args) {
  if (args.color_accessor !== false) {
    if (args.ygroup_accessor) {
      // add a custom accessor element.
      if (args.color_accessor === null) {
        args.color_accessor = args.y_accessor;
      } else {}
    }
    if (args.color_accessor !== null) {
      new MG.scale_factory(args)
        .namespace('color')
        .categoricalDomainFromData()
        .categoricalColorRange();
    }
  }
}

function mg_add_color_categorical_scale(args, domain, accessor) {
  args.scales.color = d3.scaleOrdinal(d3.schemeCategory20).domain(domain);
  args.scalefns.color = function(d) {
    return args.scales.color(d[accessor]);
  };
}

function mg_get_categorical_domain(data, accessor) {
  return d3.set(data.map(function(d) {
      return d[accessor]; }))
    .values();
}

function mg_get_color_domain(args) {
  var color_domain;
  if (args.color_domain === null) {
    if (args.color_type === 'number') {
      color_domain = d3.extent(args.data[0], function(d) {
        return d[args.color_accessor]; });
    } else if (args.color_type === 'category') {
      color_domain = mg_get_categorical_domain(args.data[0], args.color_accessor);

    }
  } else {
    color_domain = args.color_domain;
  }
  return color_domain;
}

function mg_get_color_range(args) {
  var color_range;
  if (args.color_range === null) {
    if (args.color_type === 'number') {
      color_range = ['blue', 'red'];
    } else {
      color_range = null;
    }
  } else {
    color_range = args.color_range;
  }
  return color_range;
}
<|endoftext|>


<commit_before>/**
 * Likes YouTube videos
 */
const selectors = {
  likeButton: [
    '#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(1) yt-icon-button',
  ],
  dislikeButton: [
    '#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(2) yt-icon-button',
  ],
  subscribeButton: ['#subscribe-button tp-yt-paper-button'],
};

export default class Liker {
  /**
   * @param {Object} options
   */
  constructor({ options, log }) {
    this.options = options;
    this.log = log ? log : () => {};
    this.cache = {};
    this.start = this.start.bind(this);

    // Bail if we don't need to do anything
    // DEPRECATION: options.like_what = 'none' removed in 2.0.2. Replaced with options.disabled
    if (this.options.disabled || this.options.like_what === 'none') {
      this.log('liker is disabled');
      return this.pause();
    }

    /*
    We're hooking into YouTube's custom events to determine when the page changes.
     */
    document
      .querySelector('ytd-app')
      .addEventListener('yt-page-data-updated', this.start);

    this.start();
  }

  /**
   * Just helpful for debugging at the moment
   */
  pause() {
    this.log('paused');
    if (typeof this.onPause === 'function') {
      this.onPause();
    }
  }

  /**
   * Clears data for another round of slick liking action
   */
  reset() {
    this.cache = {};
  }

  /**
   * Detects when like/dislike buttons have loaded (so we can press them)
   */
  waitForButtons() {
    this.log('waiting for buttons...');

    return new Promise((resolve) => {
      const interval = setInterval(() => {
        const likeButton = document.querySelectorAll(selectors.likeButton)[0];
        const dislikeButton = document.querySelectorAll(
          selectors.dislikeButton
        )[0];
        // Make sure both buttons exist
        if (likeButton && dislikeButton) {
          // Store buttons
          this.cache.likeButton = likeButton;
          this.cache.dislikeButton = dislikeButton;

          this.log('...buttons ready');
          clearInterval(interval);
          resolve();
        }
      }, 1000);
    });
  }

  /**
   * Detects when the video player has loaded
   */
  waitForVideo() {
    this.log('waiting for video...');

    return new Promise((resolve) => {
      const interval = setInterval(() => {
        this.cache.video = document.querySelector('.video-stream');
        // Does the video exist?
        if (this.cache.video) {
          this.log('...video ready');
          clearInterval(interval);
          resolve();
        }
      }, 1000);
    });
  }

  /**
   * @return {Boolean} True if the like or dislike button is active
   */
  isVideoRated() {
    return (
      (this.cache.likeButton.classList.contains('style-default-active') &&
        !this.cache.likeButton.classList.contains('size-default')) ||
      this.cache.dislikeButton.classList.contains('style-default-active')
    );
  }

  /**
   * @return {Boolean} True if the user is subscribed to
   *                   the current video's channel
   */
  isUserSubscribed() {
    // Select the sub button
    const subscribeButton =
      this.cache.subscribeButton ||
      document.querySelectorAll(selectors.subscribeButton)[0];
    // Does the button exist?
    if (!subscribeButton) return false;
    // Is the button active?
    if (subscribeButton.hasAttribute('subscribed')) {
      this.cache.subscribeButton = subscribeButton;
      return true;
    }
    // TODO: If not, let's reinitialize the Liker if the user subscribes
    // else if (this.options.like_what === 'subscribed') {
    //   subButton.addEventListener('click', e => {
    //     e.target.removeEventListener(e.type, arguments.callee);
    //     this.init();
    //   });
    // }
    return false;
  }

  isAdPlaying() {
    return (
      this.cache.video &&
      ['ad-showing', 'ad-interrupting'].every((c) => {
        return this.cache.video
          .closest('.html5-video-player')
          .classList.contains(c);
      })
    );
  }

  /**
   * Make sure we can & should like the video,
   * then clickity click the button
   */
  async clickLike() {
    await this.waitForButtons();
    /*
    If the video is already liked/disliked
    or the user isn't subscribed to this channel,
    then we don't need to do anything.
     */
    if (this.isVideoRated()) {
      this.log('video already rated');
      return this.pause();
    }
    if (this.options.like_what === 'subscribed' && !this.isUserSubscribed()) {
      this.log('user not subscribed');
      return this.pause();
    }

    this.cache.likeButton.click();
    this.log('like button clicked');
    this.pause();
  }

  /**
   * Starts the liking magic.
   * The liker won't do anything unless this method is called.
   */
  async start() {
    this.log('liker started');
    this.cache = {};

    switch (this.options.like_when) {
      case 'timed': {
        const minutes = parseFloat(this.options.like_when_minutes);
        await this.waitForVideo();
        const { video } = this.cache;
        const onVideoTimeUpdate = (e) => {
          if (this.isAdPlaying()) return;
          // Are we more than the chosen mins in or at the end of the video?
          if (
            video.currentTime >= minutes * 60 ||
            video.currentTime >= video.duration
          ) {
            this.clickLike();
            video.removeEventListener('timeupdate', onVideoTimeUpdate);
          }
        };
        video.addEventListener('timeupdate', onVideoTimeUpdate);
        break;
      }

      case 'percent': {
        const percent = parseFloat(this.options.like_when_percent) / 100;
        await this.waitForVideo();
        const { video } = this.cache;
        const onVideoTimeUpdate = (e) => {
          if (this.isAdPlaying()) return;
          // Are we more than the chosen percent through the video?
          if (video.currentTime / video.duration >= percent) {
            this.clickLike();
            video.removeEventListener('timeupdate', onVideoTimeUpdate);
          }
        };
        video.addEventListener('timeupdate', onVideoTimeUpdate);
        break;
      }

      default:
        this.clickLike();
    }
  }
}
<commit_msg>Update selectors & rated logic for new YT markup<commit_after>/**
 * Likes YouTube videos
 */
const selectors = {
  likeButton: [
    '#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(1) yt-icon-button',
    '#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(1) button',
  ],
  dislikeButton: [
    '#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(2) yt-icon-button',
    '#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(2) button',
  ],
  subscribeButton: ['#subscribe-button tp-yt-paper-button'],
};

export default class Liker {
  /**
   * @param {Object} options
   */
  constructor({ options, log }) {
    this.options = options;
    this.log = log ? log : () => {};
    this.cache = {};
    this.start = this.start.bind(this);

    // Bail if we don't need to do anything
    // DEPRECATION: options.like_what = 'none' removed in 2.0.2. Replaced with options.disabled
    if (this.options.disabled || this.options.like_what === 'none') {
      this.log('liker is disabled');
      return this.pause();
    }

    /*
    We're hooking into YouTube's custom events to determine when the page changes.
     */
    document
      .querySelector('ytd-app')
      .addEventListener('yt-page-data-updated', this.start);

    this.start();
  }

  /**
   * Just helpful for debugging at the moment
   */
  pause() {
    this.log('paused');
    if (typeof this.onPause === 'function') {
      this.onPause();
    }
  }

  /**
   * Clears data for another round of slick liking action
   */
  reset() {
    this.cache = {};
  }

  /**
   * Detects when like/dislike buttons have loaded (so we can press them)
   */
  waitForButtons() {
    this.log('waiting for buttons...');

    return new Promise((resolve) => {
      const interval = setInterval(() => {
        const likeButton = document.querySelectorAll(selectors.likeButton)[0];
        const dislikeButton = document.querySelectorAll(
          selectors.dislikeButton
        )[0];
        // Make sure both buttons exist
        if (likeButton && dislikeButton) {
          // Store buttons
          this.cache.likeButton = likeButton;
          this.cache.dislikeButton = dislikeButton;

          this.log('...buttons ready');
          clearInterval(interval);
          resolve();
        }
      }, 1000);
    });
  }

  /**
   * Detects when the video player has loaded
   */
  waitForVideo() {
    this.log('waiting for video...');

    return new Promise((resolve) => {
      const interval = setInterval(() => {
        this.cache.video = document.querySelector('.video-stream');
        // Does the video exist?
        if (this.cache.video) {
          this.log('...video ready');
          clearInterval(interval);
          resolve();
        }
      }, 1000);
    });
  }

  /**
   * @return {Boolean} True if the like or dislike button is active
   */
  isVideoRated() {
    return (
      (this.cache.likeButton.classList.contains('style-default-active') &&
        !this.cache.likeButton.classList.contains('size-default')) ||
      this.cache.dislikeButton.classList.contains('style-default-active') ||
      this.cache.likeButton.getAttribute('aria-pressed') === 'true' ||
      this.cache.dislikeButton.getAttribute('aria-pressed') === 'true'
    );
  }

  /**
   * @return {Boolean} True if the user is subscribed to
   *                   the current video's channel
   */
  isUserSubscribed() {
    // Select the sub button
    const subscribeButton =
      this.cache.subscribeButton ||
      document.querySelectorAll(selectors.subscribeButton)[0];
    // Does the button exist?
    if (!subscribeButton) return false;
    // Is the button active?
    if (subscribeButton.hasAttribute('subscribed')) {
      this.cache.subscribeButton = subscribeButton;
      return true;
    }
    // TODO: If not, let's reinitialize the Liker if the user subscribes
    // else if (this.options.like_what === 'subscribed') {
    //   subButton.addEventListener('click', e => {
    //     e.target.removeEventListener(e.type, arguments.callee);
    //     this.init();
    //   });
    // }
    return false;
  }

  isAdPlaying() {
    return (
      this.cache.video &&
      ['ad-showing', 'ad-interrupting'].every((c) => {
        return this.cache.video
          .closest('.html5-video-player')
          .classList.contains(c);
      })
    );
  }

  /**
   * Make sure we can & should like the video,
   * then clickity click the button
   */
  async clickLike() {
    await this.waitForButtons();
    /*
    If the video is already liked/disliked
    or the user isn't subscribed to this channel,
    then we don't need to do anything.
     */
    if (this.isVideoRated()) {
      this.log('video already rated');
      return this.pause();
    }
    if (this.options.like_what === 'subscribed' && !this.isUserSubscribed()) {
      this.log('user not subscribed');
      return this.pause();
    }

    this.cache.likeButton.click();
    this.log('like button clicked');
    this.pause();
  }

  /**
   * Starts the liking magic.
   * The liker won't do anything unless this method is called.
   */
  async start() {
    this.log('liker started');
    this.cache = {};

    switch (this.options.like_when) {
      case 'timed': {
        const minutes = parseFloat(this.options.like_when_minutes);
        await this.waitForVideo();
        const { video } = this.cache;
        const onVideoTimeUpdate = (e) => {
          if (this.isAdPlaying()) return;
          // Are we more than the chosen mins in or at the end of the video?
          if (
            video.currentTime >= minutes * 60 ||
            video.currentTime >= video.duration
          ) {
            this.clickLike();
            video.removeEventListener('timeupdate', onVideoTimeUpdate);
          }
        };
        video.addEventListener('timeupdate', onVideoTimeUpdate);
        break;
      }

      case 'percent': {
        const percent = parseFloat(this.options.like_when_percent) / 100;
        await this.waitForVideo();
        const { video } = this.cache;
        const onVideoTimeUpdate = (e) => {
          if (this.isAdPlaying()) return;
          // Are we more than the chosen percent through the video?
          if (video.currentTime / video.duration >= percent) {
            this.clickLike();
            video.removeEventListener('timeupdate', onVideoTimeUpdate);
          }
        };
        video.addEventListener('timeupdate', onVideoTimeUpdate);
        break;
      }

      default:
        this.clickLike();
    }
  }
}
<|endoftext|>


<commit_before>'use strict'

class ElasticSlider {
    constructor(el, options) {
        this.slider = el;
        this.options = options;
        this.slidePromise = null;
        this.elementList = {};
        this.elementList.containerEl = this.slider.querySelector(`.ElasticSlider-container`);
        this.elementList.slideArr = this.elementList.containerEl.children;
        this.elementList.slideActiveEl = this.elementList.slideArr[options.activeSlide - 1];
        this.slideActiveIndex = options.activeSlide - 1;
        this._slideCount = this.elementList.slideArr.length;
        this.elementList.cloneEl = null;

        // Add classes
        // ====================================================================
        this.slider.classList.add('ElasticSlider');

        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var itemEl = this.elementList.slideArr[i]

            itemEl.classList.add('ElasticSlider-item');
        }

        this._setActiveSlide(this.slideActiveIndex);

        this.animateHash = {
            fade: function(self, index, cb) {
                // return function(this, index, cb) {
                    self.elementList.slideArr[index];
                    self.slideActiveIndex = index;
                    self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeStart');

                    // Defer to force css transition onto start class
                    window.setTimeout(function() {
                        self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeEnd');
                    }, 0);

                    window.setTimeout(function() {
                        if (typeof cb === 'function') cb(self, index);
                    }, 100)
            }
        }
    }

    destroy() {

    }

    startSlide(index, animateType) {
        // Index gets moved up one due to clone element
        this._createTransitionEl(index);

        // Handle odd index values
        if (index === 'next') index = this.slideActiveIndex + 1;
        if (index === 'prev') index = this.slideActiveIndex - 1;

        if (typeof index === 'undefined' || index > this._slideCount) {
            index = 0;
        } else if (index < 0) {
            index = this._slideCount;
        };

        if (animateType) {
            this.animateHash[animateType](this, index + 1, function(self, index){
                self.endSlide(index);
            })
        } else {
            this.endSlide(index);
        }
    }

    endSlide(index) {
        this._setActiveSlide(index);

        // Remove clone
        this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        this.elementList.cloneEl = null;
    }

    _setActiveSlide(index) {
        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var slide = this.elementList.slideArr[i];

            slide.classList.remove('ElasticSlider-item--isActive');
        }

        this.elementList.slideArr[index].classList.add('ElasticSlider-item--isActive');
        this.slideActiveIndex = index;
    }

    _createTransitionEl(index) {
        if (this.elementList.cloneEl) {
            this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        }
        this.elementList.cloneEl = this.elementList.slideArr[index].cloneNode(true);
        this.elementList.cloneEl.classList.add('ElasticSlider-item--clone')

        this.elementList.containerEl.insertBefore(this.elementList.cloneEl, this.elementList.slideArr[0]);
    }
}
<commit_msg>Reformat<commit_after>'use strict'

class ElasticSlider {
    constructor(el, options) {
        this.slider = el;
        this.options = options;
        this.slidePromise = null;
        this.elementList = {};
        this.elementList.containerEl = this.slider.querySelector(`.ElasticSlider-container`);
        this.elementList.slideArr = this.elementList.containerEl.children;
        this.elementList.slideActiveEl = this.elementList.slideArr[options.activeSlide - 1];
        this.slideActiveIndex = options.activeSlide - 1;
        this._slideCount = this.elementList.slideArr.length;
        this.elementList.cloneEl = null;

        // Add classes
        // ====================================================================
        this.slider.classList.add('ElasticSlider');

        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var itemEl = this.elementList.slideArr[i]

            itemEl.classList.add('ElasticSlider-item');
        }

        this._setActiveSlide(this.slideActiveIndex);

        this.animateHash = {
            fade: function(self, index, cb) {
                self.elementList.slideArr[index];
                self.slideActiveIndex = index;
                self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeStart');

                // Defer to force css transition onto start class
                window.setTimeout(function() {
                    self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeEnd');
                }, 0);

                window.setTimeout(function() {
                    if (typeof cb === 'function') cb(self, index);
                }, 100)
            }
        }
    }

    destroy() {

    }

    startSlide(index, animateType) {
        // Index gets moved up one due to clone element
        this._createTransitionEl(index);

        // Handle odd index values
        if (index === 'next') index = this.slideActiveIndex + 1;
        if (index === 'prev') index = this.slideActiveIndex - 1;

        if (typeof index === 'undefined' || index > this._slideCount) {
            index = 0;
        } else if (index < 0) {
            index = this._slideCount;
        };

        if (animateType) {
            this.animateHash[animateType](this, index + 1, function(self, index){
                self.endSlide(index);
            })
        } else {
            this.endSlide(index);
        }
    }

    endSlide(index) {
        this._setActiveSlide(index);

        // Remove clone
        this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        this.elementList.cloneEl = null;
    }

    _setActiveSlide(index) {
        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var slide = this.elementList.slideArr[i];

            slide.classList.remove('ElasticSlider-item--isActive');
        }

        this.elementList.slideArr[index].classList.add('ElasticSlider-item--isActive');
        this.slideActiveIndex = index;
    }

    _createTransitionEl(index) {
        if (this.elementList.cloneEl) {
            this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        }

        this.elementList.cloneEl = this.elementList.slideArr[index].cloneNode(true);
        this.elementList.cloneEl.classList.add('ElasticSlider-item--clone')

        this.elementList.containerEl.insertBefore(this.elementList.cloneEl, this.elementList.slideArr[0]);
    }
}
<|endoftext|>


<commit_before>/*===============================================================================
************   Store and parse forms data   ************
===============================================================================*/
app.formsData = {};
app.formStoreData = function (formId, formJSON) {
    // Store form data in app.formsData
    app.formsData[formId] = formJSON;

    // Store form data in local storage also
    app.ls['f7form-' + formId] = JSON.stringify(formJSON);
};
app.formDeleteData = function (formId) {
    // Delete form data from app.formsData
    if (app.formsData[formId]) {
        app.formsData[formId] = '';
        delete app.formsData[formId];
    }

    // Delete form data from local storage also
    if (app.ls['f7form-' + formId]) {
        app.ls['f7form-' + formId] = '';
        app.ls.removeItem('f7form-' + formId);
    }
};
app.formGetData = function (formId) {
    // First of all check in local storage
    if (app.ls['f7form-' + formId]) {
        return JSON.parse(app.ls['f7form-' + formId]);
    }
    // Try to get it from formsData obj
    else if (app.formsData[formId]) return app.formsData[formId];
};
app.formToJSON = function (form) {
    form = $(form);
    if (form.length !== 1) return false;

    // Form data
    var formData = {};

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];
    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.attr('multiple')) {
            skipNames.push(name);
            formData[name] = [];
            form.find('select[name="' + name + '"] option').each(function () {
                if (this.selected) formData[name].push(this.value);
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    formData[name] = [];
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name].push(this.value);
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name] = this.value;
                    });
                    break;
                default :
                    formData[name] = input.val();
                    break;
            }
        }

    });
    form.trigger('formToJSON', {formData: formData});

    return formData;
};
app.formFromJSON = function (form, formData) {
    form = $(form);
    if (form.length !== 1) return false;

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];

    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (!formData[name]) return;
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.attr('multiple')) {
            skipNames.push(name);
            form.find('select[name="' + name + '"] option').each(function () {
                if (formData[name].indexOf(this.value) >= 0) this.selected = true;
                else this.selected = false;
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name].indexOf(this.value) >= 0) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name] === this.value) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                default :
                    input.val(formData[name]);
                    break;
            }
        }

    });
    form.trigger('formFromJSON', {formData: formData});
};
app.initFormsStorage = function (pageContainer) {
    pageContainer = $(pageContainer);
    if (pageContainer.length === 0) return;

    var forms = pageContainer.find('form.store-data');
    if (forms.length === 0) return;

    // Parse forms data and fill form if there is such data
    forms.each(function () {
        var id = this.getAttribute('id');
        if (!id) return;
        var formData = app.formGetData(id);
        if (formData) app.formFromJSON(this, formData);
    });
    // Update forms data on inputs change
    function storeForm() {
        /*jshint validthis:true */
        var form = $(this);
        var formId = form[0].id;
        if (!formId) return;
        var formJSON = app.formToJSON(form);
        if (!formJSON) return;
        app.formStoreData(formId, formJSON);
        form.trigger('store', {data: formJSON});
    }
    forms.on('change submit', storeForm);

    // Detach Listeners
    function pageBeforeRemove() {
        forms.off('change submit', storeForm);
        pageContainer.off('pageBeforeRemove', pageBeforeRemove);
    }
    pageContainer.on('pageBeforeRemove', pageBeforeRemove);
};

// Ajax submit on forms
$(document).on('submit change', 'form.ajax-submit, form.ajax-submit-onchange', function (e) {
    var form = $(this);
    if (e.type === 'change' && !form.hasClass('ajax-submit-onchange')) return;
    if (e.type === 'submit') e.preventDefault();

    var method = form.attr('method') || 'GET';
    var contentType = form.prop('enctype');

    var url = form.attr('action');
    if (!url) return;

    var data;
    if (method === 'POST') data = new FormData(form[0]);
    else data = $.serializeObject(app.formToJSON(form[0]));

    var xhr = $.ajax({
        method: method,
        url: url,
        contentType: contentType,
        data: data,
        beforeSend: function (xhr) {
            form.trigger('beforeSubmit', {data:data, xhr: xhr});
        },
        error: function (xhr) {
            form.trigger('submitError', {data:data, xhr: xhr});
        },
        success: function (data) {
            form.trigger('submitted', {data: data, xhr: xhr});
        }
    });
});

<commit_msg>Add also check for attr<commit_after>/*===============================================================================
************   Store and parse forms data   ************
===============================================================================*/
app.formsData = {};
app.formStoreData = function (formId, formJSON) {
    // Store form data in app.formsData
    app.formsData[formId] = formJSON;

    // Store form data in local storage also
    app.ls['f7form-' + formId] = JSON.stringify(formJSON);
};
app.formDeleteData = function (formId) {
    // Delete form data from app.formsData
    if (app.formsData[formId]) {
        app.formsData[formId] = '';
        delete app.formsData[formId];
    }

    // Delete form data from local storage also
    if (app.ls['f7form-' + formId]) {
        app.ls['f7form-' + formId] = '';
        app.ls.removeItem('f7form-' + formId);
    }
};
app.formGetData = function (formId) {
    // First of all check in local storage
    if (app.ls['f7form-' + formId]) {
        return JSON.parse(app.ls['f7form-' + formId]);
    }
    // Try to get it from formsData obj
    else if (app.formsData[formId]) return app.formsData[formId];
};
app.formToJSON = function (form) {
    form = $(form);
    if (form.length !== 1) return false;

    // Form data
    var formData = {};

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];
    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.attr('multiple')) {
            skipNames.push(name);
            formData[name] = [];
            form.find('select[name="' + name + '"] option').each(function () {
                if (this.selected) formData[name].push(this.value);
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    formData[name] = [];
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name].push(this.value);
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name] = this.value;
                    });
                    break;
                default :
                    formData[name] = input.val();
                    break;
            }
        }

    });
    form.trigger('formToJSON', {formData: formData});

    return formData;
};
app.formFromJSON = function (form, formData) {
    form = $(form);
    if (form.length !== 1) return false;

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];

    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (!formData[name]) return;
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.attr('multiple')) {
            skipNames.push(name);
            form.find('select[name="' + name + '"] option').each(function () {
                if (formData[name].indexOf(this.value) >= 0) this.selected = true;
                else this.selected = false;
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name].indexOf(this.value) >= 0) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name] === this.value) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                default :
                    input.val(formData[name]);
                    break;
            }
        }

    });
    form.trigger('formFromJSON', {formData: formData});
};
app.initFormsStorage = function (pageContainer) {
    pageContainer = $(pageContainer);
    if (pageContainer.length === 0) return;

    var forms = pageContainer.find('form.store-data');
    if (forms.length === 0) return;

    // Parse forms data and fill form if there is such data
    forms.each(function () {
        var id = this.getAttribute('id');
        if (!id) return;
        var formData = app.formGetData(id);
        if (formData) app.formFromJSON(this, formData);
    });
    // Update forms data on inputs change
    function storeForm() {
        /*jshint validthis:true */
        var form = $(this);
        var formId = form[0].id;
        if (!formId) return;
        var formJSON = app.formToJSON(form);
        if (!formJSON) return;
        app.formStoreData(formId, formJSON);
        form.trigger('store', {data: formJSON});
    }
    forms.on('change submit', storeForm);

    // Detach Listeners
    function pageBeforeRemove() {
        forms.off('change submit', storeForm);
        pageContainer.off('pageBeforeRemove', pageBeforeRemove);
    }
    pageContainer.on('pageBeforeRemove', pageBeforeRemove);
};

// Ajax submit on forms
$(document).on('submit change', 'form.ajax-submit, form.ajax-submit-onchange', function (e) {
    var form = $(this);
    if (e.type === 'change' && !form.hasClass('ajax-submit-onchange')) return;
    if (e.type === 'submit') e.preventDefault();

    var method = form.attr('method') || 'GET';
    var contentType = form.prop('enctype') || form.attr('enctype');

    var url = form.attr('action');
    if (!url) return;

    var data;
    if (method === 'POST') data = new FormData(form[0]);
    else data = $.serializeObject(app.formToJSON(form[0]));

    var xhr = $.ajax({
        method: method,
        url: url,
        contentType: contentType,
        data: data,
        beforeSend: function (xhr) {
            form.trigger('beforeSubmit', {data:data, xhr: xhr});
        },
        error: function (xhr) {
            form.trigger('submitError', {data:data, xhr: xhr});
        },
        success: function (data) {
            form.trigger('submitted', {data: data, xhr: xhr});
        }
    });
});

<|endoftext|>