<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { browserHistory } from 'react-router';
import bows from 'bows';
import moment from 'moment';
import { FastField, withFormik, useFormikContext } from 'formik';
import { Persist } from 'formik-persist';
import each from 'lodash/each';
import get from 'lodash/get';
import map from 'lodash/map';
import noop from 'lodash/noop';
import omit from 'lodash/omit';
import remove from 'lodash/remove';
import slice from 'lodash/slice';
import isEmpty from 'lodash/isEmpty';
import flattenDeep from 'lodash/flattenDeep';
import cloneDeep from 'lodash/cloneDeep';
import isUndefined from 'lodash/isUndefined';
import isInteger from 'lodash/isInteger';
import isArray from 'lodash/isArray';
import { utils as vizUtils } from '@tidepool/viz';

import { fieldsAreValid, getFieldsMeta } from '../../core/forms';
import prescriptionSchema from './prescriptionSchema';
import accountFormSteps from './accountFormSteps';
import profileFormSteps from './profileFormSteps';
import therapySettingsFormStep from './therapySettingsFormStep';
import reviewFormStep from './reviewFormStep';
import withPrescriptions from './withPrescriptions';
import Stepper from '../../components/elements/Stepper';

import {
  defaultUnits,
  defaultValues,
  stepValidationFields,
  validCountryCodes,
} from './prescriptionFormConstants';

const { TextUtil } = vizUtils.text;
const log = bows('PrescriptionForm');

export const prescriptionForm = (bgUnits = defaultUnits.bloodGlucose) => ({
  mapPropsToValues: props => ({
    id: get(props, 'prescription.id', ''),
    state: get(props, 'prescription.latestRevision.attributes.state', 'draft'),
    // type: get(props, 'prescription.latestRevision.attributes.type', ''),
    firstName: get(props, 'prescription.latestRevision.attributes.firstName', ''),
    lastName: get(props, 'prescription.latestRevision.attributes.lastName', ''),
    birthday: get(props, 'prescription.latestRevision.attributes.birthday', ''),
    email: get(props, 'prescription.latestRevision.attributes.email', ''),
    emailConfirm: get(props, 'prescription.latestRevision.attributes.email', ''),
    phoneNumber: {
      countryCode: get(props, 'prescription.latestRevision.attributes.phoneNumber.countryCode', validCountryCodes[0]),
      number: get(props, 'prescription.latestRevision.attributes.phoneNumber.number', ''),
    },
    mrn: get(props, 'prescription.latestRevision.attributes.mrn', ''),
    sex: get(props, 'prescription.latestRevision.attributes.sex', ''),
    initialSettings: {
      bloodGlucoseUnits: get(props, 'prescription.latestRevision.attributes.initialSettings.bloodGlucoseUnits', defaultUnits.bloodGlucose),
      pumpId: get(props, 'prescription.latestRevision.attributes.initialSettings.pumpId', ''),
      cgmId: get(props, 'prescription.latestRevision.attributes.initialSettings.cgmId', ''),
      // insulinModel: get(props, 'prescription.latestRevision.attributes.initialSettings.insulinModel', ''),
      // suspendThreshold: {
      //   value: get(props, 'prescription.latestRevision.attributes.initialSettings.suspendThreshold.value', ''),
      //   units: defaultUnits.suspendThreshold,
      // },
      basalRateMaximum: {
        value: get(props, 'prescription.latestRevision.attributes.initialSettings.basalRateMaximum.value', defaultValues(bgUnits).basalRateMaximum),
        units: defaultUnits.basalRate,
      },
      bolusAmountMaximum: {
        value: get(props, 'prescription.latestRevision.attributes.initialSettings.bolusAmountMaximum.value', defaultValues(bgUnits).bolusAmountMaximum),
        units: defaultUnits.bolusAmount,
      },
      bloodGlucoseTargetSchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.bloodGlucoseTargetSchedule', [{
        high: '',
        low: '',
        start: 0,
      }]),
      basalRateSchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.basalRateSchedule', [{
        rate: defaultValues(bgUnits).basalRate,
        start: 0,
      }]),
      carbohydrateRatioSchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.carbohydrateRatioSchedule', [{
        amount: '',
        start: 0,
      }]),
      insulinSensitivitySchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.insulinSensitivitySchedule', [{
        amount: '',
        start: 0,
      }]),
    },
    training: get(props, 'prescription.latestRevision.attributes.training', ''),
    therapySettingsReviewed: get(props, 'prescription.therapySettingsReviewed', false),
  }),
  validationSchema: props => prescriptionSchema(
    get(props, 'prescription.initialSettings.pumpId'),
    bgUnits
  ),
  displayName: 'PrescriptionForm',
});

export const PrescriptionForm = props => {
  const {
    t,
    createPrescription,
    createPrescriptionRevision,
    creatingPrescription,
    creatingPrescriptionRevision,
    prescription,
    trackMetric,
  } = props;

  const {
    getFieldMeta,
    handleSubmit,
    resetForm,
    setFieldValue,
    values,
  } = useFormikContext();

  const stepperId = 'prescription-form-steps';
  const bgUnits = get(values, 'initialSettings.bloodGlucoseUnits', defaultUnits.bloodGlucose);
  const pumpId = get(values, 'initialSettings.pumpId');
  const meta = getFieldsMeta(prescriptionSchema(pumpId, bgUnits), getFieldMeta);

  const asyncStates = {
    initial: { pending: false, complete: false },
    pending: { pending: true, complete: false },
    completed: { pending: false, complete: true },
  };

  const params = () => new URLSearchParams(location.search);
  const activeStepParamKey = `${stepperId}-step`;
  const activeStepsParam = params().get(activeStepParamKey);
  const storageKey = 'prescriptionForm';

  const [stepAsyncState, setStepAsyncState] = React.useState(asyncStates.initial);
  const [activeStep, setActiveStep] = React.useState(activeStepsParam ? activeStepsParam[0] : undefined);
  const [activeSubStep, setActiveSubStep] = React.useState(activeStepsParam ? activeStepsParam[1] : undefined);
  const [pendingStep, setPendingStep] = React.useState([]);
  const isSingleStepEdit = !!pendingStep.length;
  let isLastStep = activeStep === stepValidationFields.length - 1;

  // Determine the latest incomplete step, and default to starting there
  React.useEffect(() => {
    if (isUndefined(activeStep) || isUndefined(activeSubStep)) {
      let firstInvalidStep;
      let firstInvalidSubStep;
      let currentStep = 0;
      let currentSubStep = 0;

      while (isUndefined(firstInvalidStep) && currentStep < stepValidationFields.length) {
        while (currentSubStep < stepValidationFields[currentStep].length) {
          if (!fieldsAreValid(stepValidationFields[currentStep][currentSubStep], meta)) {
            firstInvalidStep = currentStep;
            firstInvalidSubStep = currentSubStep;
            break;
          }
          currentSubStep++
        }

        currentStep++;
        currentSubStep = 0;
      }

      setActiveStep(isInteger(firstInvalidStep) ? firstInvalidStep : 3);
      setActiveSubStep(isInteger(firstInvalidSubStep) ? firstInvalidSubStep : 0);
    }
  }, []);

  // Handle changes to stepper async state for completed prescription creation and revision updates
  React.useEffect(() => {
    const { inProgress, completed, prescriptionId } = get(values, 'id') ? creatingPrescriptionRevision : creatingPrescription;

    if (prescriptionId) setFieldValue('id', prescriptionId);

    if (!inProgress && completed) {
      setStepAsyncState(asyncStates.completed);
      if (isLastStep) {
        // TODO: Set a message to display as a toast on the prescriptions page
        browserHistory.push('/prescriptions');
      }
    }
  }, [creatingPrescription, creatingPrescriptionRevision]);

  const handlers = {
    activeStepUpdate: ([step, subStep], fromStep = []) => {
      setActiveStep(step);
      setActiveSubStep(subStep);
      setPendingStep(fromStep);
    },

    generateTherapySettingsText: (patientRows, therapySettingsRows) => {
      const textUtil = new TextUtil();

      let textString = textUtil.buildTextLine(t('Tidepool Loop therapy settings order'));

      textString += textUtil.buildTextLine(t('Exported from Tidepool: {{today}}', {
        today: moment().format('MMM D, YYYY'),
      }));

      textString += textUtil.buildTextLine('');

      textString += textUtil.buildTextLine(t('Patient Profile'));
      each(patientRows, row => textString += textUtil.buildTextLine(row));

      textString += textUtil.buildTextLine('');

      each(therapySettingsRows, row => {
        if (isArray(row.value)) {
          textString += textUtil.buildTextLine('');
          textString += textUtil.buildTextLine(row.label);
          each(row.value, value => textString += textUtil.buildTextLine(value));
        } else {
          textString += textUtil.buildTextLine(row);
        }
      });

      return textString;
    },

    handleCopyTherapySettingsClicked: () => {
      trackMetric('Clicked Copy Therapy Settings Order');
    },

    singleStepEditComplete: (cancelFieldUpdates) => {
      const advanceStep = false;

      if (cancelFieldUpdates) {
        resetForm();
      } else {
        resetForm({ values: cloneDeep(values) });
      }

      handlers.activeStepUpdate(pendingStep);

      return advanceStep;
    },

    stepSubmit: () => {
      setStepAsyncState(asyncStates.pending);
      // Delete fields that we never want to send to the backend
      const fieldsToDelete = ['emailConfirm', 'id', 'therapySettingsReviewed'];

      // Also delete any fields from future form steps if empty
      // We can't simply delete all future steps, as the clinician may have returned to the current
      // step via 'Back' button navigation and we don't want to lose existing data previously
      // entered in the later steps.
      if (!isLastStep) {
        const emptyFieldsInFutureSteps = remove(
          flattenDeep(slice(stepValidationFields, activeStep + 1)),
          fieldPath => isEmpty(get(values, fieldPath))
        );

        // Add empty future fields to the array of fieldpaths to delete.
        // N.B. There are some fieldpaths we check that end in '.value' or '.number'. If those keys
        // are empty, we exclude the parent object.
        fieldsToDelete.push(...map(
          emptyFieldsInFutureSteps,
          fieldPath => fieldPath.replace(/\.(value|number)$/, '')
        ));
      }

      const prescriptionAttributes = omit({ ...values }, fieldsToDelete);
      prescriptionAttributes.state = 'draft';

      if (values.id) {
        createPrescriptionRevision(prescriptionAttributes, values.id);
      } else {
        createPrescription(prescriptionAttributes);
      }
    },
  };

  const accountFormStepsProps = accountFormSteps(meta);
  const profileFormStepsProps = profileFormSteps(meta);
  const therapySettingsFormStepProps = therapySettingsFormStep(meta);
  const reviewFormStepProps = reviewFormStep(meta, handlers);

  const stepProps = step => ({
    ...step,
    completeText: isSingleStepEdit ? t('Update and Review') : step.completeText,
    backText: isSingleStepEdit ? t('Cancel Update') : step.backText,
    hideBack: isSingleStepEdit ? false : step.hideBack,
    disableBack: isSingleStepEdit ? false : step.disableBack,
    onComplete: isSingleStepEdit ? handlers.singleStepEditComplete : step.onComplete,
    onBack: isSingleStepEdit ? handlers.singleStepEditComplete.bind(null, true) : step.onBack,
  });

  const subStepProps = subSteps => map(subSteps, subStep => stepProps(subStep));

  const stepperProps = {
    activeStep,
    activeSubStep,
    'aria-label': t('New Prescription Form'),
    backText: t('Previous Step'),
    completeText: t('Save and Continue'),
    id: stepperId,
    onStepChange: (newStep) => {
      setStepAsyncState(asyncStates.initial);
      if (!isSingleStepEdit) handlers.activeStepUpdate(newStep);
      log('Step to', newStep.join(','));
    },
    steps: [
      {
        ...accountFormStepsProps,
        onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
        asyncState: isSingleStepEdit ? null : stepAsyncState,
        subSteps: subStepProps(accountFormStepsProps.subSteps),
      },
      {
        ...profileFormStepsProps,
        onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
        asyncState: isSingleStepEdit ? null : stepAsyncState,
        subSteps: subStepProps(profileFormStepsProps.subSteps),
      },
      {
        ...stepProps(therapySettingsFormStepProps),
        onComplete: isSingleStepEdit ? handlers.singleStepEditComplete : handlers.stepSubmit,
        asyncState: isSingleStepEdit ? null : stepAsyncState,
      },
      {
        ...reviewFormStepProps,
        onComplete: handlers.stepSubmit,
        asyncState: stepAsyncState,
      },
    ],
    themeProps: {
      wrapper: {
        mx: 3,
        my: 2,
        px: 2,
        py: 4,
        bg: 'white',
      },
      panel: {
        padding: 3,
      },
      actions: {
        justifyContent: 'center',
      }
    },
  };

  // When a user comes to this component initially, without the active step and subStep set by the
  // Stepper component in the url, we delete any persisted state from localStorage.
  // As well, when editing an existing prescription, we delete it so that the current prescription
  // values replace whatever values were previously stored
  if (prescription || (get(localStorage, storageKey) && activeStepsParam === null)) delete localStorage[storageKey];

  return (
    <form id="prescription-form" onSubmit={handleSubmit}>
      <FastField type="hidden" name="id" />
      {!isUndefined(activeStep) && <Stepper {...stepperProps} />}
      <Persist name={storageKey} />
    </form>
  );
};

