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

    var defaultOptions = {
        title: {
            "text": null
        },
        xAxis: {
            type: 'datetime'
        },
        yAxis: {
            title: {
                text: null
            }
        },
        tooltip: {
            valueDecimals: 2,
            formatter: function () {
                if (!this.points) {
                    this.points = [this.point];
                };

                if (moment.isMoment(this.x)) {
                    var s = '' + moment(this.x).format("DD/MM/YY HH:mm") + '',
                        pointsCount = this.points.length;

                    $.each(this.points, function (i, point) {
                        s += '
' + point.series.name + ': ' +
                            Highcharts.numberFormat(point.y);

                        if (pointsCount > 1 && point.percentage) {
                            s += " (" + Highcharts.numberFormat(point.percentage) + "%)";
                        }
                    });
                } else {
                    var s = "" + this.points[0].key + "";
                    $.each(this.points, function (i, point) {
                        s += '
' + point.series.name + ': ' +
                            Highcharts.numberFormat(point.y);
                    });
                }

                return s;
            },
            shared: true
        },
        exporting: {
            chartOptions: {
                title: {
                    text: ''
                }
            },
            buttons: {
                contextButton: {
                    menuItems: [
                        {
                            text: 'Toggle % Stacking',
                            onclick: function () {
                                var newStacking = "normal";
                                if (this.series[0].options.stacking == "normal") {
                                    newStacking = "percent";
                                }

                                _.each(this.series, function (series) {
                                    series.update({stacking: newStacking}, true);
                                });
                            }
                        }
                    ]
                }
            }
        },
        credits: {
            enabled: false
        },
        plotOptions: {
            area: {
                marker: {
                    enabled: false,
                    symbol: 'circle',
                    radius: 2,
                    states: {
                        hover: {
                            enabled: true
                        }
                    }
                }
            },
            column: {
                stacking: "normal",
                pointPadding: 0,
                borderWidth: 1,
                groupPadding: 0,
                shadow: false
            },
            line: {
                marker: {
                    radius: 3,
                },
                lineWidth: 1,
                states: {
                    hover: {
                        lineWidth: 2
                    }
                }
            },
            scatter: {
                marker: {
                    radius: 5,
                    states: {
                        hover: {
                            enabled: true,
                            lineColor: 'rgb(100,100,100)'
                        }
                    }
                },
                tooltip: {
                    headerFormat: '{series.name}
',
                    pointFormat: '{point.x}, {point.y}'
                }
            }
        },
        series: []
    };

    angular.module('highchart', [])
        .directive('chart', ['$timeout', function ($timeout) {
            return {
                restrict: 'E',
                template: '

',
                scope: {
                    options: "=options",
                    series: "=series"
                },
                transclude: true,
                replace: true,

                link: function (scope, element, attrs) {
                    var chartsDefaults = {
                        chart: {
                            renderTo: element[0],
                            type: attrs.type || null,
                            height: attrs.height || null,
                            width: attrs.width || null
                        }
                    };

                    var chartOptions = $.extend(true, {}, defaultOptions, chartsDefaults);

                    // Update when options change
                    scope.$watch('options', function (newOptions) {
                        initChart(newOptions);
                    }, true);

                    //Update when charts data changes
                    scope.$watch(function () {
                        return (scope.series && scope.series.length) || 0;
                    }, function (length) {
                        if (!length || length == 0) {
                            scope.chart.showLoading();
                        } else {
                            drawChart();
                        }
                        ;
                    }, true);

                    function initChart(options) {
                        if (scope.chart) {
                            scope.chart.destroy();
                        }

                        $.extend(true, chartOptions, options);

                        scope.chart = new Highcharts.Chart(chartOptions);
                        drawChart();
                    }

                    function drawChart() {
                        while (scope.chart.series.length > 0) {
                            scope.chart.series[0].remove(true);
                        }

                        // todo series.type

                        if (_.some(scope.series[0].data, function (p) {
                            return angular.isString(p.x)
                        })) {
                            scope.chart.xAxis[0].update({type: 'category'});

                            // We need to make sure that for each category, each series has a value.
                            var categories = _.union.apply(this, _.map(scope.series, function (s) {
                                return _.pluck(s.data, 'x')
                            }));

                            _.each(scope.series, function (s) {
                                // TODO: move this logic to Query#getChartData
                                var yValues = _.groupBy(s.data, 'x');

                                var newData = _.sortBy(_.map(categories, function (category) {
                                    return {
                                        name: category,
                                        y: yValues[category] && yValues[category][0].y
                                    }
                                }), 'name');

                                s.data = newData;
                            });
                        } else {
                            scope.chart.xAxis[0].update({type: 'datetime'});
                        }

                        scope.chart.counters.color = 0;

                        _.each(scope.series, function (s) {
                            // here we override the series with the visualization config
                            var _s = $.extend(true, {}, s, chartOptions['series']);

                            if (_s.type == 'area') {
                                _.each(_s.data, function (p) {
                                    // This is an insane hack: somewhere deep in HighChart's code,
                                    // when you stack areas, it tries to convert the string representation
                                    // of point's x into a number. With the default implementation of toString
                                    // it fails....

                                    if (moment.isMoment(p.x)) {
                                        p.x.toString = function () {
                                            return String(this.toDate().getTime());
                                        };
                                    }
                                });
                            };

                            scope.chart.addSeries(_s);
                        });

                        scope.chart.redraw();
                        scope.chart.hideLoading();
                    }

                }
            };

        }]);
})();<commit_msg>Performance improvements for chart rendering:<commit_after>(function () {
    'use strict';

    var defaultOptions = {
        title: {
            "text": null
        },
        xAxis: {
            type: 'datetime'
        },
        yAxis: {
            title: {
                text: null
            }
        },
        tooltip: {
            valueDecimals: 2,
            formatter: function () {
                if (!this.points) {
                    this.points = [this.point];
                };

                if (moment.isMoment(this.x)) {
                    var s = '' + moment(this.x).format("DD/MM/YY HH:mm") + '',
                        pointsCount = this.points.length;

                    $.each(this.points, function (i, point) {
                        s += '
' + point.series.name + ': ' +
                            Highcharts.numberFormat(point.y);

                        if (pointsCount > 1 && point.percentage) {
                            s += " (" + Highcharts.numberFormat(point.percentage) + "%)";
                        }
                    });
                } else {
                    var s = "" + this.points[0].key + "";
                    $.each(this.points, function (i, point) {
                        s += '
' + point.series.name + ': ' +
                            Highcharts.numberFormat(point.y);
                    });
                }

                return s;
            },
            shared: true
        },
        exporting: {
            chartOptions: {
                title: {
                    text: ''
                }
            },
            buttons: {
                contextButton: {
                    menuItems: [
                        {
                            text: 'Toggle % Stacking',
                            onclick: function () {
                                var newStacking = "normal";
                                if (this.series[0].options.stacking == "normal") {
                                    newStacking = "percent";
                                }

                                _.each(this.series, function (series) {
                                    series.update({stacking: newStacking}, true);
                                });
                            }
                        }
                    ]
                }
            }
        },
        credits: {
            enabled: false
        },
        plotOptions: {
            area: {
                marker: {
                    enabled: false,
                    symbol: 'circle',
                    radius: 2,
                    states: {
                        hover: {
                            enabled: true
                        }
                    }
                }
            },
            column: {
                stacking: "normal",
                pointPadding: 0,
                borderWidth: 1,
                groupPadding: 0,
                shadow: false
            },
            line: {
                marker: {
                    radius: 3,
                },
                lineWidth: 1,
                states: {
                    hover: {
                        lineWidth: 2
                    }
                }
            },
            scatter: {
                marker: {
                    radius: 5,
                    states: {
                        hover: {
                            enabled: true,
                            lineColor: 'rgb(100,100,100)'
                        }
                    }
                },
                tooltip: {
                    headerFormat: '{series.name}
',
                    pointFormat: '{point.x}, {point.y}'
                }
            }
        },
        series: []
    };

    angular.module('highchart', [])
        .directive('chart', ['$timeout', function ($timeout) {
            return {
                restrict: 'E',
                template: '

',
                scope: {
                    options: "=options",
                    series: "=series"
                },
                transclude: true,
                replace: true,

                link: function (scope, element, attrs) {
                    var chartsDefaults = {
                        chart: {
                            renderTo: element[0],
                            type: attrs.type || null,
                            height: attrs.height || null,
                            width: attrs.width || null
                        }
                    };

                    var chartOptions = $.extend(true, {}, defaultOptions, chartsDefaults);

                    // $timeout makes sure that this function invoked after the DOM ready. When draw/init
                    // invoked after the DOM is ready, we see first an empty HighCharts objects and later
                    // they get filled up. Which gives the feeling that the charts loading faster (otherwise
                    // we stare at an empty screen until the HighCharts object is ready).
                    $timeout(function(){
                        // Update when options change
                        scope.$watch('options', function (newOptions) {
                            initChart(newOptions);
                        }, true);

                        //Update when charts data changes
                        scope.$watch(function () {
                            // TODO: this might be an issue in case the series change, but they stay
                            // with the same length
                            return (scope.series && scope.series.length) || 0;
                        }, function (length) {
                            if (!length || length == 0) {
                                scope.chart.showLoading();
                            } else {
                                drawChart();
                            };
                        }, true);
                    });

                    function initChart(options) {
                        if (scope.chart) {
                            scope.chart.destroy();
                        };

                        $.extend(true, chartOptions, options);

                        scope.chart = new Highcharts.Chart(chartOptions);
                        drawChart();
                    }

                    function drawChart() {
                        while (scope.chart.series.length > 0) {
                            scope.chart.series[0].remove(false);
                        };

                        if (_.some(scope.series[0].data, function (p) {
                            return angular.isString(p.x)
                        })) {
                            scope.chart.xAxis[0].update({type: 'category'});

                            // We need to make sure that for each category, each series has a value.
                            var categories = _.union.apply(this, _.map(scope.series, function (s) {
                                return _.pluck(s.data, 'x')
                            }));

                            _.each(scope.series, function (s) {
                                // TODO: move this logic to Query#getChartData
                                var yValues = _.groupBy(s.data, 'x');

                                var newData = _.sortBy(_.map(categories, function (category) {
                                    return {
                                        name: category,
                                        y: yValues[category] && yValues[category][0].y
                                    }
                                }), 'name');

                                s.data = newData;
                            });
                        } else {
                            scope.chart.xAxis[0].update({type: 'datetime'});
                        }

                        scope.chart.counters.color = 0;

                        _.each(scope.series, function (s) {
                            // here we override the series with the visualization config
                            s = _.extend(s, chartOptions['series']);

                            if (s.type == 'area') {
                                _.each(s.data, function (p) {
                                    // This is an insane hack: somewhere deep in HighChart's code,
                                    // when you stack areas, it tries to convert the string representation
                                    // of point's x into a number. With the default implementation of toString
                                    // it fails....

                                    if (moment.isMoment(p.x)) {
                                        p.x.toString = function () {
                                            return String(this.toDate().getTime());
                                        };
                                    }
                                });
                            };

                            scope.chart.addSeries(s, false);
                        });

                        scope.chart.redraw();
                        scope.chart.hideLoading();
                    }

                }
            };

        }]);
})();<|endoftext|>


<commit_before>// NOTE: Do not use any components here,
// as they won't be wrapped in the required providers.

import React from 'react';
import PropTypes from 'prop-types';
import Helmet from 'react-helmet-async';

const GOOGLE_ANALYTICS_TRACKING_TAG = `
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
`;

const Page = ({
  bundleName,
  helmet,
  content,
  state,
  styles,
  asset,
  sharifyData,
}) => (

      {helmet.title.toComponent()}
      {helmet.meta.toComponent()}
      {helmet.link.toComponent()}

      <meta name="google-site-verification" content="yEDzyeh9dYsQoRw7VJA6X5aVthUCYVTNK6nOUQU1eEE" />
      <meta name="google-site-verification" content="YlzaBIQnBQhN5JFfKeoinJXrTlfdmdtFZ6s8Ez_O8vc" />

      <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimal-ui" />
      <meta name="apple-mobile-web-app-capable" content="yes" />
      <meta name="apple-mobile-web-app-status-bar-style" content="black" />

      <link rel="apple-touch-icon" href={`${sharifyData.IMAGE_PATH}touch-icon-iphone.png`} />
      <link rel="apple-touch-icon" sizes="76x76" href={`${sharifyData.IMAGE_PATH}touch-icon-ipad.png`} />
      <link rel="apple-touch-icon" sizes="120x120" href={`${sharifyData.IMAGE_PATH}touch-icon-iphone-retina.png`} />
      <link rel="apple-touch-icon" sizes="152x152" href={`${sharifyData.IMAGE_PATH}touch-icon-ipad-retina.png`} />

      <meta name="apple-itunes-app" content="app-id=1299153149" />
      <link rel="mask-icon" href={`${sharifyData.IMAGE_PATH}arena-mark.svg" color="black`} />

      <meta name="twitter:site" content="@aredotna" />

      {styles}


<commit_before>/* eslint-disable array-callback-return */
import { LightningElement, api, track, wire } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import {
    createRecord,
    updateRecord,
    getRecord,
    getRecordCreateDefaults,
    generateRecordInputForCreate
} from 'lightning/uiRecordApi';
import { fireEvent } from 'c/pubsubNoPageRef';
import { handleError, addKeyToCollectionItems } from 'c/utilTemplateBuilder';
import {
    getNamespace,
    getNestedProperty,
    isNull,
    stripNamespace
} from 'c/utilCommon'
import GeLabelService from 'c/geLabelService';

import getAllFormTemplates from '@salesforce/apex/FORM_ServiceGiftEntry.getAllFormTemplates';
import getDonationMatchingValues from '@salesforce/apex/FORM_ServiceGiftEntry.getDonationMatchingValues';

import DATA_IMPORT_BATCH_INFO from '@salesforce/schema/DataImportBatch__c';
import DATA_IMPORT_BATCH_ID_INFO from '@salesforce/schema/DataImportBatch__c.Id';
import DATA_IMPORT_BATCH_FORM_TEMPLATE_INFO from '@salesforce/schema/DataImportBatch__c.Form_Template__c';
import DATA_IMPORT_BATCH_VERSION_INFO from '@salesforce/schema/DataImportBatch__c.Batch_Gift_Entry_Version__c';
import DATA_IMPORT_BATCH_GIFT_INFO from '@salesforce/schema/DataImportBatch__c.GiftBatch__c';
import DATA_IMPORT_BATCH_DEFAULTS_INFO from '@salesforce/schema/DataImportBatch__c.Batch_Defaults__c';
import DATA_IMPORT_MATCHING_BEHAVIOR_INFO from '@salesforce/schema/DataImportBatch__c.Donation_Matching_Behavior__c';
import DATA_IMPORT_BATCH_TABLE_COLUMNS_FIELD from '@salesforce/schema/DataImportBatch__c.Batch_Table_Columns__c';
import DATA_IMPORT_BATCH_DONATION_MATCHING_RULE from '@salesforce/schema/DataImportBatch__c.Donation_Matching_Rule__c';

const NAME = 'name';
const ID = 'id';
const MAX_STEPS = 2;
const CANCEL = 'cancel';
const COMMA_SEPARATOR = ';';

export default class geBatchWizard extends NavigationMixin(LightningElement) {

    // Expose custom labels to template
    CUSTOM_LABELS = GeLabelService.CUSTOM_LABELS;

    @api recordId;
    @api dedicatedListenerEventName;

    @track step = 0;
    @track templates;
    @track selectedBatchHeaderFields = [];
    @track formSections = [];
    @track selectedTemplateId;
    @track isLoading = true;
    @track donationMatchingBehaviors;
    @track hasInvalidBatchFields = false;
    @track missingBatchHeaderFieldLabels = [];
    @track missingRequiredFieldsMessage;

    dataImportBatchFieldInfos;
    dataImportBatchInfo;
    dataImportBatchRecord;
    templatesById = {};
    templateOptions;
    isLoaded = false;

    headers = {
        0: this.CUSTOM_LABELS.geHeaderBatchSelectTemplate,
        1: this.CUSTOM_LABELS.geHeaderBatchEnterInfo,
        2: this.CUSTOM_LABELS.geHeaderBatchSetDefaultValues
    }

    steps = {
        first: 0,
        second: 1,
        third: 2
    }

    get showBackButton() {
        if (this.step === 1 && this.isEditMode) {
            return false;
        }
        return this.step > 0 ? true : false;
    }

    get showSaveButton() {
        return this.step === 2 ? true : false;
    }

    get isNextButtonDisabled() {
        if (this.step === 0) {
            return !this.selectedTemplateId ? true : false;
        } else if (this.step === 1) {
            return false;
        }
        return false;
    }

    get header() {
        return this.headers[this.step];
    }

    get cssClassStep0() {
        return this.header === this.headers[0] ?
            'slds-p-horizontal_x-large slds-p-vertical_large slds-size_1-of-1 step-0' :
            'slds-hide';
    }

    get cssClassStep1() {
        return this.header === this.headers[1] ?
            'slds-p-horizontal_x-large slds-p-vertical_large slds-size_1-of-1' :
            'slds-hide';
    }

    get cssClassStep2() {
        return this.header === this.headers[2] ?
            'slds-p-horizontal_large slds-p-bottom_x-large slds-size_1-of-1' :
            'slds-hide';
    }

    get selectedTemplate() {
        if (this.selectedTemplateId && this.templatesById) {
            return this.templatesById[this.selectedTemplateId];
        }
        return undefined;
    }

    get isEditMode() {
        return this.recordId ? true : false;
    }

    get dataImportBatchName() {
        return getNestedProperty(DATA_IMPORT_BATCH_INFO, 'objectApiName');
    }

    /*******************************************************************************
    * @description Retrieves the DataImportBatch__c describe info.
    *
    * @param {string} dataImportBatchName: DataImportBatch__c object api name.
    */
    @wire(getObjectInfo, { objectApiName: '$dataImportBatchName' })
    wiredDataImportBatchInfo(response) {
        if (response.data) {
            this.dataImportBatchInfo = response.data;

            this.dataImportBatchFieldInfos =
                this.buildFieldDescribesForWiredMethod(
                    this.dataImportBatchInfo.fields,
                    this.dataImportBatchInfo.apiName);
        }
    }

    /*******************************************************************************
    * @description Method converts field describe info into objects that the
    * getRecord method can accept into its 'fields' parameter.
    *
    * @param {list} fields: List of field describe info.
    * @param {string} objectApiName: An SObject api name.
    */
    buildFieldDescribesForWiredMethod(fields, objectApiName) {
        return Object.keys(fields).map((fieldApiName) => {
            return {
                fieldApiName: fieldApiName,
                objectApiName: objectApiName
            }
        });
    }

    @wire(getRecord, { recordId: '$recordId', fields: '$dataImportBatchFieldInfos' })
    wiredDataImportBatchRecord(response) {
        if (response.data) {
            getAllFormTemplates()
                .then(templates => {
                    this.templates = templates;
                    this.builderTemplateComboboxOptions(this.templates);

                    this.dataImportBatchRecord = response.data;
                    let templateId = this
                        .dataImportBatchRecord
                        .fields[DATA_IMPORT_BATCH_FORM_TEMPLATE_INFO.fieldApiName]
                        .value;

                    this.handleTemplateChange({ detail: { value: templateId } });
                    this.setFormFieldsBatchLevelDefaults();

                    this.step = 1;

                    this.isLoading = false;
                })
                .catch(error => {
                    handleError(error);
                });
        }
    }

    setFormFieldsBatchLevelDefaults() {
        let batchLevelDefaults =
            JSON.parse(this.dataImportBatchRecord.fields[DATA_IMPORT_BATCH_DEFAULTS_INFO.fieldApiName].value);

        this.formSections.forEach(section => {
            if (section.elements) {
                section.elements.forEach(element => {
                    if (batchLevelDefaults[element.fieldApiName]) {
                        element.value = batchLevelDefaults[element.fieldApiName].value;
                    }
                });
            }
        });
    }

    @wire(getRecordCreateDefaults, { objectApiName: '$dataImportBatchName' })
    dataImportBatchCreateDefaults;

    setValuesForSelectedBatchHeaderFields(allFields) {
        this.selectedBatchHeaderFields.map(batchHeaderField => {
            let queriedField = allFields[batchHeaderField.apiName];
            if (queriedField) {
                batchHeaderField.value = queriedField.value;
            }
        });
    }

    async connectedCallback() {
        try {
            this.donationMatchingBehaviors = await getDonationMatchingValues();

            if (!this.recordId) {
                this.templates = await getAllFormTemplates();
                this.templates = this.templates.sort();
                this.builderTemplateComboboxOptions(this.templates);
                this.isLoading = false;
            }
        } catch (error) {
            handleError(error);
        }
    }

    builderTemplateComboboxOptions(templates) {
        if (templates && templates.length > 0) {
            this.templateOptions = this.templates.map(template => {
                this.templatesById[template[ID]] = template;
                return { label: template[NAME], value: template[ID] }
            });
        }
    }

    handleNext() {
        if (this.step === 1) {
            this.validateBatchHeaderFields();

            if (this.hasInvalidBatchFields) {
                return;
            }
        }

        if (this.step < MAX_STEPS) {
            this.step += 1;
        }
    }

    handleBack() {
        if (this.showBackButton || this.step > 0) {
            this.step -= 1;
        }
    }

    handleTemplateChange(event) {
        this.selectedTemplateId = event.detail.value;
        this.selectedBatchHeaderFields = [];

        this.selectedBatchHeaderFields = addKeyToCollectionItems(this.selectedTemplate.batchHeaderFields);
        this.formSections = this.selectedTemplate.layout.sections;
        if (this.recordId && this.dataImportBatchRecord && this.dataImportBatchRecord.fields) {
            this.setValuesForSelectedBatchHeaderFields(this.dataImportBatchRecord.fields);
        }

        this.resetValidations();
    }

    /*******************************************************************************
    * @description Method collects all batch header fields and checks for their
    * validity.
    */
    validateBatchHeaderFields() {
        this.resetValidations();

        let inputComponents = this.template.querySelectorAll('c-util-input[data-id="batchHeaderField"]');
        for (let i = 0; i < inputComponents.length; i++) {
            if (!inputComponents[i].isValid()) {
                this.hasInvalidBatchFields = true;
                this.missingBatchHeaderFieldLabels =
                    [...this.missingBatchHeaderFieldLabels, inputComponents[i].uiLabel];
            }
        }

        if (this.hasInvalidBatchFields &&
            (this.missingBatchHeaderFieldLabels && this.missingBatchHeaderFieldLabels.length > 0)) {

            this.missingRequiredFieldsMessage = GeLabelService.format(
                this.CUSTOM_LABELS.commonMissingRequiredFields,
                [this.missingBatchHeaderFieldLabels.join(', ')]);
        }
    }

    /*******************************************************************************
    * @description Fires an event to utilDedicatedListener with the save action if
    * a dedicated listener event name is provided otherwise dispatches a CustomEvent.
    */
    handleSave() {
        this.isLoading = true;
        const dataImportBatchObjectInfo = this.dataImportBatchCreateDefaults.data.objectInfos[
            this.dataImportBatchName
        ];
        const recordDefaults = this.dataImportBatchCreateDefaults.data.record;
        let recordObject = generateRecordInputForCreate(recordDefaults, dataImportBatchObjectInfo);
        recordObject = this.setFieldValues(recordObject);

        if (this.recordId) {
            this.handleRecordUpdate(recordObject);
        } else {
            this.handleRecordCreate(recordObject);
        }
    }

    setFieldValues(dataImportBatch) {
        let utilInputs = this.template.querySelectorAll('c-util-input');
        let batchDefaults = {};
        for (let i = 0; i < utilInputs.length; i++) {
            let formElement = utilInputs[i].reportValue();

            if (dataImportBatch.apiName === formElement.objectApiName) {
                dataImportBatch.fields[formElement.fieldApiName] = formElement.value;
            } else {
                batchDefaults[formElement.fieldApiName] = {
                    objectApiName: formElement.objectApiName,
                    fieldApiName: formElement.fieldApiName,
                    value: formElement.value
                };
            }
        }

        dataImportBatch.fields[DATA_IMPORT_BATCH_DEFAULTS_INFO.fieldApiName] =
            JSON.stringify(batchDefaults);
        dataImportBatch.fields[DATA_IMPORT_BATCH_FORM_TEMPLATE_INFO.fieldApiName] = this.selectedTemplateId;
        dataImportBatch.fields[DATA_IMPORT_BATCH_VERSION_INFO.fieldApiName] = 2.0;
        dataImportBatch.fields[DATA_IMPORT_BATCH_GIFT_INFO.fieldApiName] = true;
        // Set matching behavior
        dataImportBatch.fields[DATA_IMPORT_MATCHING_BEHAVIOR_INFO.fieldApiName] =
            this.donationMatchingBehaviors.ExactMatchOrCreate;
        // Set batch table column headers
        const hasAccessTobatchTableColumnsField =
            this.dataImportBatchInfo.fields[DATA_IMPORT_BATCH_TABLE_COLUMNS_FIELD.fieldApiName];
        if (hasAccessTobatchTableColumnsField) {
            dataImportBatch.fields[DATA_IMPORT_BATCH_TABLE_COLUMNS_FIELD.fieldApiName] =
                JSON.stringify(this.selectedTemplate.defaultBatchTableColumns);
        }

        if (this.recordId) {
            dataImportBatch.fields[DATA_IMPORT_BATCH_ID_INFO.fieldApiName] = this.recordId;
        }

        dataImportBatch = this.stripNameSpacedDonationMatchingRuleFields(dataImportBatch);

        return dataImportBatch;
    }

    /***************************************************************************
     * @description Strips namespace prefix from the Data Import Batch donation matching
     * rule fields if in a namespaced context
     * @param dataImportBatch
     * @returns {object}
     */
    stripNamespaceFromDonationMatchingRuleFields (dataImportBatch) {
        const donationMatchingRule = dataImportBatch.fields[
          DATA_IMPORT_BATCH_DONATION_MATCHING_RULE.fieldApiName];
        const namespace = getNamespace(DATA_IMPORT_BATCH_INFO.objectApiName);

        if (isNull(namespace)) {
            let strippedFields = '';
            const matchingRuleFields = donationMatchingRule.split(COMMA_SEPARATOR);
            matchingRuleFields.forEach(field => {
                strippedFields += stripNamespace(field,
                  namespace + '__') + COMMA_SEPARATOR;
            });
            dataImportBatch.fields[
              DATA_IMPORT_BATCH_DONATION_MATCHING_RULE.fieldApiName] =
              strippedFields.slice(0, -1);
        }
        return dataImportBatch;
    }

    handleRecordCreate(recordObject) {
        createRecord(recordObject)
            .then(record => {
                this.navigateToRecordViewPage(record.id);
            })
            .catch(error => {
                handleError(error);
            });
    }

    handleRecordUpdate(recordObject) {
        updateRecord({ fields: recordObject.fields })
            .then(() => {
                this.navigateToRecordViewPage(this.recordId);
            })
            .catch(error => {
                handleError(error);
            })
    }

    /*******************************************************************************
    * @description Fires an event to utilDedicatedListener with the cancel action if
    * a dedicated listener event name is provided otherwise dispatches a CustomEvent.
    */
    handleCancel() {
        if (this.dedicatedListenerEventName) {
            fireEvent(this.pageRef, this.dedicatedListenerEventName, { action: CANCEL });
        } else {
            this.dispatchEvent(new CustomEvent(CANCEL, { detail: {} }));
        }
    }

    /*******************************************************************************
    * @description Navigates to a record detail page by record id.
    *
    * @param {string} formTemplateRecordId: Form_Template__c record id.
    */
    navigateToRecordViewPage(recordId) {
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recordId,
                actionName: 'view'
            }
        });
    }

    resetValidations() {
        this.hasInvalidBatchFields = false;
        this.missingBatchHeaderFieldLabels = [];
    }

    /*******************************************************************************
     * Start getters for data-qa-locator attributes
     */

    get qaLocatorSelectTemplate() {
        return `combobox Wizard ${this.CUSTOM_LABELS.commonTemplate}`;
    }

    get qaLocatorSave() {
        return `button Wizard ${this.CUSTOM_LABELS.commonSave}`;
    }

    get qaLocatorNext() {
        return `button Wizard ${this.CUSTOM_LABELS.commonNext}`;
    }

    get qaLocatorCancel() {
        return `button Wizard ${this.CUSTOM_LABELS.commonCancel}`;
    }

    get qaLocatorBack() {
        return `button Wizard ${this.CUSTOM_LABELS.commonBack}`;
    }

    /*******************************************************************************
     * End getters for data-qa-locator-attributes
     */
}
<commit_msg>Updated function call<commit_after>/* eslint-disable array-callback-return */
import { LightningElement, api, track, wire } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import {
    createRecord,
    updateRecord,
    getRecord,
    getRecordCreateDefaults,
    generateRecordInputForCreate
} from 'lightning/uiRecordApi';
import { fireEvent } from 'c/pubsubNoPageRef';
import { handleError, addKeyToCollectionItems } from 'c/utilTemplateBuilder';
import {
    getNamespace,
    getNestedProperty,
    isNull,
    stripNamespace
} from 'c/utilCommon'
import GeLabelService from 'c/geLabelService';