PrescriptionForm.propTypes = {
  location: PropTypes.shape({
    pathname: PropTypes.string,
    search: PropTypes.string,
  }),
};

PrescriptionForm.defaultProps = {
  location: window.location,
};

export default withPrescriptions(withFormik(prescriptionForm())(translate()(PrescriptionForm)));
<commit_msg>Use passed-in location prop in prescription form stepper<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { browserHistory } from 'react-router';
import bows from 'bows';
import moment from 'moment';
import { FastField, withFormik, useFormikContext } from 'formik';
import { Persist } from 'formik-persist';
import each from 'lodash/each';
import get from 'lodash/get';
import map from 'lodash/map';
import noop from 'lodash/noop';
import omit from 'lodash/omit';
import remove from 'lodash/remove';
import slice from 'lodash/slice';
import isEmpty from 'lodash/isEmpty';
import flattenDeep from 'lodash/flattenDeep';
import cloneDeep from 'lodash/cloneDeep';
import isUndefined from 'lodash/isUndefined';
import isInteger from 'lodash/isInteger';
import isArray from 'lodash/isArray';
import { utils as vizUtils } from '@tidepool/viz';

import { fieldsAreValid, getFieldsMeta } from '../../core/forms';
import prescriptionSchema from './prescriptionSchema';
import accountFormSteps from './accountFormSteps';
import profileFormSteps from './profileFormSteps';
import therapySettingsFormStep from './therapySettingsFormStep';
import reviewFormStep from './reviewFormStep';
import withPrescriptions from './withPrescriptions';
import Stepper from '../../components/elements/Stepper';

import {
  defaultUnits,
  defaultValues,
  stepValidationFields,
  validCountryCodes,
} from './prescriptionFormConstants';

const { TextUtil } = vizUtils.text;
const log = bows('PrescriptionForm');

export const prescriptionForm = (bgUnits = defaultUnits.bloodGlucose) => ({
  mapPropsToValues: props => ({
    id: get(props, 'prescription.id', ''),
    state: get(props, 'prescription.latestRevision.attributes.state', 'draft'),
    // type: get(props, 'prescription.latestRevision.attributes.type', ''),
    firstName: get(props, 'prescription.latestRevision.attributes.firstName', ''),
    lastName: get(props, 'prescription.latestRevision.attributes.lastName', ''),
    birthday: get(props, 'prescription.latestRevision.attributes.birthday', ''),
    email: get(props, 'prescription.latestRevision.attributes.email', ''),
    emailConfirm: get(props, 'prescription.latestRevision.attributes.email', ''),
    phoneNumber: {
      countryCode: get(props, 'prescription.latestRevision.attributes.phoneNumber.countryCode', validCountryCodes[0]),
      number: get(props, 'prescription.latestRevision.attributes.phoneNumber.number', ''),
    },
    mrn: get(props, 'prescription.latestRevision.attributes.mrn', ''),
    sex: get(props, 'prescription.latestRevision.attributes.sex', ''),
    initialSettings: {
      bloodGlucoseUnits: get(props, 'prescription.latestRevision.attributes.initialSettings.bloodGlucoseUnits', defaultUnits.bloodGlucose),
      pumpId: get(props, 'prescription.latestRevision.attributes.initialSettings.pumpId', ''),
      cgmId: get(props, 'prescription.latestRevision.attributes.initialSettings.cgmId', ''),
      // insulinModel: get(props, 'prescription.latestRevision.attributes.initialSettings.insulinModel', ''),
      // suspendThreshold: {
      //   value: get(props, 'prescription.latestRevision.attributes.initialSettings.suspendThreshold.value', ''),
      //   units: defaultUnits.suspendThreshold,
      // },
      basalRateMaximum: {
        value: get(props, 'prescription.latestRevision.attributes.initialSettings.basalRateMaximum.value', defaultValues(bgUnits).basalRateMaximum),
        units: defaultUnits.basalRate,
      },
      bolusAmountMaximum: {
        value: get(props, 'prescription.latestRevision.attributes.initialSettings.bolusAmountMaximum.value', defaultValues(bgUnits).bolusAmountMaximum),
        units: defaultUnits.bolusAmount,
      },
      bloodGlucoseTargetSchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.bloodGlucoseTargetSchedule', [{
        high: '',
        low: '',
        start: 0,
      }]),
      basalRateSchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.basalRateSchedule', [{
        rate: defaultValues(bgUnits).basalRate,
        start: 0,
      }]),
      carbohydrateRatioSchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.carbohydrateRatioSchedule', [{
        amount: '',
        start: 0,
      }]),
      insulinSensitivitySchedule: get(props, 'prescription.latestRevision.attributes.initialSettings.insulinSensitivitySchedule', [{
        amount: '',
        start: 0,
      }]),
    },
    training: get(props, 'prescription.latestRevision.attributes.training', ''),
    therapySettingsReviewed: get(props, 'prescription.therapySettingsReviewed', false),
  }),
  validationSchema: props => prescriptionSchema(
    get(props, 'prescription.initialSettings.pumpId'),
    bgUnits
  ),
  displayName: 'PrescriptionForm',
});