import getAllFormTemplates from '@salesforce/apex/FORM_ServiceGiftEntry.getAllFormTemplates';
import getDonationMatchingValues from '@salesforce/apex/FORM_ServiceGiftEntry.getDonationMatchingValues';

import DATA_IMPORT_BATCH_INFO from '@salesforce/schema/DataImportBatch__c';
import DATA_IMPORT_BATCH_ID_INFO from '@salesforce/schema/DataImportBatch__c.Id';
import DATA_IMPORT_BATCH_FORM_TEMPLATE_INFO from '@salesforce/schema/DataImportBatch__c.Form_Template__c';
import DATA_IMPORT_BATCH_VERSION_INFO from '@salesforce/schema/DataImportBatch__c.Batch_Gift_Entry_Version__c';
import DATA_IMPORT_BATCH_GIFT_INFO from '@salesforce/schema/DataImportBatch__c.GiftBatch__c';
import DATA_IMPORT_BATCH_DEFAULTS_INFO from '@salesforce/schema/DataImportBatch__c.Batch_Defaults__c';
import DATA_IMPORT_MATCHING_BEHAVIOR_INFO from '@salesforce/schema/DataImportBatch__c.Donation_Matching_Behavior__c';
import DATA_IMPORT_BATCH_TABLE_COLUMNS_FIELD from '@salesforce/schema/DataImportBatch__c.Batch_Table_Columns__c';
import DATA_IMPORT_BATCH_DONATION_MATCHING_RULE from '@salesforce/schema/DataImportBatch__c.Donation_Matching_Rule__c';