export const PrescriptionForm = props => {
  const {
    t,
    createPrescription,
    createPrescriptionRevision,
    creatingPrescription,
    creatingPrescriptionRevision,
    location,
    prescription,
    trackMetric,
  } = props;

  const {
    getFieldMeta,
    handleSubmit,
    resetForm,
    setFieldValue,
    values,
  } = useFormikContext();

  const stepperId = 'prescription-form-steps';
  const bgUnits = get(values, 'initialSettings.bloodGlucoseUnits', defaultUnits.bloodGlucose);
  const pumpId = get(values, 'initialSettings.pumpId');
  const meta = getFieldsMeta(prescriptionSchema(pumpId, bgUnits), getFieldMeta);

  const asyncStates = {
    initial: { pending: false, complete: false },
    pending: { pending: true, complete: false },
    completed: { pending: false, complete: true },
  };

  const params = () => new URLSearchParams(location.search);
  const activeStepParamKey = `${stepperId}-step`;
  const activeStepsParam = params().get(activeStepParamKey);
  const storageKey = 'prescriptionForm';

  const [stepAsyncState, setStepAsyncState] = React.useState(asyncStates.initial);
  const [activeStep, setActiveStep] = React.useState(activeStepsParam ? activeStepsParam[0] : undefined);
  const [activeSubStep, setActiveSubStep] = React.useState(activeStepsParam ? activeStepsParam[1] : undefined);
  const [pendingStep, setPendingStep] = React.useState([]);
  const isSingleStepEdit = !!pendingStep.length;
  let isLastStep = activeStep === stepValidationFields.length - 1;

  // Determine the latest incomplete step, and default to starting there
  React.useEffect(() => {
    if (isUndefined(activeStep) || isUndefined(activeSubStep)) {
      let firstInvalidStep;
      let firstInvalidSubStep;
      let currentStep = 0;
      let currentSubStep = 0;

      while (isUndefined(firstInvalidStep) && currentStep < stepValidationFields.length) {
        while (currentSubStep < stepValidationFields[currentStep].length) {
          if (!fieldsAreValid(stepValidationFields[currentStep][currentSubStep], meta)) {
            firstInvalidStep = currentStep;
            firstInvalidSubStep = currentSubStep;
            break;
          }
          currentSubStep++
        }

        currentStep++;
        currentSubStep = 0;
      }

      setActiveStep(isInteger(firstInvalidStep) ? firstInvalidStep : 3);
      setActiveSubStep(isInteger(firstInvalidSubStep) ? firstInvalidSubStep : 0);
    }
  }, []);

  // Handle changes to stepper async state for completed prescription creation and revision updates
  React.useEffect(() => {
    const { inProgress, completed, prescriptionId } = get(values, 'id') ? creatingPrescriptionRevision : creatingPrescription;

    if (prescriptionId) setFieldValue('id', prescriptionId);

    if (!inProgress && completed) {
      setStepAsyncState(asyncStates.completed);
      if (isLastStep) {
        // TODO: Set a message to display as a toast on the prescriptions page
        browserHistory.push('/prescriptions');
      }
    }
  }, [creatingPrescription, creatingPrescriptionRevision]);

  const handlers = {
    activeStepUpdate: ([step, subStep], fromStep = []) => {
      setActiveStep(step);
      setActiveSubStep(subStep);
      setPendingStep(fromStep);
    },

    generateTherapySettingsText: (patientRows, therapySettingsRows) => {
      const textUtil = new TextUtil();

      let textString = textUtil.buildTextLine(t('Tidepool Loop therapy settings order'));

      textString += textUtil.buildTextLine(t('Exported from Tidepool: {{today}}', {
        today: moment().format('MMM D, YYYY'),
      }));

      textString += textUtil.buildTextLine('');

      textString += textUtil.buildTextLine(t('Patient Profile'));
      each(patientRows, row => textString += textUtil.buildTextLine(row));

      textString += textUtil.buildTextLine('');

      each(therapySettingsRows, row => {
        if (isArray(row.value)) {
          textString += textUtil.buildTextLine('');
          textString += textUtil.buildTextLine(row.label);
          each(row.value, value => textString += textUtil.buildTextLine(value));
        } else {
          textString += textUtil.buildTextLine(row);
        }
      });

      return textString;
    },

    handleCopyTherapySettingsClicked: () => {
      trackMetric('Clicked Copy Therapy Settings Order');
    },

    singleStepEditComplete: (cancelFieldUpdates) => {
      const advanceStep = false;

      if (cancelFieldUpdates) {
        resetForm();
      } else {
        resetForm({ values: cloneDeep(values) });
      }

      handlers.activeStepUpdate(pendingStep);

      return advanceStep;
    },

    stepSubmit: () => {
      setStepAsyncState(asyncStates.pending);
      // Delete fields that we never want to send to the backend
      const fieldsToDelete = ['emailConfirm', 'id', 'therapySettingsReviewed'];

      // Also delete any fields from future form steps if empty
      // We can't simply delete all future steps, as the clinician may have returned to the current
      // step via 'Back' button navigation and we don't want to lose existing data previously
      // entered in the later steps.
      if (!isLastStep) {
        const emptyFieldsInFutureSteps = remove(
          flattenDeep(slice(stepValidationFields, activeStep + 1)),
          fieldPath => isEmpty(get(values, fieldPath))
        );

        // Add empty future fields to the array of fieldpaths to delete.
        // N.B. There are some fieldpaths we check that end in '.value' or '.number'. If those keys
        // are empty, we exclude the parent object.
        fieldsToDelete.push(...map(
          emptyFieldsInFutureSteps,
          fieldPath => fieldPath.replace(/\.(value|number)$/, '')
        ));
      }

      const prescriptionAttributes = omit({ ...values }, fieldsToDelete);
      prescriptionAttributes.state = 'draft';

      if (values.id) {
        createPrescriptionRevision(prescriptionAttributes, values.id);
      } else {
        createPrescription(prescriptionAttributes);
      }
    },
  };

  const accountFormStepsProps = accountFormSteps(meta);
  const profileFormStepsProps = profileFormSteps(meta);
  const therapySettingsFormStepProps = therapySettingsFormStep(meta);
  const reviewFormStepProps = reviewFormStep(meta, handlers);

  const stepProps = step => ({
    ...step,
    completeText: isSingleStepEdit ? t('Update and Review') : step.completeText,
    backText: isSingleStepEdit ? t('Cancel Update') : step.backText,
    hideBack: isSingleStepEdit ? false : step.hideBack,
    disableBack: isSingleStepEdit ? false : step.disableBack,
    onComplete: isSingleStepEdit ? handlers.singleStepEditComplete : step.onComplete,
    onBack: isSingleStepEdit ? handlers.singleStepEditComplete.bind(null, true) : step.onBack,
  });

  const subStepProps = subSteps => map(subSteps, subStep => stepProps(subStep));

  const stepperProps = {
    activeStep,
    activeSubStep,
    'aria-label': t('New Prescription Form'),
    backText: t('Previous Step'),
    completeText: t('Save and Continue'),
    id: stepperId,
    location,
    onStepChange: (newStep) => {
      setStepAsyncState(asyncStates.initial);
      if (!isSingleStepEdit) handlers.activeStepUpdate(newStep);
      log('Step to', newStep.join(','));
    },
    steps: [
      {
        ...accountFormStepsProps,
        onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
        asyncState: isSingleStepEdit ? null : stepAsyncState,
        subSteps: subStepProps(accountFormStepsProps.subSteps),
      },
      {
        ...profileFormStepsProps,
        onComplete: isSingleStepEdit ? noop : handlers.stepSubmit,
        asyncState: isSingleStepEdit ? null : stepAsyncState,
        subSteps: subStepProps(profileFormStepsProps.subSteps),
      },
      {
        ...stepProps(therapySettingsFormStepProps),
        onComplete: isSingleStepEdit ? handlers.singleStepEditComplete : handlers.stepSubmit,
        asyncState: isSingleStepEdit ? null : stepAsyncState,
      },
      {
        ...reviewFormStepProps,
        onComplete: handlers.stepSubmit,
        asyncState: stepAsyncState,
      },
    ],
    themeProps: {
      wrapper: {
        mx: 3,
        my: 2,
        px: 2,
        py: 4,
        bg: 'white',
      },
      panel: {
        padding: 3,
      },
      actions: {
        justifyContent: 'center',
      }
    },
  };

  // When a user comes to this component initially, without the active step and subStep set by the
  // Stepper component in the url, we delete any persisted state from localStorage.
  // As well, when editing an existing prescription, we delete it so that the current prescription
  // values replace whatever values were previously stored
  if (prescription || (get(localStorage, storageKey) && activeStepsParam === null)) delete localStorage[storageKey];

  return (
    <form id="prescription-form" onSubmit={handleSubmit}>
      <FastField type="hidden" name="id" />
      {!isUndefined(activeStep) && <Stepper {...stepperProps} />}
      <Persist name={storageKey} />
    </form>
  );
};

PrescriptionForm.propTypes = {
  location: PropTypes.shape({
    pathname: PropTypes.string,
    search: PropTypes.string,
  }),
};

PrescriptionForm.defaultProps = {
  location: window.location,
};

export default withPrescriptions(withFormik(prescriptionForm())(translate()(PrescriptionForm)));
<|endoftext|>


<commit_before>include('../view.js');
include('observable.js');

/**
 * @class
 */
uki.view.Focusable = new function() {/** @lends uki.view.Focusable.prototype */

    // dom: function() {
    //     return null; // should implement
    // },
    this._focusable = true; // default value
    this._focusOnClick = true;

    this.focusOnClick = uki.newProp('_focusOnClick');

    this.focusable = uki.newProp('_focusable', function(v) {
        this._focusable = v;
        if (v) this._initFocusable();
        this._updateFocusable();
    }),

    this.disabled = uki.newProp('_disabled', function(d) {
        this._disabled = d;
        if (d) this.blur();
        this._updateFocusable();
        if (this._updateBg) this._updateBg();
    }),

    this._updateFocusable = function() {
        if (this._preCreatedFocusTarget) return;

        if (this._focusable && !this._disabled) {
            this._focusTarget.style.display = 'block';
        } else {
            this._focusTarget.style.display = 'none';
        }
    },

    this._initFocusable = function(preCreatedFocusTarget) {
        if ((!preCreatedFocusTarget && !this._focusable) || this._focusTarget) return;
        this._focusTarget = preCreatedFocusTarget;
        this._preCreatedFocusTarget = preCreatedFocusTarget;

        if (!preCreatedFocusTarget) {
            this._focusTarget = uki.createElement('input', 'position:absolute;left:-9999px;top:0;width:1px;height:1px;');
            this.dom().appendChild(this._focusTarget);
        }
        this._hasFocus = false;
        this._firstFocus = true;

        uki.dom.bind(this._focusTarget, 'focus', uki.proxy(function(e) {
            if (!this._hasFocus) this._focus(e);
        }, this));

        uki.dom.bind(this._focusTarget, 'blur', uki.proxy(function(e) {
            if (this._hasFocus) {
                this._hasFocus = false;
                setTimeout(uki.proxy(function() { // wait for mousedown refocusing
                    if (!this._hasFocus) this._blur(e);
                }, this),1);
            }
        }, this));

        if (!preCreatedFocusTarget) this.bind('mousedown', function(e) {
            if (this._focusOnClick) {
                if (this._focusable && !this._disabled && !this._hasFocus) this._focus();
                setTimeout(uki.proxy(this.focus, this), 1);
            }
        });
        this._updateFocusable();
    }

    this._focus = function(e) {
        this._hasFocus = true;
        this._firstFocus = false;
    }

    this._blur = function(e) {
        this._hasFocus = false;
    }

    this.focus = function() {
        try {
            if (this._focusable && !this._disabled) {
                this._focusTarget.focus();
            }
        } catch(e) {}
        return this;
    },

    this.blur = function() {
        try {
            this._focusTarget.blur();
        } catch(e) {}
        return this;
    }

    this.hasFocus = function() {
        return this._hasFocus;
    }

    this._bindToDom = function(name) {
        if (!this._focusTarget || 'keyup keydown keypress focus blur'.indexOf(name) == -1) return false;

        return uki.view.Observable._bindToDom.call(this, name, this._focusTarget);
    }

};<commit_msg>update bg only if disabled changed, moved focusing code to focus<commit_after>include('../view.js');
include('observable.js');

/**
 * @class
 */
uki.view.Focusable = new function() {/** @lends uki.view.Focusable.prototype */

    // dom: function() {
    //     return null; // should implement
    // },
    this._focusable = true; // default value
    this._focusOnClick = true;

    this.focusOnClick = uki.newProp('_focusOnClick');

    this.focusable = uki.newProp('_focusable', function(v) {
        this._focusable = v;
        if (v) this._initFocusable();
        this._updateFocusable();
    }),

    this.disabled = uki.newProp('_disabled', function(d) {
        var changed = d !== !!this._disabled;
        this._disabled = d;
        if (d) this.blur();
        this._updateFocusable();
        if (changed && this._updateBg) this._updateBg();
    }),

    this._updateFocusable = function() {
        if (this._preCreatedFocusTarget || !this._focusTarget) return;

        if (this._focusable && !this._disabled) {
            this._focusTarget.style.display = 'block';
        } else {
            this._focusTarget.style.display = 'none';
        }
    },

    this._initFocusable = function(preCreatedFocusTarget) {
        if ((!preCreatedFocusTarget && !this._focusable) || this._focusTarget) return;
        this._focusTarget = preCreatedFocusTarget;
        this._preCreatedFocusTarget = preCreatedFocusTarget;

        if (!preCreatedFocusTarget) {
            this._focusTarget = uki.createElement('input', 'position:absolute;left:-9999px;top:0;width:1px;height:1px;');
            this.dom().appendChild(this._focusTarget);
        }
        this._hasFocus = false;
        this._firstFocus = true;

        uki.dom.bind(this._focusTarget, 'focus', uki.proxy(function(e) {
            if (!this._hasFocus) this._focus(e);
        }, this));

        uki.dom.bind(this._focusTarget, 'blur', uki.proxy(function(e) {
            if (this._hasFocus) {
                this._hasFocus = false;
                setTimeout(uki.proxy(function() { // wait for mousedown refocusing
                    if (!this._hasFocus) this._blur(e);
                }, this), 1);
            }
        }, this));

        if (!preCreatedFocusTarget) this.bind('mousedown', function(e) {
            if (this._focusOnClick) this.focus();
        });
        this._updateFocusable();
    }

    this._focus = function(e) {
        this._hasFocus = true;
        this._firstFocus = false;
    }

    this._blur = function(e) {
        this._hasFocus = false;
    }

    this.focus = function() {
        try {
            if (this._focusable && !this._disabled && !this._hasFocus) this._focus();
            setTimeout(uki.proxy(this._focusTarget.focus, this._focusTarget), 1);
        } catch(e) {}
        return this;
    },

    this.blur = function() {
        try {
            this._focusTarget.blur();
        } catch(e) {}
        return this;
    }

    this.hasFocus = function() {
        return this._hasFocus;
    }

    this._bindToDom = function(name) {
        if (!this._focusTarget || 'keyup keydown keypress focus blur'.indexOf(name) == -1) return false;

        return uki.view.Observable._bindToDom.call(this, name, this._focusTarget);
    }

};<|endoftext|>


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

  angular.module('involved', ['ngResource'])
    .run(function($rootScope, $timeout, github, repo) {
      github.me();

      $rootScope.$on('myProfileReceived', function(event, profile) {
        $timeout(function() {
          $rootScope.me = profile;
        }, 0);
      });

      // temporary
      repo.watch({owner: 'strongloop', repo: 'express'});
      repo.watch({owner: 'summernote', repo: 'summernote'});
      repo.watch({owner: 'Automattic', repo: 'socket.io'});
      repo.watch({owner: 'nodejs', repo: 'io.js'});
      repo.watch({owner: 'angular', repo: 'angular.js'});
      repo.watch({owner: 'facebook', repo: 'react'});
      repo.watch({owner: 'rails', repo: 'rails'});
      repo.watch({owner: 'antirez', repo: 'redis'});
      repo.watch({owner: 'bower', repo: 'bower'});
    });

  // controllers
  angular.module('involved')
    .controller('TimelineCtrl', function($scope, $timeout, repo) {
      var loadingMore = false;
      $scope.timeline = [];
      repo.timeline();

      $scope.$on('timelineReceived', function(event, list) {
        loadingMore = false;
        $timeout(function() {
          $scope.timeline = $scope.timeline.concat(list);
        }, 0);
      });

      $scope.loadMore = function() {
        loadingMore = true;
        var lastId = $scope.timeline[$scope.timeline.length - 1].id;
        repo.timeline(lastId);
      };

      $scope.showEvent = function(evt) {
        $scope.detail = evt;
      };

      $scope.state= function(status) {
        return 'state-' + status;
      };
    });

  // directives
  angular.module('involved')
    .directive('whenScrolled', function() {
      return function(scope, elem, attr) {
        var raw = elem[0];
        elem.on('scroll', function() {
          if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
            scope.$apply(attr.whenScrolled);
          }
        });
      };
    });

  // services
  var ipc = require('ipc');
  angular.module('involved')
    .factory('github', function($rootScope) {
      ipc.on('github.me', function(profile) {
        $rootScope.$broadcast('myProfileReceived', profile);
      });

      ipc.on('github.emojis', function(emojis) {
        $rootScope.$broadcast('emojisReceived', emojis);
      });

      return {
        me: function() {
          ipc.send('github.me');
        },
        emojis: function() {
          ipc.send('github.emojis');
        }
      };
    })
    .factory('repo', function($rootScope) {
      ipc.on('repo.timeline', function(list) {
        $rootScope.$broadcast('timelineReceived', list);
      });

      return {
        watch: function(p) {
          return ipc.sendSync('repo.watch', p);
        },
        unwatch: function(p) {
          return ipc.sendSync('repo.unwatch', p);
        },
        timeline: function(since) {
          ipc.send('repo.timeline', since);
        }
      };
    })
    .factory('markdown', function($rootScope, github) {
      var md = window.markdownit(),
          list;

      github.emojis();
      $rootScope.$on('emojisReceived', function(event, emojis) {
        list = emojis

        if (!md.renderer.rules.emoji) { md.use(window.markdownitEmoji);  }
        md.renderer.rules.emoji = function(token, idx) {
          var code = token[idx].markup;
          return '';
        };
      });

      return md;
    });

  // filters
  angular.module('involved')
    .filter('fromNow', function() {
      return function(date) { return moment(date).fromNow(); };
    })
    .filter('removeRef', function() {
      return function(ref) { return ref.replace('refs/heads/', ''); };
    })
    .filter('shortSha', function() {
      return function(sha, length) {
        length = length || 7;
        return sha ? sha.substr(0, length) : sha;
      };
    })
    .filter('md', function($sce, markdown) {
      return function(text) { return $sce.trustAsHtml(markdown.render(text)); };
    });
})();
<commit_msg>print default message when rendering markdown<commit_after>(function() {
  'use strict';

  angular.module('involved', ['ngResource'])
    .run(function($rootScope, $timeout, github, repo) {
      github.me();

      $rootScope.$on('myProfileReceived', function(event, profile) {
        $timeout(function() {
          $rootScope.me = profile;
        }, 0);
      });

      // temporary
      repo.watch({owner: 'strongloop', repo: 'express'});
      repo.watch({owner: 'summernote', repo: 'summernote'});
      repo.watch({owner: 'Automattic', repo: 'socket.io'});
      repo.watch({owner: 'nodejs', repo: 'io.js'});
      repo.watch({owner: 'angular', repo: 'angular.js'});
      repo.watch({owner: 'facebook', repo: 'react'});
      repo.watch({owner: 'rails', repo: 'rails'});
      repo.watch({owner: 'antirez', repo: 'redis'});
      repo.watch({owner: 'bower', repo: 'bower'});
    });

  // controllers
  angular.module('involved')
    .controller('TimelineCtrl', function($scope, $timeout, repo) {
      var loadingMore = false;
      $scope.timeline = [];
      repo.timeline();

      $scope.$on('timelineReceived', function(event, list) {
        loadingMore = false;
        $timeout(function() {
          $scope.timeline = $scope.timeline.concat(list);
        }, 0);
      });

      $scope.loadMore = function() {
        loadingMore = true;
        var lastId = $scope.timeline[$scope.timeline.length - 1].id;
        repo.timeline(lastId);
      };

      $scope.showEvent = function(evt) {
        $scope.detail = evt;
      };

      $scope.state= function(status) {
        return 'state-' + status;
      };
    });

  // directives
  angular.module('involved')
    .directive('whenScrolled', function() {
      return function(scope, elem, attr) {
        var raw = elem[0];
        elem.on('scroll', function() {
          if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
            scope.$apply(attr.whenScrolled);
          }
        });
      };
    });

  // services
  var ipc = require('ipc');
  angular.module('involved')
    .factory('github', function($rootScope) {
      ipc.on('github.me', function(profile) {
        $rootScope.$broadcast('myProfileReceived', profile);
      });

      ipc.on('github.emojis', function(emojis) {
        $rootScope.$broadcast('emojisReceived', emojis);
      });

      return {
        me: function() {
          ipc.send('github.me');
        },
        emojis: function() {
          ipc.send('github.emojis');
        }
      };
    })
    .factory('repo', function($rootScope) {
      ipc.on('repo.timeline', function(list) {
        $rootScope.$broadcast('timelineReceived', list);
      });

      return {
        watch: function(p) {
          return ipc.sendSync('repo.watch', p);
        },
        unwatch: function(p) {
          return ipc.sendSync('repo.unwatch', p);
        },
        timeline: function(since) {
          ipc.send('repo.timeline', since);
        }
      };
    })
    .factory('markdown', function($rootScope, github) {
      var md = window.markdownit(),
          list;

      github.emojis();
      $rootScope.$on('emojisReceived', function(event, emojis) {
        list = emojis

        if (!md.renderer.rules.emoji) { md.use(window.markdownitEmoji);  }
        md.renderer.rules.emoji = function(token, idx) {
          var code = token[idx].markup;
          return '';
        };
      });

      return md;
    });

  // filters
  angular.module('involved')
    .filter('fromNow', function() {
      return function(date) { return moment(date).fromNow(); };
    })
    .filter('removeRef', function() {
      return function(ref) { return ref.replace('refs/heads/', ''); };
    })
    .filter('shortSha', function() {
      return function(sha, length) {
        length = length || 7;
        return sha ? sha.substr(0, length) : sha;
      };
    })
    .filter('md', function($sce, markdown) {
      return function(text) {
        if (text && text.trim() !== '') {
          return $sce.trustAsHtml(markdown.render(text));
        } else {
          return $sce.trustAsHtml('
No description provided.
');
        }
      };
    });
})();
<|endoftext|>