const NAME = 'name';
const ID = 'id';
const MAX_STEPS = 2;
const CANCEL = 'cancel';
const COMMA_SEPARATOR = ';';

export default class geBatchWizard extends NavigationMixin(LightningElement) {

    // Expose custom labels to template
    CUSTOM_LABELS = GeLabelService.CUSTOM_LABELS;

    @api recordId;
    @api dedicatedListenerEventName;

    @track step = 0;
    @track templates;
    @track selectedBatchHeaderFields = [];
    @track formSections = [];
    @track selectedTemplateId;
    @track isLoading = true;
    @track donationMatchingBehaviors;
    @track hasInvalidBatchFields = false;
    @track missingBatchHeaderFieldLabels = [];
    @track missingRequiredFieldsMessage;

    dataImportBatchFieldInfos;
    dataImportBatchInfo;
    dataImportBatchRecord;
    templatesById = {};
    templateOptions;
    isLoaded = false;

    headers = {
        0: this.CUSTOM_LABELS.geHeaderBatchSelectTemplate,
        1: this.CUSTOM_LABELS.geHeaderBatchEnterInfo,
        2: this.CUSTOM_LABELS.geHeaderBatchSetDefaultValues
    }

    steps = {
        first: 0,
        second: 1,
        third: 2
    }

    get showBackButton() {
        if (this.step === 1 && this.isEditMode) {
            return false;
        }
        return this.step > 0 ? true : false;
    }

    get showSaveButton() {
        return this.step === 2 ? true : false;
    }

    get isNextButtonDisabled() {
        if (this.step === 0) {
            return !this.selectedTemplateId ? true : false;
        } else if (this.step === 1) {
            return false;
        }
        return false;
    }

    get header() {
        return this.headers[this.step];
    }

    get cssClassStep0() {
        return this.header === this.headers[0] ?
            'slds-p-horizontal_x-large slds-p-vertical_large slds-size_1-of-1 step-0' :
            'slds-hide';
    }

    get cssClassStep1() {
        return this.header === this.headers[1] ?
            'slds-p-horizontal_x-large slds-p-vertical_large slds-size_1-of-1' :
            'slds-hide';
    }

    get cssClassStep2() {
        return this.header === this.headers[2] ?
            'slds-p-horizontal_large slds-p-bottom_x-large slds-size_1-of-1' :
            'slds-hide';
    }

    get selectedTemplate() {
        if (this.selectedTemplateId && this.templatesById) {
            return this.templatesById[this.selectedTemplateId];
        }
        return undefined;
    }

    get isEditMode() {
        return this.recordId ? true : false;
    }

    get dataImportBatchName() {
        return getNestedProperty(DATA_IMPORT_BATCH_INFO, 'objectApiName');
    }

    /*******************************************************************************
    * @description Retrieves the DataImportBatch__c describe info.
    *
    * @param {string} dataImportBatchName: DataImportBatch__c object api name.
    */
    @wire(getObjectInfo, { objectApiName: '$dataImportBatchName' })
    wiredDataImportBatchInfo(response) {
        if (response.data) {
            this.dataImportBatchInfo = response.data;

            this.dataImportBatchFieldInfos =
                this.buildFieldDescribesForWiredMethod(
                    this.dataImportBatchInfo.fields,
                    this.dataImportBatchInfo.apiName);
        }
    }

    /*******************************************************************************
    * @description Method converts field describe info into objects that the
    * getRecord method can accept into its 'fields' parameter.
    *
    * @param {list} fields: List of field describe info.
    * @param {string} objectApiName: An SObject api name.
    */
    buildFieldDescribesForWiredMethod(fields, objectApiName) {
        return Object.keys(fields).map((fieldApiName) => {
            return {
                fieldApiName: fieldApiName,
                objectApiName: objectApiName
            }
        });
    }

    @wire(getRecord, { recordId: '$recordId', fields: '$dataImportBatchFieldInfos' })
    wiredDataImportBatchRecord(response) {
        if (response.data) {
            getAllFormTemplates()
                .then(templates => {
                    this.templates = templates;
                    this.builderTemplateComboboxOptions(this.templates);

                    this.dataImportBatchRecord = response.data;
                    let templateId = this
                        .dataImportBatchRecord
                        .fields[DATA_IMPORT_BATCH_FORM_TEMPLATE_INFO.fieldApiName]
                        .value;

                    this.handleTemplateChange({ detail: { value: templateId } });
                    this.setFormFieldsBatchLevelDefaults();

                    this.step = 1;

                    this.isLoading = false;
                })
                .catch(error => {
                    handleError(error);
                });
        }
    }

    setFormFieldsBatchLevelDefaults() {
        let batchLevelDefaults =
            JSON.parse(this.dataImportBatchRecord.fields[DATA_IMPORT_BATCH_DEFAULTS_INFO.fieldApiName].value);

        this.formSections.forEach(section => {
            if (section.elements) {
                section.elements.forEach(element => {
                    if (batchLevelDefaults[element.fieldApiName]) {
                        element.value = batchLevelDefaults[element.fieldApiName].value;
                    }
                });
            }
        });
    }

    @wire(getRecordCreateDefaults, { objectApiName: '$dataImportBatchName' })
    dataImportBatchCreateDefaults;

    setValuesForSelectedBatchHeaderFields(allFields) {
        this.selectedBatchHeaderFields.map(batchHeaderField => {
            let queriedField = allFields[batchHeaderField.apiName];
            if (queriedField) {
                batchHeaderField.value = queriedField.value;
            }
        });
    }

    async connectedCallback() {
        try {
            this.donationMatchingBehaviors = await getDonationMatchingValues();

            if (!this.recordId) {
                this.templates = await getAllFormTemplates();
                this.templates = this.templates.sort();
                this.builderTemplateComboboxOptions(this.templates);
                this.isLoading = false;
            }
        } catch (error) {
            handleError(error);
        }
    }

    builderTemplateComboboxOptions(templates) {
        if (templates && templates.length > 0) {
            this.templateOptions = this.templates.map(template => {
                this.templatesById[template[ID]] = template;
                return { label: template[NAME], value: template[ID] }
            });
        }
    }

    handleNext() {
        if (this.step === 1) {
            this.validateBatchHeaderFields();

            if (this.hasInvalidBatchFields) {
                return;
            }
        }

        if (this.step < MAX_STEPS) {
            this.step += 1;
        }
    }