<commit_before>function createHash(data, key) {
    var hash = {};
    for (var i in data) {
        var v = data[i];
        var kv = v[key];
        hash["row" + kv] = v;

    }
    return hash;
}
function CreateMapForData(dataSource, adminUnitInfo, renderingInfo) {
  /*  dataSource = { url: "", indicator: "", postData: {} };
    adminUnitInfo = { level: "Region" };
    renderingInfo = { shadingOption: {}, div: "" };
    */
    console.log("CreateMapForData", dataSource);

    var drawDatayMap = function (data)
    {
        var key = "AdminUnitID";
        key = "code";
        var indicator = dataSource.indicator;
        var dataTable = createHash(data, key);

        normalizeIndicator(dataTable, indicator);
        ShowLegend(renderingInfo.shadingOption, renderingInfo.div + "Legend", dataTable, indicator, renderingInfo.div + "Legend");
        console.log("drawDatayMap", dataTable);
        var shapeFile = adminUnitInfo.shapeFile;
        if (!shapeFile) {
            var shapeFiles = {
                                Region: "ethiopiaRegions2.txt"
                                , Zone: "AllZones.txt"
                             };
            shapeFile = shapeFiles[adminUnitInfo.level];
        }
        var shapeURL = "/Content/MapResources/MapData/"+shapeFile;

        var mapLayer =
            [
                { name: adminUnitInfo.level, url: shapeURL, style: getPolygonShadingStyle(key, dataTable, indicator, renderingInfo.shadingOption) }
            ];
        CreateMap(renderingInfo.div, { layers: mapLayer });
    }

    $.post(dataSource.url, dataSource.postData, function (data) {
        console.log("CreateMapForData", "data-fetched", data);

        drawDatayMap(data.Data);

    });
 //

}
function CreateMap(div, _options) {
    var options = {};
    options=$.extend(options, _options);
    var map, draw, modify, snap, point, line, poly;

    map = new OpenLayers.Map(div, {
        controls: [new OpenLayers.Control.Navigation(), new OpenLayers.Control.PanZoomBar(),new OpenLayers.Control.ScaleLine()]});
    map.addControl(new OpenLayers.Control.MousePosition());

   var base= new OpenLayers.Layer.Vector("Base", {
        strategies: [new OpenLayers.Strategy.Fixed()],
        protocol: new OpenLayers.Protocol.HTTP({ url: "/Content/MapResources/MapData/ethiopiaJson.js", format: new OpenLayers.Format.GeoJSON() }),
        isBaseLayer: true
   });
   map.addLayer(base);
   var mapLayers={};
   isBaseLayer = false;
    if (options) {
        if (options.layers) {
            //var isBaseLayer = true;
            for (var i in options.layers) {

                var layerData = options.layers[i];
                //layerData=$.extend(layerData, options.layers[i]);
               // console.log("Layer : ", layerData);
                var styleMap = layerData.styleMap;
                if (!styleMap) {
                    styleMap = createStyle(layerData.style ? layerData.style : {});
                }
                /*
                var layer = new OpenLayers.Layer.Vector(layerData.name, {
                    strategies: [new OpenLayers.Strategy.Fixed()],
                    //protocol: new OpenLayers.Protocol.HTTP({ url: layerData.url, format: new OpenLayers.Format.GeoJSON() }),
                    isBaseLayer: isBaseLayer,
                    styleMap: styleMap
                });
                */
                var layer = new OpenLayers.Layer.Vector(layerData.name, { styleMap: styleMap });
                mapLayers[i]=layer;
                map.addLayer(layer);
                if (!isBaseLayer) {
                    addSelectControl(map, layer)
                }
                isBaseLayer = false;
               /* $.get(layerData.url, function (data) {
                    console.log("Feature downloaded",data);
                    deserialize(data,map,layer);
                });
                */
                var jqxhr = $.get(layerData.url, {})
  .done(function (data) {
      console.log("second success");
      deserialize(data, map, layer);
  })
  .fail(function (data) {
     // console.log("error",data);
  })
  .always(function () {
      //alert("finished");
  });

            }
        }

    }
    // map.setCenter(new OpenLayers.LonLat(39, 9), 5);

    //map.zoomToMaxExtent();
    return { map: map, layers: mapLayers };
}
function addSelectControl(map, layer) {
    console.log("addSelectControl");
    selectControl = new OpenLayers.Control.SelectFeature(layer);
    map.addControl(selectControl);
    selectControl.activate();
    layer.events.on({
        'featureselected': function () { console.log("feature selected");},
        'featureunselected': function () { }
    });
}
function normalizeIndicator(data, fld) {
    var hasRows = 0;
    var maxVal = -999999;
    var minVal = 99999999999999;
    for (var i in data) {
        var indVal = data[i][fld];
        maxVal = Math.max(maxVal, indVal);
        minVal = Math.min(minVal, indVal);
        hasRows = 1;
    }
    for (var i in data) {
        var indVal = data[i][fld];
        data[i][fld + "normalized"] = (indVal-minVal) / (maxVal-minVal);
    }
    data.minVal = minVal;
    data.maxVal = maxVal;
    return data;
}
function addLayers(map, layers) {

}
function createShadedMap(div, _options) {
    var options = { dataTable: [], key: "", indicator: "", url: "" };
    CreateMap("map2", { layers: layers2 });
}
function deserialize(text, map, layer) {
    var projection="EPSG:4326";// lon,lat in degrees.
    var projection = "EPSG:900913";
    //console.log("deserialize ", text);
    var in_options = { "internalProjection": map.baseLayer.projection, "externalProjection": new OpenLayers.Projection(projection) };
    var geojson= new OpenLayers.Format.GeoJSON(in_options)

    //var element = document.getElementById('text');
    //var type = document.getElementById("formatType").value;
// var features = formats['in'][type].read(text);
    var features = geojson.read(text);
    var bounds;
    if (features) {
        if (features.constructor != Array) {
            features = [features];
        }
        for (var i = 0; i < features.length; ++i) {
            if (!bounds) {
                bounds = features[i].geometry.getBounds();
            } else {
                bounds.extend(features[i].geometry.getBounds());
            }

        }
        layer.addFeatures(features);
        map.zoomToExtent(bounds);
        var plural = (features.length > 1) ? 's' : '';
        //element.value = features.length + ' feature' + plural + ' added';
    } else {
       // element.value = 'Bad input ' + type;
    }
}<commit_msg>Mapping suggestion auto generate on select event.<commit_after>function createHash(data, key) {
    var hash = {};
    for (var i in data) {
        var v = data[i];
        var kv = v[key];
        hash["row" + kv] = v;

    }
    return hash;
}
function CreateMapForData(dataSource, adminUnitInfo, renderingInfo) {
  /*  dataSource = { url: "", indicator: "", postData: {} };
    adminUnitInfo = { level: "Region" };
    renderingInfo = { shadingOption: {}, div: "" };
    */
    console.log("CreateMapForData", dataSource);

    var drawDatayMap = function (data)
    {
        var key = "AdminUnitID";
        key = "code";
        var indicator = dataSource.indicator;
        var dataTable = createHash(data, key);

        normalizeIndicator(dataTable, indicator);
        ShowLegend(renderingInfo.shadingOption, renderingInfo.div + "Legend", dataTable, indicator, renderingInfo.div + "Legend");
        console.log("drawDatayMap", dataTable);
        var shapeFile = adminUnitInfo.shapeFile;
        if (!shapeFile) {
            var shapeFiles = {
                                Region: "ethiopiaRegions2.txt"
                                , Zone: "AllZones.txt"
                             };
            shapeFile = shapeFiles[adminUnitInfo.level];
        }
        var shapeURL = "/Content/MapResources/MapData/"+shapeFile;

        var mapLayer =
            [
                { name: adminUnitInfo.level, url: shapeURL, style: getPolygonShadingStyle(key, dataTable, indicator, renderingInfo.shadingOption) }
            ];
        CreateMap(renderingInfo.div, { layers: mapLayer });
    }

    $.post(dataSource.url, dataSource.postData, function (data) {
        console.log("CreateMapForData", "data-fetched", data);

        drawDatayMap(data.Data);

    });
 //

}
function CreateMap(div, _options) {
    var options = {};
    options=$.extend(options, _options);
    var map, draw, modify, snap, point, line, poly;

    map = new OpenLayers.Map(div, {
        controls: [new OpenLayers.Control.Navigation(), new OpenLayers.Control.PanZoomBar(),new OpenLayers.Control.ScaleLine()]});
    map.addControl(new OpenLayers.Control.MousePosition());

   var base= new OpenLayers.Layer.Vector("Base", {
        strategies: [new OpenLayers.Strategy.Fixed()],
        protocol: new OpenLayers.Protocol.HTTP({ url: "/Content/MapResources/MapData/ethiopiaJson.js", format: new OpenLayers.Format.GeoJSON() }),
        isBaseLayer: true
   });
   map.addLayer(base);
   var mapLayers={};
   isBaseLayer = false;
    if (options) {
        if (options.layers) {
            //var isBaseLayer = true;
            for (var i in options.layers) {

                var layerData = options.layers[i];
                //layerData=$.extend(layerData, options.layers[i]);
               // console.log("Layer : ", layerData);
                var styleMap = layerData.styleMap;
                if (!styleMap) {
                    styleMap = createStyle(layerData.style ? layerData.style : {});
                }
                /*
                var layer = new OpenLayers.Layer.Vector(layerData.name, {
                    strategies: [new OpenLayers.Strategy.Fixed()],
                    //protocol: new OpenLayers.Protocol.HTTP({ url: layerData.url, format: new OpenLayers.Format.GeoJSON() }),
                    isBaseLayer: isBaseLayer,
                    styleMap: styleMap
                });
                */
                var layer = new OpenLayers.Layer.Vector(layerData.name, { styleMap: styleMap });
                mapLayers[i]=layer;
                map.addLayer(layer);

                if (!isBaseLayer) {
                    addSelectControl(map, layer, options.selectionCallback)
                }
                isBaseLayer = false;
               /* $.get(layerData.url, function (data) {
                    console.log("Feature downloaded",data);
                    deserialize(data,map,layer);
                });
                */
                var jqxhr = $.get(layerData.url, {})
  .done(function (data) {
      console.log("second success");
      deserialize(data, map, layer);
  })
  .fail(function (data) {
     // console.log("error",data);
  })
  .always(function () {
      //alert("finished");
  });

            }
        }

    }
    // map.setCenter(new OpenLayers.LonLat(39, 9), 5);

    //map.zoomToMaxExtent();
    return { map: map, layers: mapLayers };
}
function addSelectControl(map, layer,cb) {
    console.log("addSelectControl");
    selectControl = new OpenLayers.Control.SelectFeature(layer);
    map.addControl(selectControl);
    selectControl.activate();
    layer.events.on({
        'featureselected': function (feature)
        {
            console.log("feature selected");
            if (cb)
            {
                cb(feature, 'featureselected')
            }
        },
        'featureunselected': function (feature)
        {
            console.log("feature featureunselected");
            if (cb) {
                cb(feature, 'featureunselected')
            }
        }
    });
}
function normalizeIndicator(data, fld) {
    var hasRows = 0;
    var maxVal = -999999;
    var minVal = 99999999999999;
    for (var i in data) {
        var indVal = data[i][fld];
        maxVal = Math.max(maxVal, indVal);
        minVal = Math.min(minVal, indVal);
        hasRows = 1;
    }
    for (var i in data) {
        var indVal = data[i][fld];
        data[i][fld + "normalized"] = (indVal-minVal) / (maxVal-minVal);
    }
    data.minVal = minVal;
    data.maxVal = maxVal;
    return data;
}
function addLayers(map, layers) {

}
function createShadedMap(div, _options) {
    var options = { dataTable: [], key: "", indicator: "", url: "" };
    CreateMap("map2", { layers: layers2 });
}
function deserialize(text, map, layer) {
    var projection="EPSG:4326";// lon,lat in degrees.
    var projection = "EPSG:900913";
    //console.log("deserialize ", text);
    var in_options = { "internalProjection": map.baseLayer.projection, "externalProjection": new OpenLayers.Projection(projection) };
    var geojson= new OpenLayers.Format.GeoJSON(in_options)

    //var element = document.getElementById('text');
    //var type = document.getElementById("formatType").value;
// var features = formats['in'][type].read(text);
    var features = geojson.read(text);
    var bounds;
    if (features) {
        if (features.constructor != Array) {
            features = [features];
        }
        for (var i = 0; i < features.length; ++i) {
            if (!bounds) {
                bounds = features[i].geometry.getBounds();
            } else {
                bounds.extend(features[i].geometry.getBounds());
            }

        }
        layer.addFeatures(features);
        map.zoomToExtent(bounds);
        var plural = (features.length > 1) ? 's' : '';
        //element.value = features.length + ' feature' + plural + ' added';
    } else {
       // element.value = 'Bad input ' + type;
    }
}<|endoftext|>


<commit_before>/**
 * @author: @AngularClass
 */

const webpack = require('webpack');
const helpers = require('./helpers');
const ngtools = require('@ngtools/webpack');
const branding = require('./branding');
var path = require('path');
var stringify = require('json-stringify');

/*
 * Webpack Plugins
 */