    handleBack() {
        if (this.showBackButton || this.step > 0) {
            this.step -= 1;
        }
    }

    handleTemplateChange(event) {
        this.selectedTemplateId = event.detail.value;
        this.selectedBatchHeaderFields = [];

        this.selectedBatchHeaderFields = addKeyToCollectionItems(this.selectedTemplate.batchHeaderFields);
        this.formSections = this.selectedTemplate.layout.sections;
        if (this.recordId && this.dataImportBatchRecord && this.dataImportBatchRecord.fields) {
            this.setValuesForSelectedBatchHeaderFields(this.dataImportBatchRecord.fields);
        }

        this.resetValidations();
    }

    /*******************************************************************************
    * @description Method collects all batch header fields and checks for their
    * validity.
    */
    validateBatchHeaderFields() {
        this.resetValidations();

        let inputComponents = this.template.querySelectorAll('c-util-input[data-id="batchHeaderField"]');
        for (let i = 0; i < inputComponents.length; i++) {
            if (!inputComponents[i].isValid()) {
                this.hasInvalidBatchFields = true;
                this.missingBatchHeaderFieldLabels =
                    [...this.missingBatchHeaderFieldLabels, inputComponents[i].uiLabel];
            }
        }

        if (this.hasInvalidBatchFields &&
            (this.missingBatchHeaderFieldLabels && this.missingBatchHeaderFieldLabels.length > 0)) {

            this.missingRequiredFieldsMessage = GeLabelService.format(
                this.CUSTOM_LABELS.commonMissingRequiredFields,
                [this.missingBatchHeaderFieldLabels.join(', ')]);
        }
    }

    /*******************************************************************************
    * @description Fires an event to utilDedicatedListener with the save action if
    * a dedicated listener event name is provided otherwise dispatches a CustomEvent.
    */
    handleSave() {
        this.isLoading = true;
        const dataImportBatchObjectInfo = this.dataImportBatchCreateDefaults.data.objectInfos[
            this.dataImportBatchName
        ];
        const recordDefaults = this.dataImportBatchCreateDefaults.data.record;
        let recordObject = generateRecordInputForCreate(recordDefaults, dataImportBatchObjectInfo);
        recordObject = this.setFieldValues(recordObject);

        if (this.recordId) {
            this.handleRecordUpdate(recordObject);
        } else {
            this.handleRecordCreate(recordObject);
        }
    }

    setFieldValues(dataImportBatch) {
        let utilInputs = this.template.querySelectorAll('c-util-input');
        let batchDefaults = {};
        for (let i = 0; i < utilInputs.length; i++) {
            let formElement = utilInputs[i].reportValue();

            if (dataImportBatch.apiName === formElement.objectApiName) {
                dataImportBatch.fields[formElement.fieldApiName] = formElement.value;
            } else {
                batchDefaults[formElement.fieldApiName] = {
                    objectApiName: formElement.objectApiName,
                    fieldApiName: formElement.fieldApiName,
                    value: formElement.value
                };
            }
        }

        dataImportBatch.fields[DATA_IMPORT_BATCH_DEFAULTS_INFO.fieldApiName] =
            JSON.stringify(batchDefaults);
        dataImportBatch.fields[DATA_IMPORT_BATCH_FORM_TEMPLATE_INFO.fieldApiName] = this.selectedTemplateId;
        dataImportBatch.fields[DATA_IMPORT_BATCH_VERSION_INFO.fieldApiName] = 2.0;
        dataImportBatch.fields[DATA_IMPORT_BATCH_GIFT_INFO.fieldApiName] = true;
        // Set matching behavior
        dataImportBatch.fields[DATA_IMPORT_MATCHING_BEHAVIOR_INFO.fieldApiName] =
            this.donationMatchingBehaviors.ExactMatchOrCreate;
        // Set batch table column headers
        const hasAccessTobatchTableColumnsField =
            this.dataImportBatchInfo.fields[DATA_IMPORT_BATCH_TABLE_COLUMNS_FIELD.fieldApiName];
        if (hasAccessTobatchTableColumnsField) {
            dataImportBatch.fields[DATA_IMPORT_BATCH_TABLE_COLUMNS_FIELD.fieldApiName] =
                JSON.stringify(this.selectedTemplate.defaultBatchTableColumns);
        }

        if (this.recordId) {
            dataImportBatch.fields[DATA_IMPORT_BATCH_ID_INFO.fieldApiName] = this.recordId;
        }

        dataImportBatch = this.stripNamespaceFromDonationMatchingRuleFields(dataImportBatch);

        return dataImportBatch;
    }

    /***************************************************************************
     * @description Strips namespace prefix from the Data Import Batch donation matching
     * rule fields if in a namespaced context
     * @param dataImportBatch
     * @returns {object}
     */
    stripNamespaceFromDonationMatchingRuleFields (dataImportBatch) {
        const donationMatchingRule = dataImportBatch.fields[
          DATA_IMPORT_BATCH_DONATION_MATCHING_RULE.fieldApiName];
        const namespace = getNamespace(DATA_IMPORT_BATCH_INFO.objectApiName);

        if (isNull(namespace)) {
            let strippedFields = '';
            const matchingRuleFields = donationMatchingRule.split(COMMA_SEPARATOR);
            matchingRuleFields.forEach(field => {
                strippedFields += stripNamespace(field,
                  namespace + '__') + COMMA_SEPARATOR;
            });
            dataImportBatch.fields[
              DATA_IMPORT_BATCH_DONATION_MATCHING_RULE.fieldApiName] =
              strippedFields.slice(0, -1);
        }
        return dataImportBatch;
    }

    handleRecordCreate(recordObject) {
        createRecord(recordObject)
            .then(record => {
                this.navigateToRecordViewPage(record.id);
            })
            .catch(error => {
                handleError(error);
            });
    }

    handleRecordUpdate(recordObject) {
        updateRecord({ fields: recordObject.fields })
            .then(() => {
                this.navigateToRecordViewPage(this.recordId);
            })
            .catch(error => {
                handleError(error);
            })
    }

    /*******************************************************************************
    * @description Fires an event to utilDedicatedListener with the cancel action if
    * a dedicated listener event name is provided otherwise dispatches a CustomEvent.
    */
    handleCancel() {
        if (this.dedicatedListenerEventName) {
            fireEvent(this.pageRef, this.dedicatedListenerEventName, { action: CANCEL });
        } else {
            this.dispatchEvent(new CustomEvent(CANCEL, { detail: {} }));
        }
    }

    /*******************************************************************************
    * @description Navigates to a record detail page by record id.
    *
    * @param {string} formTemplateRecordId: Form_Template__c record id.
    */
    navigateToRecordViewPage(recordId) {
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recordId,
                actionName: 'view'
            }
        });
    }

    resetValidations() {
        this.hasInvalidBatchFields = false;
        this.missingBatchHeaderFieldLabels = [];
    }

    /*******************************************************************************
     * Start getters for data-qa-locator attributes
     */

    get qaLocatorSelectTemplate() {
        return `combobox Wizard ${this.CUSTOM_LABELS.commonTemplate}`;
    }

    get qaLocatorSave() {
        return `button Wizard ${this.CUSTOM_LABELS.commonSave}`;
    }

    get qaLocatorNext() {
        return `button Wizard ${this.CUSTOM_LABELS.commonNext}`;
    }

    get qaLocatorCancel() {
        return `button Wizard ${this.CUSTOM_LABELS.commonCancel}`;
    }

    get qaLocatorBack() {
        return `button Wizard ${this.CUSTOM_LABELS.commonBack}`;
    }

    /*******************************************************************************
     * End getters for data-qa-locator-attributes
     */
}
<|endoftext|>


<commit_before>import {LightningElement, api, track} from 'lwc';

export default class GeFormSection extends LightningElement {
    @api section;
    @api widgetData;
    @track collapsed = false;

    /**
     * Get the alternative text that represents the section expand/collapse button
     * @returns {string} containing the section expand alternative text
     */
    get altTextLabel() {
        return 'Toggle ' + this.section.label;
    }

    @api
    get values() {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        let dataImportFieldAndValues = {};
        if(fields !== null && typeof fields !== 'undefined') {
            fields.forEach(field => {
                dataImportFieldAndValues = { ...dataImportFieldAndValues, ...(field.fieldAndValue) };
            });
        }
        return dataImportFieldAndValues;
    }

    /**
     * Gets value and UI-label for the requestedFields in the section (if any)
     * @param requestedFields - Array of API Field Names to get information
     * @returns {Array} - field value and ui-label using api-field-name as key
     */
    @api
    getFieldValueAndLabel( requestedFields ) {

        const fields = this.template.querySelectorAll('c-ge-form-field');
        let dataImportFieldAndLabels = {};

        if (fields !== null && typeof fields !== 'undefined') {
            fields.forEach( field => {
                if ( requestedFields.indexOf(field.sourceFieldAPIName) !== -1 ){
                    field.clearCustomValidity();
                    dataImportFieldAndLabels = { ...dataImportFieldAndLabels, ...(field.fieldValueAndLabel) };
                }
            });
        }

        return dataImportFieldAndLabels;

    }

    /**
     * Sets custom validity on fields inside fieldsArray
     * @param {fieldsArray},Array with sourceFieldAPIName field property
     * @param {errorMessage}, String custom error message for fields
     */
    @api
    setCustomValidityOnFields( fieldsArray, errorMessage ) {

        const fields = this.template.querySelectorAll('c-ge-form-field');
        if (fields !== null && typeof fields !== 'undefined') {
            fields.forEach(f => {
                if ( fieldsArray.indexOf(f.sourceFieldAPIName)!== -1 ) {
                    f.setCustomValidity(errorMessage);
                }
            });
        }

    }

    @api
    get widgetValues() {
        const widgets = this.template.querySelectorAll('c-ge-form-widget');
        let widgetValues = {};
        if(widgets !== null && typeof widgets !== 'undefined') {
            widgets.forEach(widget => {
                widgetValues = { ...widgetValues, ...(widget.widgetAndValues) };
            });
        }
        return widgetValues;
    }

    /**
     * Get a list of fields that are required, but are null/undefined or otherwise blank in the dynamic form
     * @returns {Array} of invalid fields. If all fields are ok, the array is empty.
     */
    @api
    getInvalidFields() {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        let invalidFields = [];

        fields.forEach(f => {
            if(!f.isValid()) {
                invalidFields.push(f.fieldLabel);
            }
        });

        return invalidFields;
    }

    @api
    getAllFieldsByAPIName() {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        let fieldMappedByAPIName = {};

        fields.forEach(f => {
            fieldMappedByAPIName[f.sourceFieldAPIName] = f;
        });

        return fieldMappedByAPIName;
    }

    @api
    load(data){
        const fields = this.template.querySelectorAll('c-ge-form-field');

        fields.forEach(field => {
            field.load(data);
        });
    }

    @api
    reset(fieldMappingDevNames = null) {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        const widgetList = this.template.querySelectorAll('c-ge-form-widget');

        fields.forEach(field => {
            if (fieldMappingDevNames) {
                // reset the fields elements related to
                // these field mappings
                if (fieldMappingDevNames.includes(
                    field.element.dataImportFieldMappingDevNames[0]
                )) {
                    field.reset();
                }
            } else {
                // reset all field elements in this section
                field.reset();
            }
        });

        widgetList.forEach(widget => {
            widget.reset();
        });
    }

    handleLookupRecordSelect(event) {
        const selectEvent = new CustomEvent(
            'lookuprecordselect',
            { detail: event.detail });
        this.dispatchEvent(selectEvent);
    }

    handleChangeDonationDonor(event) {
        const changeDonationDonorEvent = new CustomEvent(
            'changedonationdonor',
            { detail: event.detail });
        this.dispatchEvent(changeDonationDonorEvent);
    }
}<commit_msg>Only call load() on field component if the property exists<commit_after>import {LightningElement, api, track} from 'lwc';

export default class GeFormSection extends LightningElement {
    @api section;
    @api widgetData;
    @track collapsed = false;

    /**
     * Get the alternative text that represents the section expand/collapse button
     * @returns {string} containing the section expand alternative text
     */
    get altTextLabel() {
        return 'Toggle ' + this.section.label;
    }

    @api
    get values() {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        let dataImportFieldAndValues = {};
        if(fields !== null && typeof fields !== 'undefined') {
            fields.forEach(field => {
                dataImportFieldAndValues = { ...dataImportFieldAndValues, ...(field.fieldAndValue) };
            });
        }
        return dataImportFieldAndValues;
    }

    /**
     * Gets value and UI-label for the requestedFields in the section (if any)
     * @param requestedFields - Array of API Field Names to get information
     * @returns {Array} - field value and ui-label using api-field-name as key
     */
    @api
    getFieldValueAndLabel( requestedFields ) {

        const fields = this.template.querySelectorAll('c-ge-form-field');
        let dataImportFieldAndLabels = {};

        if (fields !== null && typeof fields !== 'undefined') {
            fields.forEach( field => {
                if ( requestedFields.indexOf(field.sourceFieldAPIName) !== -1 ){
                    field.clearCustomValidity();
                    dataImportFieldAndLabels = { ...dataImportFieldAndLabels, ...(field.fieldValueAndLabel) };
                }
            });
        }

        return dataImportFieldAndLabels;

    }

    /**
     * Sets custom validity on fields inside fieldsArray
     * @param {fieldsArray},Array with sourceFieldAPIName field property
     * @param {errorMessage}, String custom error message for fields
     */
    @api
    setCustomValidityOnFields( fieldsArray, errorMessage ) {

        const fields = this.template.querySelectorAll('c-ge-form-field');
        if (fields !== null && typeof fields !== 'undefined') {
            fields.forEach(f => {
                if ( fieldsArray.indexOf(f.sourceFieldAPIName)!== -1 ) {
                    f.setCustomValidity(errorMessage);
                }
            });
        }

    }

    @api
    get widgetValues() {
        const widgets = this.template.querySelectorAll('c-ge-form-widget');
        let widgetValues = {};
        if(widgets !== null && typeof widgets !== 'undefined') {
            widgets.forEach(widget => {
                widgetValues = { ...widgetValues, ...(widget.widgetAndValues) };
            });
        }
        return widgetValues;
    }

    /**
     * Get a list of fields that are required, but are null/undefined or otherwise blank in the dynamic form
     * @returns {Array} of invalid fields. If all fields are ok, the array is empty.
     */
    @api
    getInvalidFields() {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        let invalidFields = [];

        fields.forEach(f => {
            if(!f.isValid()) {
                invalidFields.push(f.fieldLabel);
            }
        });

        return invalidFields;
    }

    @api
    getAllFieldsByAPIName() {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        let fieldMappedByAPIName = {};

        fields.forEach(f => {
            fieldMappedByAPIName[f.sourceFieldAPIName] = f;
        });

        return fieldMappedByAPIName;
    }

    @api
    load(data){
        const fields = this.template.querySelectorAll('c-ge-form-field');

        fields.forEach(fieldCmp => {
            if (Object.keys(data).includes(fieldCmp.sourceFieldAPIName)) {
                fieldCmp.load(data);
            }
        });
    }

    @api
    reset(fieldMappingDevNames = null) {
        const fields = this.template.querySelectorAll('c-ge-form-field');
        const widgetList = this.template.querySelectorAll('c-ge-form-widget');

        fields.forEach(field => {
            if (fieldMappingDevNames) {
                // reset the fields elements related to
                // these field mappings
                if (fieldMappingDevNames.includes(
                    field.element.dataImportFieldMappingDevNames[0]
                )) {
                    field.reset();
                }
            } else {
                // reset all field elements in this section
                field.reset();
            }
        });

        widgetList.forEach(widget => {
            widget.reset();
        });
    }

    handleLookupRecordSelect(event) {
        const selectEvent = new CustomEvent(
            'lookuprecordselect',
            { detail: event.detail });
        this.dispatchEvent(selectEvent);
    }

    handleChangeDonationDonor(event) {
        const changeDonationDonorEvent = new CustomEvent(
            'changedonationdonor',
            { detail: event.detail });
        this.dispatchEvent(changeDonationDonorEvent);
    }
}<|endoftext|>


<commit_before>var options = require("commander");
var q = require("q");
var BigIp = require('./lib/bigIp');

var bigIp;

var createVirtualAndPool = function() {
    var pool;

    return bigIp.create(
        '/tm/ltm/pool',
        {
            'name': 'myPool',
            'members': [
                { 'name': '192.168.100.1:80', 'description': 'test-member-1' },
                { 'name': '192.168.100.2:80', 'description': 'test-member-2' },
                { 'name': '192.168.100.3:80', 'description': 'test-member-3' },
            ]
        }
    )
    .then(function(response) {
        pool = response;

        return bigIp.create(
            '/tm/ltm/virtual',
            {
                'name': 'myVirtual',
                'pool': pool.fullPath,
                'destination': '1.2.3.4:80'
            }
        );
    })
    .then(function(response) {
        console.log("Created virtual: " + JSON.stringify(response, null, 4));
    })
    .catch(function(error) {
        console.log("createVirtualAndPool failed: " + error.message);
    });
};

var collect = function(val, collection) {
    collection.push(val);
    return collection;
};

options
    .option('--host <ip_address>', 'BIG-IP management IP.')
    .option('-u, --user <user>', 'BIG-IP admin user.')
    .option('-p, --password <password>', 'BIG-IP admin user password.')
    .option('-n, --host-name <hostname>', 'Hostname to set on BIG-IP.')
    .option('-l, --license <license_key>', 'BIG-IP license key.')
    .option('-a, --add-on <add-on keys>', 'Add on license keys.', collect, [])
    .parse(process.argv);

bigIp = new BigIp(options.host, options.user, options.password);

console.log("Waiting for BIG-IP to be ready...");
bigIp.ready()
    .then(function() {
        console.log("BIG-IP is ready.");
        console.log("Performing initial setup...");

        var nameServers = ["10.133.20.70", "10.133.20.71"];
        var timezone = 'UTC';
        var ntpServers = ["0.us.pool.ntp.org", "1.us.pool.ntp.org"];

        return bigIp.initialSetup(
            {
                guiSetup: false,
                dns: {
                    nameServers: nameServers
                },
                ntp: {
                    timezone: timezone,
                    servers: ntpServers
                },
                hostname: options.hostName
            }
        );
    })
    .then(function() {
        console.log("Initial setup complete.");

        var registrationKey = options.license;
        var addOnKeys = options.addOn;

        if (registrationKey || addOnKeys.length > 0) {
            console.log("Licensing...");

            return bigIp.license(
                {
                    registrationKey: registrationKey,
                    addOnKeys: addOnKeys
                }
            );
        }

        return q();
    })
    .then(function(response) {
        if (response) {
            console.log(response);
        }

        console.log("BIG-IP setup complete.");
    })
    .catch(function(err) {
        console.log("BIG-IP setup failed: " + (typeof err === 'object' ? err.message : err));
    })
    .done();