const autoprefixer = require('autoprefixer');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const IgnorePlugin = require('webpack/lib/IgnorePlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
// const ngcWebpack = require('ngc-webpack');
const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
// const TsConfigPathsPlugin = require('awesome-typescript-loader');

/*
 * Webpack Constants
 */
// const HMR = helpers.hasProcessFlag('hot');
// const AOT = helpers.hasNpmFlag('aot');
const METADATA = {
  baseUrl: '/',
  isDevServer: helpers.isWebpackDevServer(),
  FABRIC8_BRANDING: process.env.FABRIC8_BRANDING || 'fabric8'
};

/*
 * Webpack configuration
 *
 * See: http://webpack.github.io/docs/configuration.html#cli
 */
module.exports = function (options) {
  const isProd = options.env === 'production';
  const aotMode = false;//options && options.aot !== undefined;
  console.log('The options from the webpack config: ' + stringify(options, null, 2));

  // ExtractTextPlugin
  const extractCSS = new ExtractTextPlugin({
    filename: '_assets/stylesheets/[name].[id]' + ( isProd ? '.[contenthash]' : '' ) + '.css'
  });

  // const entryFile = aotMode ? './src/main.browser.aot.ts' : './src/main.browser.ts';
  // const outPath = aotMode ? 'dist' : 'aot';
  // const devtool = aotMode ? 'source-map' : 'eval-source-map';
  // const srcPath = path.join(__dirname, 'demo', 'src');
  var config = {

    /*
     * Cache generated modules and chunks to improve performance for multiple incremental builds.
     * This is enabled by default in watch mode.
     * You can pass false to disable it.
     *
     * See: http://webpack.github.io/docs/configuration.html#cache
     */
    //cache: false,

    /*
     * The entry point for the bundle
     * Our Angular.js app
     *
     * See: https://webpack.js.org/configuration/entry-context/#entry
     */
    entry: {
      'polyfills': './src/polyfills.browser.ts',
      'vendor': './src/vendor.browser.ts',
      // 'main': aotMode ? './src/main.browser.aot.ts' : './src/main.browser.ts'
      'main': './src/main.browser.ts'
    },

    /*
     * Options affecting the resolving of modules.
     *
     * See: https://webpack.js.org/configuration/resolve
     */
    resolve: {

      /**
       * An array that automatically resolve certain extensions.
       * Which is what enables users to leave off the extension when importing.
       *
       * See: https://webpack.js.org/configuration/resolve/#resolve-extensions
       */
      extensions: ['.ts', '.js', '.json'],

      /**
       * Tell webpack what directories should be searched when resolving modules.
       *
       * We enable this in dev as it allows npm link to work
       *
       * See: https://webpack.js.org/configuration/resolve/#resolve-modules
       */
      modules: [helpers.root('src'), helpers.root('node_modules'),
        // Todo: fabric8-stack-analysis-ui/src/app/stack/overview/chart-component.js cannot locate c3
        helpers.root("node_modules/patternfly/node_modules/c3"),
        helpers.root("node_modules/patternfly/node_modules/d3")
      // ],
      //
      // plugins: [
      //   new TsConfigPathsPlugin( {
      //     baseUrl: helpers.root('src'),
      //     configFileName: 'tsconfig.json'
      //   })
      ]
    },

    /*
     * Options affecting the normal modules.
     *
     * See: http://webpack.github.io/docs/configuration.html#module
     */
    module: {

      rules: [

        /*
         * Typescript loader support for .ts and Angular 2 async routes via .async.ts
         * Replace templateUrl and stylesUrl with require()
         *
         * See: https://github.com/s-panferov/awesome-typescript-loader
         * See: https://github.com/TheLarkInn/angular2-template-loader
         */
        {
          test: /\.ts$/,
          use: aotMode ? [
            '@ngtools/webpack'
          ] : [
              '@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd,
              'awesome-typescript-loader',
              'angular2-template-loader',
              'angular2-router-loader'
            ],
          // loaders: '@ngtools/webpack',
          exclude: [/\.(spec|e2e)\.ts$/]
        },

        /**
         * Static analysis linter for TypeScript advanced options configuration
         * Description: An extensible linter for the TypeScript language.
         *
         * See: https://github.com/wbuchwalter/tslint-loader
         */
        {
          test: /\.ts$/,
          enforce: 'pre',
          loader: 'tslint-loader',
          exclude: [
            /node_modules/,
            /src\/a-runtime-console/,
            // /src\/main.browser.ts/,
            // /src\/polyfills.browser.ts/,
            // /src\/vendor.browser.ts/
          ],
          options: {
          //   configuration: {
          //     rules: {
          //       quotemark: [true, 'double']
          //     }
          //   },
          //
            // can specify a custom config file relative to current directory or with absolute path
            // 'tslint-custom.json'
            configFile: "tslint.json",

            // tslint errors are displayed by default as warnings
            // set emitErrors to true to display them as errors
            emitErrors: true,

            // tslint does not interrupt the compilation by default
            // if you want any file with tslint errors to fail
            // set failOnHint to true
            failOnHint: true,

            // enables type checked rules like 'for-in-array'
            // uses tsconfig.json from current working directory
            typeCheck: false,

            // automatically fix linting errors
            fix: false,

            // can specify a custom tsconfig file relative to current directory or with absolute path
            // to be used with type checked rules
            tsConfigFile: 'tsconfig.json',

            // path to directory containing formatter (optional)
            formattersDirectory: 'node_modules/tslint-loader/formatters/',

            // name of your formatter (optional)
            formatter: 'custom',

            // These options are useful if you want to save output to files
            // for your continuous integration server
            fileOutput: {
              // The directory where each file's report is saved
              dir: './lint/',

              // The extension to use for each report's filename. Defaults to 'txt'
              ext: 'xml',

              // If true, all files are removed from the report directory at the beginning of run
              clean: true,

              // A string to include at the top of every report file.
              // Useful for some report formats.
              header: '<?xml version="1.0" encoding="utf-8"?>\n<checkstyle version="5.7">',

              // A string to include at the bottom of every report file.
              // Useful for some report formats.
              footer: '</checkstyle>'
            }
          }
        },

        /*
         * Json loader support for *.json files.
         *
         * See: https://github.com/webpack/json-loader
         */
        {
          test: /\.json$/,
          use: ['json-loader']
        },

        /* HTML Linter
         * Checks all files against .htmlhintrc
        */
        {
          enforce: 'pre',
          test: /\.html$/,
          loader: 'htmlhint-loader',
          exclude: [/node_modules/,/src\/a-runtime-console/],
          options: {
            configFile: './.htmlhintrc'
          }
        },

        /* Raw loader support for *.html
         * Returns file content as string
         *
         * See: https://github.com/webpack/raw-loader
         */
        {
          test: /\.html$/,
          use: ['html-loader']
        },

        /*
         * to string and css loader support for *.css files
         * Returns file content as string
         *
         */
        {
          test: /^(?!.*component).*\.css$/,
          use: extractCSS.extract({
            fallback: "style-loader",
            use: [
              {
                loader: 'css-loader',
                options: {
                  sourceMap: true,
                  context: '/'
                },
              },
            ]
          })
        },
        {
          test: /\.component\.css$/,
          use: [
            {
              loader: 'to-string-loader'
            }, {
              loader: 'css-loader',
              options: {
                minimize: true,
                sourceMap: true,
                context: '/'
              }
            }
          ],
        },
        {
          test: /^(?!.*component).*\.less$/,
          use: extractCSS.extract({
            fallback: 'style-loader',
            use: [
              {
                loader: 'css-loader',
                options: {
                  minimize: true,
                  sourceMap: true,
                  context: '/'
                }
              }, {
                loader: 'less-loader',
                options: {
                  paths: [
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less"),
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies"),
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/bootstrap"),
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/font-awesome"),
                  ],
                  sourceMap: true
                }
              }
            ],
          })
        }, {
          test: /\.component\.less$/,
          use: [
            {
              loader: 'to-string-loader'
            }, {
              loader: 'css-loader',
              options: {
                minimize: true,
                sourceMap: true,
                context: '/'
              }
            }, {
              loader: 'less-loader',
              options: {
                paths: [
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less"),
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies"),
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/bootstrap"),
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/font-awesome"),
                ],
                sourceMap: true
              }
            }
          ],
        },

        /**
         * File loader for supporting fonts, for example, in CSS files.
         */
        {
          test: /\.(woff2|woff|ttf|eot|svg)$/,
          use: {
            loader: 'url-loader',
            query: {
              limit: 3000,
              includePaths: [
                path.resolve(__dirname, "../node_modules/patternfly/dist/fonts/")
              ],
              name: '_assets/fonts/[name].' + (isProd ? '[hash]' : '') + '[ext]'
            }
          },
          exclude: path.resolve(__dirname, "../src/assets/images/")
        },
        {
          test: /\.(jpg|png|svg|gif|jpeg)$/,
          use: {
            loader: 'url-loader',
            query: {
              limit: 3000,
              includePaths: [
                path.resolve(__dirname, "../src/assets/images/")
              ],
              name: '_assets/images/[name].' + (isProd ? '[hash]' : '') + '[ext]'
            }
          },
          exclude: path.resolve(__dirname, "../node_modules/patternfly/dist/fonts/")
        }
      ]
    },

    /*
     * Add additional plugins to the compiler.
     *
     * See: http://webpack.github.io/docs/configuration.html#plugins
     */
    plugins: [
      /*
       * Plugin: ForkCheckerPlugin
       * Description: Do type checking in a separate process, so webpack don't need to wait.
       *
       * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse
       */
      new CheckerPlugin(),

      /*
       * Plugin: CommonsChunkPlugin
       * Description: Shares common code between the pages.
       * It identifies common modules and put them into a commons chunk.
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
       * See: https://github.com/webpack/docs/wiki/optimization#multi-page-app
       */
      new CommonsChunkPlugin({
        name: ['polyfills', 'vendor'].reverse()
      }),

      /*
       * Plugin: ContextReplacementPlugin
       * Description: Provides context to Angular's use of System.import
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#contextreplacementplugin
       * See: https://github.com/angular/angular/issues/11580
       */
      new ContextReplacementPlugin(
        // The (\\|\/) piece accounts for path separators in *nix and Windows
        /(.+)?angular(\\|\/)core(.+)?/,
        path.resolve(__dirname, 'src') // location of your src
      ),

      /*
       * Plugin: CopyWebpackPlugin
       * Description: Copy files and directories in webpack.
       *
       * Copies project static assets.
       *
       * See: https://www.npmjs.com/package/copy-webpack-plugin
       */
       /*
       * this needs to be redirected to reside in the _assets/ directory
       */
      new CopyWebpackPlugin([
        {
          from: 'src/meta'
        }
      ]),

      /*
       * Plugin: HtmlWebpackPlugin
       * Description: Simplifies creation of HTML files to serve your webpack bundles.
       * This is especially useful for webpack bundles that include a hash in the filename
       * which changes every compilation.
       *
       * See: https://github.com/ampedandwired/html-webpack-plugin
       */
      new HtmlWebpackPlugin({
        template: 'src/index.ejs',
        title: branding.assets[METADATA.FABRIC8_BRANDING].title.prefix,
        chunksSortMode: 'dependency',
        metadata: METADATA
      }),

      /*
       * Plugin: ScriptExtHtmlWebpackPlugin
       * Description: Enhances html-webpack-plugin functionality
       * with different deployment options for your scripts including:
       *
       * See: https://github.com/numical/script-ext-html-webpack-plugin
       */
      new ScriptExtHtmlWebpackPlugin({
        defaultAttribute: 'defer'
      }),

      /*
       * Plugin LoaderOptionsPlugin (experimental)
       *
       * See: https://gist.github.com/sokra/27b24881210b56bbaff7
       */
      new LoaderOptionsPlugin({}),

      extractCSS,

      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),

      /*
       * StyleLintPlugin
      */
      new StyleLintPlugin({
        configFile: '.stylelintrc',
        syntax: 'less',
        context: 'src',
        files: '**/*.less',
        lintDirtyModulesOnly: true,
        failOnError: true,
        emitErrors: true,
        quiet: false,
      })
    ],

    /*
     * Include polyfills or mocks for various node stuff
     * Description: Node configuration
     *
     * See: https://webpack.github.io/docs/configuration.html#node
     */
    node: {
      global: true,
      crypto: 'empty',
      process: true,
      module: false,
      clearImmediate: false,
      setImmediate: false
    }
  };

  if (aotMode) {
    config.plugins.push(new ngtools.AotPlugin({
      tsConfigPath: 'tsconfig-aot.json'
      // entryModule: './src/app/app.module#AppModule',
      // genDir: './src/aot'
    }));
  }

  return config;
};
<commit_msg>fix(build): correct file name format (#2667)<commit_after>/**
 * @author: @AngularClass
 */

const webpack = require('webpack');
const helpers = require('./helpers');
const ngtools = require('@ngtools/webpack');
const branding = require('./branding');
var path = require('path');
var stringify = require('json-stringify');

/*
 * Webpack Plugins
 */
const autoprefixer = require('autoprefixer');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const IgnorePlugin = require('webpack/lib/IgnorePlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
// const ngcWebpack = require('ngc-webpack');
const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
// const TsConfigPathsPlugin = require('awesome-typescript-loader');

/*
 * Webpack Constants
 */
// const HMR = helpers.hasProcessFlag('hot');
// const AOT = helpers.hasNpmFlag('aot');
const METADATA = {
  baseUrl: '/',
  isDevServer: helpers.isWebpackDevServer(),
  FABRIC8_BRANDING: process.env.FABRIC8_BRANDING || 'fabric8'
};

/*
 * Webpack configuration
 *
 * See: http://webpack.github.io/docs/configuration.html#cli
 */
module.exports = function (options) {
  const isProd = options.env === 'production';
  const aotMode = false;//options && options.aot !== undefined;
  console.log('The options from the webpack config: ' + stringify(options, null, 2));

  // ExtractTextPlugin
  const extractCSS = new ExtractTextPlugin({
    filename: '_assets/stylesheets/[name].[id]' + ( isProd ? '.[contenthash]' : '' ) + '.css'
  });

  // const entryFile = aotMode ? './src/main.browser.aot.ts' : './src/main.browser.ts';
  // const outPath = aotMode ? 'dist' : 'aot';
  // const devtool = aotMode ? 'source-map' : 'eval-source-map';
  // const srcPath = path.join(__dirname, 'demo', 'src');
  var config = {

    /*
     * Cache generated modules and chunks to improve performance for multiple incremental builds.
     * This is enabled by default in watch mode.
     * You can pass false to disable it.
     *
     * See: http://webpack.github.io/docs/configuration.html#cache
     */
    //cache: false,

    /*
     * The entry point for the bundle
     * Our Angular.js app
     *
     * See: https://webpack.js.org/configuration/entry-context/#entry
     */
    entry: {
      'polyfills': './src/polyfills.browser.ts',
      'vendor': './src/vendor.browser.ts',
      // 'main': aotMode ? './src/main.browser.aot.ts' : './src/main.browser.ts'
      'main': './src/main.browser.ts'
    },

    /*
     * Options affecting the resolving of modules.
     *
     * See: https://webpack.js.org/configuration/resolve
     */
    resolve: {

      /**
       * An array that automatically resolve certain extensions.
       * Which is what enables users to leave off the extension when importing.
       *
       * See: https://webpack.js.org/configuration/resolve/#resolve-extensions
       */
      extensions: ['.ts', '.js', '.json'],

      /**
       * Tell webpack what directories should be searched when resolving modules.
       *
       * We enable this in dev as it allows npm link to work
       *
       * See: https://webpack.js.org/configuration/resolve/#resolve-modules
       */
      modules: [helpers.root('src'), helpers.root('node_modules'),
        // Todo: fabric8-stack-analysis-ui/src/app/stack/overview/chart-component.js cannot locate c3
        helpers.root("node_modules/patternfly/node_modules/c3"),
        helpers.root("node_modules/patternfly/node_modules/d3")
      // ],
      //
      // plugins: [
      //   new TsConfigPathsPlugin( {
      //     baseUrl: helpers.root('src'),
      //     configFileName: 'tsconfig.json'
      //   })
      ]
    },

    /*
     * Options affecting the normal modules.
     *
     * See: http://webpack.github.io/docs/configuration.html#module
     */
    module: {

      rules: [

        /*
         * Typescript loader support for .ts and Angular 2 async routes via .async.ts
         * Replace templateUrl and stylesUrl with require()
         *
         * See: https://github.com/s-panferov/awesome-typescript-loader
         * See: https://github.com/TheLarkInn/angular2-template-loader
         */
        {
          test: /\.ts$/,
          use: aotMode ? [
            '@ngtools/webpack'
          ] : [
              '@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd,
              'awesome-typescript-loader',
              'angular2-template-loader',
              'angular2-router-loader'
            ],
          // loaders: '@ngtools/webpack',
          exclude: [/\.(spec|e2e)\.ts$/]
        },

        /**
         * Static analysis linter for TypeScript advanced options configuration
         * Description: An extensible linter for the TypeScript language.
         *
         * See: https://github.com/wbuchwalter/tslint-loader
         */
        {
          test: /\.ts$/,
          enforce: 'pre',
          loader: 'tslint-loader',
          exclude: [
            /node_modules/,
            /src\/a-runtime-console/,
            // /src\/main.browser.ts/,
            // /src\/polyfills.browser.ts/,
            // /src\/vendor.browser.ts/
          ],
          options: {
          //   configuration: {
          //     rules: {
          //       quotemark: [true, 'double']
          //     }
          //   },
          //
            // can specify a custom config file relative to current directory or with absolute path
            // 'tslint-custom.json'
            configFile: "tslint.json",

            // tslint errors are displayed by default as warnings
            // set emitErrors to true to display them as errors
            emitErrors: true,

            // tslint does not interrupt the compilation by default
            // if you want any file with tslint errors to fail
            // set failOnHint to true
            failOnHint: true,

            // enables type checked rules like 'for-in-array'
            // uses tsconfig.json from current working directory
            typeCheck: false,

            // automatically fix linting errors
            fix: false,

            // can specify a custom tsconfig file relative to current directory or with absolute path
            // to be used with type checked rules
            tsConfigFile: 'tsconfig.json',

            // path to directory containing formatter (optional)
            formattersDirectory: 'node_modules/tslint-loader/formatters/',

            // name of your formatter (optional)
            formatter: 'custom',

            // These options are useful if you want to save output to files
            // for your continuous integration server
            fileOutput: {
              // The directory where each file's report is saved
              dir: './lint/',

              // The extension to use for each report's filename. Defaults to 'txt'
              ext: 'xml',

              // If true, all files are removed from the report directory at the beginning of run
              clean: true,

              // A string to include at the top of every report file.
              // Useful for some report formats.
              header: '<?xml version="1.0" encoding="utf-8"?>\n<checkstyle version="5.7">',

              // A string to include at the bottom of every report file.
              // Useful for some report formats.
              footer: '</checkstyle>'
            }
          }
        },

        /*
         * Json loader support for *.json files.
         *
         * See: https://github.com/webpack/json-loader
         */
        {
          test: /\.json$/,
          use: ['json-loader']
        },

        /* HTML Linter
         * Checks all files against .htmlhintrc
        */
        {
          enforce: 'pre',
          test: /\.html$/,
          loader: 'htmlhint-loader',
          exclude: [/node_modules/,/src\/a-runtime-console/],
          options: {
            configFile: './.htmlhintrc'
          }
        },

        /* Raw loader support for *.html
         * Returns file content as string
         *
         * See: https://github.com/webpack/raw-loader
         */
        {
          test: /\.html$/,
          use: ['html-loader']
        },

        /*
         * to string and css loader support for *.css files
         * Returns file content as string
         *
         */
        {
          test: /^(?!.*component).*\.css$/,
          use: extractCSS.extract({
            fallback: "style-loader",
            use: [
              {
                loader: 'css-loader',
                options: {
                  sourceMap: true,
                  context: '/'
                },
              },
            ]
          })
        },
        {
          test: /\.component\.css$/,
          use: [
            {
              loader: 'to-string-loader'
            }, {
              loader: 'css-loader',
              options: {
                minimize: true,
                sourceMap: true,
                context: '/'
              }
            }
          ],
        },
        {
          test: /^(?!.*component).*\.less$/,
          use: extractCSS.extract({
            fallback: 'style-loader',
            use: [
              {
                loader: 'css-loader',
                options: {
                  minimize: true,
                  sourceMap: true,
                  context: '/'
                }
              }, {
                loader: 'less-loader',
                options: {
                  paths: [
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less"),
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies"),
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/bootstrap"),
                    path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/font-awesome"),
                  ],
                  sourceMap: true
                }
              }
            ],
          })
        }, {
          test: /\.component\.less$/,
          use: [
            {
              loader: 'to-string-loader'
            }, {
              loader: 'css-loader',
              options: {
                minimize: true,
                sourceMap: true,
                context: '/'
              }
            }, {
              loader: 'less-loader',
              options: {
                paths: [
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less"),
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies"),
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/bootstrap"),
                  path.resolve(__dirname, "../node_modules/patternfly/dist/less/dependencies/font-awesome"),
                ],
                sourceMap: true
              }
            }
          ],
        },

        /**
         * File loader for supporting fonts, for example, in CSS files.
         */
        {
          test: /\.(woff2|woff|ttf|eot|svg)$/,
          use: {
            loader: 'url-loader',
            query: {
              limit: 3000,
              includePaths: [
                path.resolve(__dirname, "../node_modules/patternfly/dist/fonts/")
              ],
              name: '_assets/fonts/[name]' + (isProd ? '.[hash]' : '') + '.[ext]'
            }
          },
          exclude: path.resolve(__dirname, "../src/assets/images/")
        },
        {
          test: /\.(jpg|png|svg|gif|jpeg)$/,
          use: {
            loader: 'url-loader',
            query: {
              limit: 3000,
              includePaths: [
                path.resolve(__dirname, "../src/assets/images/")
              ],
              name: '_assets/images/[name]' + (isProd ? '.[hash]' : '') + '.[ext]'
            }
          },
          exclude: path.resolve(__dirname, "../node_modules/patternfly/dist/fonts/")
        }
      ]
    },

    /*
     * Add additional plugins to the compiler.
     *
     * See: http://webpack.github.io/docs/configuration.html#plugins
     */
    plugins: [
      /*
       * Plugin: ForkCheckerPlugin
       * Description: Do type checking in a separate process, so webpack don't need to wait.
       *
       * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse
       */
      new CheckerPlugin(),

      /*
       * Plugin: CommonsChunkPlugin
       * Description: Shares common code between the pages.
       * It identifies common modules and put them into a commons chunk.
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
       * See: https://github.com/webpack/docs/wiki/optimization#multi-page-app
       */
      new CommonsChunkPlugin({
        name: ['polyfills', 'vendor'].reverse()
      }),

      /*
       * Plugin: ContextReplacementPlugin
       * Description: Provides context to Angular's use of System.import
       *
       * See: https://webpack.github.io/docs/list-of-plugins.html#contextreplacementplugin
       * See: https://github.com/angular/angular/issues/11580
       */
      new ContextReplacementPlugin(
        // The (\\|\/) piece accounts for path separators in *nix and Windows
        /(.+)?angular(\\|\/)core(.+)?/,
        path.resolve(__dirname, 'src') // location of your src
      ),

      /*
       * Plugin: CopyWebpackPlugin
       * Description: Copy files and directories in webpack.
       *
       * Copies project static assets.
       *
       * See: https://www.npmjs.com/package/copy-webpack-plugin
       */
       /*
       * this needs to be redirected to reside in the _assets/ directory
       */
      new CopyWebpackPlugin([
        {
          from: 'src/meta'
        }
      ]),

      /*
       * Plugin: HtmlWebpackPlugin
       * Description: Simplifies creation of HTML files to serve your webpack bundles.
       * This is especially useful for webpack bundles that include a hash in the filename
       * which changes every compilation.
       *
       * See: https://github.com/ampedandwired/html-webpack-plugin
       */
      new HtmlWebpackPlugin({
        template: 'src/index.ejs',
        title: branding.assets[METADATA.FABRIC8_BRANDING].title.prefix,
        chunksSortMode: 'dependency',
        metadata: METADATA
      }),

      /*
       * Plugin: ScriptExtHtmlWebpackPlugin
       * Description: Enhances html-webpack-plugin functionality
       * with different deployment options for your scripts including:
       *
       * See: https://github.com/numical/script-ext-html-webpack-plugin
       */
      new ScriptExtHtmlWebpackPlugin({
        defaultAttribute: 'defer'
      }),

      /*
       * Plugin LoaderOptionsPlugin (experimental)
       *
       * See: https://gist.github.com/sokra/27b24881210b56bbaff7
       */
      new LoaderOptionsPlugin({}),

      extractCSS,

      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),

      /*
       * StyleLintPlugin
      */
      new StyleLintPlugin({
        configFile: '.stylelintrc',
        syntax: 'less',
        context: 'src',
        files: '**/*.less',
        lintDirtyModulesOnly: true,
        failOnError: true,
        emitErrors: true,
        quiet: false,
      })
    ],

    /*
     * Include polyfills or mocks for various node stuff
     * Description: Node configuration
     *
     * See: https://webpack.github.io/docs/configuration.html#node
     */
    node: {
      global: true,
      crypto: 'empty',
      process: true,
      module: false,
      clearImmediate: false,
      setImmediate: false
    }
  };

  if (aotMode) {
    config.plugins.push(new ngtools.AotPlugin({
      tsConfigPath: 'tsconfig-aot.json'
      // entryModule: './src/app/app.module#AppModule',
      // genDir: './src/aot'
    }));
  }

  return config;
};
<|endoftext|>


<commit_before>const webpack = require('webpack');

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const NotifyPlugin = require('notify-webpack-plugin');
// const Visualizer = require('webpack-visualizer-plugin');

const packageJson = require('../package.json');
const configJson = require('../apiKey.json');
const ASSET_NAME_PATTERN = 'static/[name]-[hash:6].[ext]';

module.exports = (env) => {
  const isDev = env === 'dev';
  const version = packageJson.version.toString();
  // const apiKey = configJson.apiKey.toString();
  // const apiKey = configJson.apiKeyServerWeb.toString();
  const apiKey = configJson.apiKeyServerDev.toString();

  const config = {
    entry: {
      main: './app/index.js'
    },

    output: {
      path: path.resolve('./dist'),
      filename: '[name]-[chunkhash:6].js',
      chunkFilename: 'chunk-[id]-[name]-[chunkhash:6].js'
    },

    devServer: {
      contentBase: path.resolve(__dirname, './app'),
      publicPath: '/',
      https: true,
      host: '0.0.0.0',
      hot: false,
      historyApiFallback: {
        index: '/index.html'
      }
    },

    devtool: 'source-map',

    stats: 'errors-only',

    performance: {
      hints: false
    },

    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: [
            'babel-loader'
          ]
        }, {
          test: /\.json$/,
          loader: 'json-loader'
        }, {
          test: /\.html$/,
          use: [
            'raw-loader',
            'extract-loader',
            'html-loader'
          ]
        }, {
          test: /\.(png|eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
          loader: 'url-loader',
          options: {
            limit: 5 * 1024,
            name: ASSET_NAME_PATTERN
          }
        }, {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract({
            use: [
              'css-loader',
              'postcss-loader',
              'sass-loader'
            ],
            fallback: 'style-loader'
          })
        }
      ],
    },

    resolve: {
      extensions: ['.js', '.json'],
      alias: {
        app: path.resolve('./app')
      }
    },

    plugins: [
      new CleanWebpackPlugin(['dist'], {
        root: path.resolve('./')
      }),

      new NotifyPlugin('DRS', !isDev),

      new ExtractTextPlugin('styles-[contenthash:6].css'),

      new HtmlWebpackPlugin({
        inject: false,
        filename: 'index.html',
        template: '!handlebars-loader!app/index.html'
      }),

      new CopyWebpackPlugin([
        // Web app stuff
        { from: './app/.htaccess' },
        { from: `./icons/` },
        // Chrome extension stuff
        { from: './app/chrome-extension/', to: 'chrome-extension/' },
        { from: `./icons/`, to: 'chrome-extension/' },
      ]),

      // Optimize chunk IDs
      new webpack.optimize.OccurrenceOrderPlugin(true),

      new webpack.DefinePlugin({
        $DRS_VERSION: JSON.stringify(version),
        $DRS_FLAVOR: JSON.stringify(env),
        $DRS_API_KEY: JSON.stringify(apiKey)
      }),

      new LodashModuleReplacementPlugin({
        shorthands: true,
        // cloning: true,
        // currying: true,
        // caching: true,
        collections: true,
        exotics: true,
        guards: true,
        // metadata: true,
        deburring: true,
        unicode: true,
        chaining: true,
        // memoizing: true,
        // coercions: true,
        flattening: true,
        paths: true,
        placeholders: true
      }),

      // Enable if you want to debug the size of the chunks
      // new Visualizer(),
    ],

    node: {
      fs: 'empty',
      net: 'empty',
      tls: 'empty'
    }
  };

  return config;
};<commit_msg>API key based off build mode.<commit_after>const webpack = require('webpack');

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const NotifyPlugin = require('notify-webpack-plugin');
// const Visualizer = require('webpack-visualizer-plugin');

const packageJson = require('../package.json');
const configJson = require('../apiKey.json');
const ASSET_NAME_PATTERN = 'static/[name]-[hash:6].[ext]';

module.exports = (env) => {
  const isDev = env === 'dev';
  const version = packageJson.version.toString();
  const apiKey = isDev ? configJson.apiKeyServerDev.toString() : configJson.apiKeyServerWeb.toString();

  const config = {
    entry: {
      main: './app/index.js'
    },

    output: {
      path: path.resolve('./dist'),
      filename: '[name]-[chunkhash:6].js',
      chunkFilename: 'chunk-[id]-[name]-[chunkhash:6].js'
    },

    devServer: {
      contentBase: path.resolve(__dirname, './app'),
      publicPath: '/',
      https: true,
      host: '0.0.0.0',
      hot: false,
      historyApiFallback: {
        index: '/index.html'
      }
    },

    devtool: 'source-map',

    stats: 'errors-only',

    performance: {
      hints: false
    },

    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: [
            'babel-loader'
          ]
        }, {
          test: /\.json$/,
          loader: 'json-loader'
        }, {
          test: /\.html$/,
          use: [
            'raw-loader',
            'extract-loader',
            'html-loader'
          ]
        }, {
          test: /\.(png|eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
          loader: 'url-loader',
          options: {
            limit: 5 * 1024,
            name: ASSET_NAME_PATTERN
          }
        }, {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract({
            use: [
              'css-loader',
              'postcss-loader',
              'sass-loader'
            ],
            fallback: 'style-loader'
          })
        }
      ],
    },

    resolve: {
      extensions: ['.js', '.json'],
      alias: {
        app: path.resolve('./app')
      }
    },

    plugins: [
      new CleanWebpackPlugin(['dist'], {
        root: path.resolve('./')
      }),

      new NotifyPlugin('DRS', !isDev),

      new ExtractTextPlugin('styles-[contenthash:6].css'),

      new HtmlWebpackPlugin({
        inject: false,
        filename: 'index.html',
        template: '!handlebars-loader!app/index.html'
      }),

      new CopyWebpackPlugin([
        // Web app stuff
        { from: './app/.htaccess' },
        { from: `./icons/` },
        // Chrome extension stuff
        { from: './app/chrome-extension/', to: 'chrome-extension/' },
        { from: `./icons/`, to: 'chrome-extension/' },
      ]),

      // Optimize chunk IDs
      new webpack.optimize.OccurrenceOrderPlugin(true),

      new webpack.DefinePlugin({
        $DRS_VERSION: JSON.stringify(version),
        $DRS_FLAVOR: JSON.stringify(env),
        $DRS_API_KEY: JSON.stringify(apiKey)
      }),

      new LodashModuleReplacementPlugin({
        shorthands: true,
        // cloning: true,
        // currying: true,
        // caching: true,
        collections: true,
        exotics: true,
        guards: true,
        // metadata: true,
        deburring: true,
        unicode: true,
        chaining: true,
        // memoizing: true,
        // coercions: true,
        flattening: true,
        paths: true,
        placeholders: true
      }),

      // Enable if you want to debug the size of the chunks
      // new Visualizer(),
    ],

    node: {
      fs: 'empty',
      net: 'empty',
      tls: 'empty'
    }
  };

  return config;
};<|endoftext|>