<commit_msg>Remove createServerAndPool<commit_after>var options = require("commander");
var q = require("q");
var BigIp = require('./lib/bigIp');

var bigIp;

var collect = function(val, collection) {
    collection.push(val);
    return collection;
};

options
    .option('--host <ip_address>', 'BIG-IP management IP.')
    .option('-u, --user <user>', 'BIG-IP admin user.')
    .option('-p, --password <password>', 'BIG-IP admin user password.')
    .option('-n, --host-name <hostname>', 'Hostname to set on BIG-IP.')
    .option('-l, --license <license_key>', 'BIG-IP license key.')
    .option('-a, --add-on <add-on keys>', 'Add on license keys.', collect, [])
    .parse(process.argv);

bigIp = new BigIp(options.host, options.user, options.password);

console.log("Waiting for BIG-IP to be ready...");
bigIp.ready()
    .then(function() {
        console.log("BIG-IP is ready.");
        console.log("Performing initial setup...");

        var nameServers = ["10.133.20.70", "10.133.20.71"];
        var timezone = 'UTC';
        var ntpServers = ["0.us.pool.ntp.org", "1.us.pool.ntp.org"];

        return bigIp.initialSetup(
            {
                guiSetup: false,
                dns: {
                    nameServers: nameServers
                },
                ntp: {
                    timezone: timezone,
                    servers: ntpServers
                },
                hostname: options.hostName
            }
        );
    })
    .then(function() {
        console.log("Initial setup complete.");

        var registrationKey = options.license;
        var addOnKeys = options.addOn;

        if (registrationKey || addOnKeys.length > 0) {
            console.log("Licensing...");

            return bigIp.license(
                {
                    registrationKey: registrationKey,
                    addOnKeys: addOnKeys
                }
            );
        }

        return q();
    })
    .then(function(response) {
        if (response) {
            console.log(response);
        }

        console.log("BIG-IP setup complete.");
    })
    .catch(function(err) {
        console.log("BIG-IP setup failed: " + (typeof err === 'object' ? err.message : err));
    })
    .done();
<|endoftext|>


<commit_before>var tooltipsCats = [
	'.resource_add_button',
    '.resource_edit_button',
    '.recommender_vote_arrow_up',
    '.recommender_vote_arrow_down',
    '.recommender_vote_score',
    '.recommender_blurb',
    '.previewingImg',
    '.in_title',
    '.in_url',
    '.edit_title',
    '.edit_url',
    '.backToViewButton',
    '.flag_reason',
    '.flagResource',
    '.flagResource.problematic',
    '.recommender_row_top',
    '.recommender_row_top.resource_list_expanded'
];

var tooltipsCatsText = {
	'.resource_add_button': 'Recommend a new helpful resource for this problem with a short description, hyperlink, and previewing screenshot to the new resource',
    '.resource_edit_button': 'Edit the description, hypelink, and previewing screenshot of this resource',
    '.recommender_vote_arrow_up': 'Upvote for a helpful resource',
    '.recommender_vote_arrow_down': 'Downvote for an irrelevant resource',
    '.recommender_vote_score': 'Votes',
    '.recommender_blurb': 'The title of a helpful resource',
    '.previewingImg': 'Previewing screenshot',
    '.in_title': 'Type in the description of the resource',
    '.in_url': 'Type in the hyperlink to the resource',
    '.edit_title': 'Type in the description of the resource',
    '.edit_url': 'Type in the hyperlink to the resource',
    '.backToViewButton': 'Back to list of related resources',
    '.flag_reason': 'Type in the reason why you flag the resource',
    '.flagResource': 'Flag this resource as problematic and give the reason',
    '.flagResource.problematic': 'Unflag this problematic resource or edit the reason for it',
    '.recommender_row_top': 'Select for expanding resource list',
    '.recommender_row_top.resource_list_expanded': 'Select to hide the list'
};

var staff_edit_buttons = [
	"submit_s3_info",
	'delete_resource'/*,
    "endorse_resource",
    "deendorse_resource"*/
]

var staff_edit_buttons_text = {
	'delete_resource': "Delete resource",
    "endorse_resource": "Endorse resource",
    "deendorse_resource": "De-endorse resource",
	"submit_s3_info": "Submit information for Amazon Web Services S3"
}

var staff_edit_textareas = [
	'aws_access_key',
	'aws_secret_key',
	'bucketName',
	'uploadedFileDir'
]

var staff_edit_textareas_text = {
	'aws_access_key': 'Amazon Web Services access key',
	'aws_secret_key': 'Amazon Web Services secret key',
	'bucketName': 'Bucket name of your Amazon Web Services',
	'uploadedFileDir': 'Directory for your upload files'
}

var staff_edit_textareas_placeholder = {
	'aws_access_key': '',
	'aws_secret_key': '',
	'bucketName': 'danielswli',
	'uploadedFileDir': 'uploads/'
}<commit_msg>Update cats.js<commit_after>var tooltipsCats = [
    '.resource_add_button',
    '.resource_edit_button',
    '.recommender_vote_arrow_up',
    '.recommender_vote_arrow_down',
    '.recommender_vote_score',
    '.recommender_blurb',
    '.previewingImg',
    '.in_title',
    '.in_url',
    '.edit_title',
    '.edit_url',
    '.backToViewButton',
    '.flag_reason',
    '.flagResource',
    '.flagResource.problematic',
    '.recommender_row_top',
    '.recommender_row_top.resource_list_expanded'
];

var tooltipsCatsText = {
    '.resource_add_button': 'Recommend a new resource which may be helpful to other students solving this problem',
    '.resource_edit_button': 'Edit this resource',
    '.recommender_vote_arrow_up': 'Upvote if the resource is helpful',
    '.recommender_vote_arrow_down': 'Downvote if the resource is not helpful',
    '.recommender_vote_score': 'Votes', //
    '.recommender_blurb': 'Resource title', // TODO: I would suggest making the description be the tooltip.
    '.previewingImg': 'Preview image (typically, a screenshot)',
    '.in_title': 'Give a short (1-3 sentence) summary of the resource; ideally, this should be concise, but give enough detail to let students know whether this resources is useful to them',
    '.in_url': 'Cut-and-paste the URL of the resource.',
    '.edit_title': 'Give a short (1-3 sentence) summary of the resource; ideally, this should be concise, but give enough detail to let students know whether this resources is useful to them',
    '.edit_url': 'Cut-and-paste the URL of the resource.', // TODO: Give instructions to go to element of learning sequence, or time in video
    '.backToViewButton': 'Go back to the main list',
    '.flag_reason': 'Give a meaningful reason for why this resource should be removed',
    '.flagResource': 'Flag this resource as problematic',
    '.flagResource.problematic': 'Unflag this problematic resource or edit the reason for it',
    '.recommender_row_top': 'Show a list of student-recommented related resources',
    '.recommender_row_top.resource_list_expanded': 'Hide the recommendations list'
};

var staff_edit_buttons = [
	"submit_s3_info",
	'delete_resource'/*,
	"endorse_resource",
	"deendorse_resource"*/
]

var staff_edit_buttons_text = {
	'delete_resource': "Delete resource",
	"endorse_resource": "Endorse resource",
	"deendorse_resource": "De-endorse resource",
	"submit_s3_info": "Submit information for Amazon Web Services S3"
}

var staff_edit_textareas = [
	'aws_access_key',
	'aws_secret_key',
	'bucketName',
	'uploadedFileDir'
]

var staff_edit_textareas_text = {
	'aws_access_key': 'Amazon Web Services access key',
	'aws_secret_key': 'Amazon Web Services secret key',
	'bucketName': 'Bucket name of your Amazon Web Services',
	'uploadedFileDir': 'Directory for your upload files'
}

var staff_edit_textareas_placeholder = {
	'aws_access_key': '',
	'aws_secret_key': '',
	'bucketName': 'danielswli',
	'uploadedFileDir': 'uploads/'
}
<|endoftext|>


<commit_before>/*globals Hungarian*/
(function( window, document, undefined ) {
  'use strict';

  var PI2 = 2 * Math.PI;

  var canvas  = document.querySelector( 'canvas' ),
      context = canvas.getContext( '2d' );

  var points = {
    a: [],
    b: [],
    lerp: []
  };

  function randomPointInCircle( x, y, radius ) {
    var r = radius * Math.sqrt( Math.random() ),
        theta = PI2 * Math.random();

    return [
      x + r * Math.cos( theta ),
      y + r * Math.sin( theta )
    ];
  }

  function lerp( a, b, t ) {
    return a + t * ( b - a );
  }

  function lerpArray( n, m, t ) {
    var length = Math.min( n.length, m.length );

    var array = [];
    for ( var i = 0; i < length; i++) {
      array.push( lerp( n[i], m[i], t ) );
    }

    return array;
  }

  function costMatrix( n, m ) {
    var height = 0.5 * n.length;
    var width = 0.5 * m.length;

    var array = [];
    for ( var y = 0; y < height; y++ ) {
      array.push( [] );
    }

    var dx, dy;
    var i, j;
    var xi, yi, xj, yj;
    for ( j = 0; j < height; j++ ) {
      for ( i = 0; i < width; i++ ) {
        xi = m[ 2 * i ];
        yi = m[ 2 * i + 1 ];
        xj = n[ 2 * j ];
        yj = n[ 2 * j + 1 ];

        dx = xj - xi;
        dy = yj - yi;

        array[j][i] = Math.sqrt( dx * dx + dy * dy );
      }
    }

    return array;
  }

  function drawPoints( ctx, points, size ) {
    size = size || 3;
    var halfSize = 0.5 * size;

    for ( var i = 0, il = 0.5 * points.length; i < il; i++ ) {
      ctx.rect(
        points[ 2 * i     ] - halfSize,
        points[ 2 * i + 1 ] - halfSize,
        size, size
      );
    }
  }

  /**
   * Draw line segments between corresponding vertex pairs (by index) in
   * the two arrays: n, m.
   */
  function drawSegments( ctx, n, m ) {
    var length = Math.min( n.length, m.length );

    for ( var i = 0, il = 0.5 * length; i < il; i++ ) {
      ctx.moveTo( n[ 2 * i ], n[ 2 * i + 1 ] );
      ctx.lineTo( m[ 2 * i ], m[ 2 * i + 1 ] );
    }
  }

  function draw( ctx ) {
    ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );

    // Draw lerped points.
    ctx.beginPath();
    drawPoints( ctx, points.lerp );
    ctx.fillStyle = '#fff';
    ctx.fill();

    // Draw connecting segments.
    ctx.beginPath();
    drawSegments( ctx, points.a, points.b );
    ctx.lineWidth = 0.2;
    ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
    ctx.stroke();

    // Draw point sets.
    ctx.beginPath();
    drawPoints( ctx, points.a );
    ctx.fillStyle = '#f00';
    ctx.fill();

    ctx.beginPath();
    drawPoints( ctx, points.b );
    ctx.fillStyle = '#0f0';
    ctx.fill();
  }

  function resize() {
    var width  = window.innerWidth,
        height = window.innerHeight;

    canvas.width  = width;
    canvas.height = height;

    var x = 0.5 * width,
        y = 0.5 * height;

    var radius = 0.5 * Math.min( width, height );

    // Reset points.
    points.a = [];
    points.b = [];
    points.lerp = [];

    var pointCount = 60;
    while ( pointCount-- ) {
      points.a = points.a.concat( randomPointInCircle( x, y, 0.2 * radius ) );
      points.b = points.b.concat( randomPointInCircle( x, y, 0.8 * radius ) );
    }

    // Compute cost matrix and Hungarian assignments.
    var matrix = costMatrix( points.a, points.b );
    var clone = Hungarian.Matrix.clone( matrix );

    console.time( 'hungarian' );
    var solution = Hungarian.calculate( clone );
    console.timeEnd( 'hungarian' );
    console.log( 'cost: ' + Hungarian.cost( matrix, solution ) );

    var array = [];
    for ( var i = 0, il = 0.5 * points.b.length; i < il; i++ ) {
      array[ 2 * i ] = points.b[ 2 * solution[i] ];
      array[ 2 * i + 1 ] = points.b[ 2 * solution[i] + 1 ];
    }

    points.b = array;

    draw( context );
  }

  resize();

  function onMouse( event ) {
    var xt = event.pageX / window.innerWidth;
    // Smoother step: 6t^5 - 15t^4 + 10t^3.
    xt = 6 * Math.pow( xt, 5 ) - 15 * Math.pow( xt, 4 ) + 10 * Math.pow( xt, 3 );
    points.lerp = lerpArray( points.a, points.b, xt );
    draw( context );
  }

  function onTouch( event ) {
    onMouse( event.touches[0] );
  }

  if ( 'ontouchstart' in window ) {
    window.addEventListener( 'touchstart', onTouch );

    window.addEventListener( 'touchmove', function( event ) {
      event.preventDefault();
      onTouch( event );
    });
  } else {
    window.addEventListener( 'mousemove', onMouse );
  }

  window.addEventListener( 'resize', resize );
  window.addEventListener( 'orientationchange', resize );

}) ( window, document );
<commit_msg>registration[points]: Extract smootherstep function.<commit_after>/*globals Hungarian*/
(function( window, document, undefined ) {
  'use strict';

  var PI2 = 2 * Math.PI;

  var canvas  = document.querySelector( 'canvas' ),
      context = canvas.getContext( '2d' );

  var points = {
    a: [],
    b: [],
    lerp: []
  };

  function randomPointInCircle( x, y, radius ) {
    var r = radius * Math.sqrt( Math.random() ),
        theta = PI2 * Math.random();

    return [
      x + r * Math.cos( theta ),
      y + r * Math.sin( theta )
    ];
  }

  function lerp( a, b, t ) {
    return a + t * ( b - a );
  }

  function lerpArray( n, m, t ) {
    var length = Math.min( n.length, m.length );

    var array = [];
    for ( var i = 0; i < length; i++) {
      array.push( lerp( n[i], m[i], t ) );
    }

    return array;
  }

  function costMatrix( n, m ) {
    var height = 0.5 * n.length;
    var width = 0.5 * m.length;

    var array = [];
    for ( var y = 0; y < height; y++ ) {
      array.push( [] );
    }

    var dx, dy;
    var i, j;
    var xi, yi, xj, yj;
    for ( j = 0; j < height; j++ ) {
      for ( i = 0; i < width; i++ ) {
        xi = m[ 2 * i ];
        yi = m[ 2 * i + 1 ];
        xj = n[ 2 * j ];
        yj = n[ 2 * j + 1 ];

        dx = xj - xi;
        dy = yj - yi;

        array[j][i] = Math.sqrt( dx * dx + dy * dy );
      }
    }

    return array;
  }

  function drawPoints( ctx, points, size ) {
    size = size || 3;
    var halfSize = 0.5 * size;

    for ( var i = 0, il = 0.5 * points.length; i < il; i++ ) {
      ctx.rect(
        points[ 2 * i     ] - halfSize,
        points[ 2 * i + 1 ] - halfSize,
        size, size
      );
    }
  }

  /**
   * Draw line segments between corresponding vertex pairs (by index) in
   * the two arrays: n, m.
   */
  function drawSegments( ctx, n, m ) {
    var length = Math.min( n.length, m.length );

    for ( var i = 0, il = 0.5 * length; i < il; i++ ) {
      ctx.moveTo( n[ 2 * i ], n[ 2 * i + 1 ] );
      ctx.lineTo( m[ 2 * i ], m[ 2 * i + 1 ] );
    }
  }

  function draw( ctx ) {
    ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );

    // Draw lerped points.
    ctx.beginPath();
    drawPoints( ctx, points.lerp );
    ctx.fillStyle = '#fff';
    ctx.fill();

    // Draw connecting segments.
    ctx.beginPath();
    drawSegments( ctx, points.a, points.b );
    ctx.lineWidth = 0.2;
    ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
    ctx.stroke();

    // Draw point sets.
    ctx.beginPath();
    drawPoints( ctx, points.a );
    ctx.fillStyle = '#f00';
    ctx.fill();

    ctx.beginPath();
    drawPoints( ctx, points.b );
    ctx.fillStyle = '#0f0';
    ctx.fill();
  }

  function resize() {
    var width  = window.innerWidth,
        height = window.innerHeight;

    canvas.width  = width;
    canvas.height = height;

    var x = 0.5 * width,
        y = 0.5 * height;

    var radius = 0.5 * Math.min( width, height );

    // Reset points.
    points.a = [];
    points.b = [];
    points.lerp = [];

    var pointCount = 60;
    while ( pointCount-- ) {
      points.a = points.a.concat( randomPointInCircle( x, y, 0.2 * radius ) );
      points.b = points.b.concat( randomPointInCircle( x, y, 0.8 * radius ) );
    }

    // Compute cost matrix and Hungarian assignments.
    var matrix = costMatrix( points.a, points.b );
    var clone = Hungarian.Matrix.clone( matrix );

    console.time( 'hungarian' );
    var solution = Hungarian.calculate( clone );
    console.timeEnd( 'hungarian' );
    console.log( 'cost: ' + Hungarian.cost( matrix, solution ) );

    var array = [];
    for ( var i = 0, il = 0.5 * points.b.length; i < il; i++ ) {
      array[ 2 * i ] = points.b[ 2 * solution[i] ];
      array[ 2 * i + 1 ] = points.b[ 2 * solution[i] + 1 ];
    }

    points.b = array;

    draw( context );
  }

  resize();

  function smootherstep( t ) {
    // 6t^5 - 15t^4 + 10t^3.
    return t * t * t * ( t * ( t * 6 - 15 ) + 10 );
  }

  function onMouse( event ) {
    var xt = smootherstep( event.pageX / window.innerWidth );
    points.lerp = lerpArray( points.a, points.b, xt );
    draw( context );
  }

  function onTouch( event ) {
    onMouse( event.touches[0] );
  }

  if ( 'ontouchstart' in window ) {
    window.addEventListener( 'touchstart', onTouch );

    window.addEventListener( 'touchmove', function( event ) {
      event.preventDefault();
      onTouch( event );
    });
  } else {
    window.addEventListener( 'mousemove', onMouse );
  }

  window.addEventListener( 'resize', resize );
  window.addEventListener( 'orientationchange', resize );

}) ( window, document );
<|endoftext|>