<commit_before>/** Base class for all sections. */

'use strict';

var memoize          = require('memoizee/plain')
  , validDb          = require('dbjs/valid-dbjs')
  , defineStringLine = require('dbjs-ext/string/string-line')
  , defineUInteger   = require('dbjs-ext/number/integer/u-integer')
  , definePercentage = require('dbjs-ext/number/percentage');

module.exports = memoize(function (db) {
	var StringLine, Percentage, UInteger;
	validDb(db);
	db.Object.defineProperties({
		getFormApplicablePropName: { type: db.Function, value: function (prop) {
			return 'is' + prop[0].toUpperCase() + prop.slice(1) + 'FormApplicable';
		} },
		getApplicablePropName: { type: db.Function, value: function (prop) {
			return 'is' + prop[0].toUpperCase() + prop.slice(1) + 'Applicable';
		} }
	});
	UInteger   = defineUInteger(db);
	StringLine = defineStringLine(db);
	Percentage = definePercentage(db);
	return db.Object.extend('FormSectionBase', {
		label: { type: StringLine, required: true },
		// When isApplicable !== true the section will not be visible in the view
		// (rendered with default generator)
		isApplicable: { type: db.Boolean, required: true, value: true },
		// The master for property paths resolution
		propertyMaster: { type: db.Object, value: function () {
			var owner;
			if (this.propertyMasterType) {
				// we take first owner who is a person
				owner = this.owner;
				while (owner && !this.propertyMasterType.is(owner)) {
					owner = owner.owner;
				}
				return owner;
			}
			return this.master;
		} },
		// Setup for type to check against in propertyMaster's owner search
		propertyMasterType: { type: db.Base },
		// A percentage of completion of fields covered by the section
		status: { type: Percentage, required: true, value: 1 },
		// The weight of the section status. It is used to determine weighed status across sections.
		// It is usually equal to number of fields covered by the section.
		weight: { type: UInteger, required: true, value: 0 },
		// The value upon which resolventProperty is resolved.
		// Section is visible when section.master[section.resolventProperty] === section.resolventValue
		// See also resolventProperty.
		resolventValue: { type: db.Base },
		// Used to overwrite default message which is shown through view/components/incomplete-form-nav.
		onIncompleteMessage: { type: StringLine },
		isUnresolved: { type: db.Boolean, value: function (_observe) {
			var resolved;
			if (!this.resolventProperty) return false;
			resolved = this.master.resolveSKeyPath(this.resolventProperty, _observe);
			return _observe(resolved.observable) !== this.resolventValue;
		} },
		resolventStatus: {
			type: UInteger,
			value: function (_observe) {
				var isResolventExcluded, resolved;
				if (this.resolventProperty) {
					resolved = this.master.resolveSKeyPath(this.resolventProperty, _observe);
					if (!resolved) {
						return 0;
					}
					isResolventExcluded = this.isPropertyExcludedFromStatus(resolved, _observe);
					if (isResolventExcluded) return 1;
					if (_observe(resolved.observable) !== _observe(this.resolventValue)) {
						if (resolved.descriptor.multiple) {
							if (_observe(resolved.observable).size) return 1;
						} else {
							if (_observe(resolved.observable) != null) return 1;
						}
						return 0;
					}
					if (!isResolventExcluded) {
						return 1;
					}
				}
				return 1;
			}
		},
		resolventWeight: {
			type: UInteger,
			value: function (_observe) {
				var weightTotal, isResolventExcluded, resolved;
				weightTotal = 0;
				if (this.resolventProperty) {
					resolved = this.master.resolveSKeyPath(this.resolventProperty, _observe);
					if (!resolved) {
						return 0;
					}
					isResolventExcluded = this.isPropertyExcludedFromStatus(resolved, _observe);
					if (_observe(resolved.observable) !== _observe(this.resolventValue)) {
						return isResolventExcluded ? 0 : 1;
					}
					if (!isResolventExcluded) {
						++weightTotal;
					}
				}
				return weightTotal;
			}
		},
		isPropertyExcludedFromStatus: { type: db.Function, value: function (resolved, _observe) {
			if (!resolved.descriptor.required) return true;
			if (this.excludedFromStatusIfFilled.has(resolved.key) ||
					(!resolved.descriptor.multiple &&
					Object.getPrototypeOf(resolved.object).get(resolved.key) != null)) {
				if (resolved.descriptor.multiple) {
					if (_observe(resolved.observable).size) return true;
				} else {
					if (_observe(resolved.observable) != null) return true;
				}
			}

			return false;
		} },
		lastEditStamp: { type: UInteger, value: 0 },
		lastEditDate: { type: db.DateTime, value: function () {
			return this.lastEditStamp / 1000;
		} },
		// A multiple for which you can pass names of the properties you want excluded from
		// status calculation if they were already provided for the form (for example from guide).
		excludedFromStatusIfFilled: { type: StringLine, multiple: true },
		// The url to which the the form created around the section will be submitted.
		actionUrl: { type: StringLine, required: true },
		// Used to hide and show section depending on a value of certain property.
		// Set name of the property as value of resolventProperty.
		// Section is visible when section.master[section.resolventProperty] === section.resolventValue
		resolventProperty: { type: StringLine }
	});
}, { normalizer: require('memoizee/normalizers/get-1')() });
<commit_msg>#688 simplified resolvent weight calculation<commit_after>/** Base class for all sections. */

'use strict';

var memoize          = require('memoizee/plain')
  , validDb          = require('dbjs/valid-dbjs')
  , defineStringLine = require('dbjs-ext/string/string-line')
  , defineUInteger   = require('dbjs-ext/number/integer/u-integer')
  , definePercentage = require('dbjs-ext/number/percentage');

module.exports = memoize(function (db) {
	var StringLine, Percentage, UInteger;
	validDb(db);
	db.Object.defineProperties({
		getFormApplicablePropName: { type: db.Function, value: function (prop) {
			return 'is' + prop[0].toUpperCase() + prop.slice(1) + 'FormApplicable';
		} },
		getApplicablePropName: { type: db.Function, value: function (prop) {
			return 'is' + prop[0].toUpperCase() + prop.slice(1) + 'Applicable';
		} }
	});
	UInteger   = defineUInteger(db);
	StringLine = defineStringLine(db);
	Percentage = definePercentage(db);
	return db.Object.extend('FormSectionBase', {
		label: { type: StringLine, required: true },
		// When isApplicable !== true the section will not be visible in the view
		// (rendered with default generator)
		isApplicable: { type: db.Boolean, required: true, value: true },
		// The master for property paths resolution
		propertyMaster: { type: db.Object, value: function () {
			var owner;
			if (this.propertyMasterType) {
				// we take first owner who is a person
				owner = this.owner;
				while (owner && !this.propertyMasterType.is(owner)) {
					owner = owner.owner;
				}
				return owner;
			}
			return this.master;
		} },
		// Setup for type to check against in propertyMaster's owner search
		propertyMasterType: { type: db.Base },
		// A percentage of completion of fields covered by the section
		status: { type: Percentage, required: true, value: 1 },
		// The weight of the section status. It is used to determine weighed status across sections.
		// It is usually equal to number of fields covered by the section.
		weight: { type: UInteger, required: true, value: 0 },
		// The value upon which resolventProperty is resolved.
		// Section is visible when section.master[section.resolventProperty] === section.resolventValue
		// See also resolventProperty.
		resolventValue: { type: db.Base },
		// Used to overwrite default message which is shown through view/components/incomplete-form-nav.
		onIncompleteMessage: { type: StringLine },
		isUnresolved: { type: db.Boolean, value: function (_observe) {
			var resolved;
			if (!this.resolventProperty) return false;
			resolved = this.master.resolveSKeyPath(this.resolventProperty, _observe);
			return _observe(resolved.observable) !== this.resolventValue;
		} },
		resolventStatus: {
			type: UInteger,
			value: function (_observe) {
				var isResolventExcluded, resolved;
				if (this.resolventProperty) {
					resolved = this.master.resolveSKeyPath(this.resolventProperty, _observe);
					if (!resolved) {
						return 0;
					}
					isResolventExcluded = this.isPropertyExcludedFromStatus(resolved, _observe);
					if (isResolventExcluded) return 1;
					if (_observe(resolved.observable) !== _observe(this.resolventValue)) {
						if (resolved.descriptor.multiple) {
							if (_observe(resolved.observable).size) return 1;
						} else {
							if (_observe(resolved.observable) != null) return 1;
						}
						return 0;
					}
					if (!isResolventExcluded) {
						return 1;
					}
				}
				return 1;
			}
		},
		resolventWeight: {
			type: UInteger,
			value: function (_observe) {
				var isResolventExcluded, resolved;
				if (this.resolventProperty) {
					resolved = this.master.resolveSKeyPath(this.resolventProperty, _observe);
					if (!resolved) {
						return 0;
					}
					isResolventExcluded = this.isPropertyExcludedFromStatus(resolved, _observe);
					if (isResolventExcluded) return 0;
					return 1;
				}
				return 0;
			}
		},
		isPropertyExcludedFromStatus: { type: db.Function, value: function (resolved, _observe) {
			if (!resolved.descriptor.required) return true;
			if (this.excludedFromStatusIfFilled.has(resolved.key) ||
					(!resolved.descriptor.multiple &&
					Object.getPrototypeOf(resolved.object).get(resolved.key) != null)) {
				if (resolved.descriptor.multiple) {
					if (_observe(resolved.observable).size) return true;
				} else {
					if (_observe(resolved.observable) != null) return true;
				}
			}

			return false;
		} },
		lastEditStamp: { type: UInteger, value: 0 },
		lastEditDate: { type: db.DateTime, value: function () {
			return this.lastEditStamp / 1000;
		} },
		// A multiple for which you can pass names of the properties you want excluded from
		// status calculation if they were already provided for the form (for example from guide).
		excludedFromStatusIfFilled: { type: StringLine, multiple: true },
		// The url to which the the form created around the section will be submitted.
		actionUrl: { type: StringLine, required: true },
		// Used to hide and show section depending on a value of certain property.
		// Set name of the property as value of resolventProperty.
		// Section is visible when section.master[section.resolventProperty] === section.resolventValue
		resolventProperty: { type: StringLine }
	});
}, { normalizer: require('memoizee/normalizers/get-1')() });
<|endoftext|>


<commit_before>// @flow
import React, { useState } from "react"
import gql from "graphql-tag"
import { FixedSizeList } from "react-window"
import AutoSizer from "react-virtualized-auto-sizer"
import InfiniteLoader from "react-window-infinite-loader"
import { makeStyles } from "@material-ui/styles"
import Paper from "@material-ui/core/Paper"
import StrainCatalogListHeader from "components/Stocks/Strains/Catalog/StrainCatalogListHeader"
import StrainCatalogListItem from "components/Stocks/Strains/Catalog/StrainCatalogListItem"

const GET_MORE_STRAINS_LIST = gql`
  query MoreStrainsList($cursor: Int!) {
    listStrains(input: { cursor: $cursor, limit: 10 }) {
      nextCursor
      strains {
        id
        label
        summary
        in_stock
      }
    }
  }
`

const useStyles = makeStyles({
  catalogPaper: {
    height: 600,
    width: "100%",
  },
})

type Props = {
  data: Array<{
    label: string,
    id: string,
    summary: string,
  }>,
  fetchMore: Function,
  cursor: number,
}

const StrainCatalogList = ({ data, fetchMore, cursor }: Props) => {
  const [checkedItems, setCheckedItems] = useState([])
  const classes = useStyles()

  const handleCheckboxChange = (id, label) => event => {
    // if checkbox is already checked, remove that item from state
    if (checkedItems.some(item => item.id === id)) {
      setCheckedItems(checkedItems.filter(item => item.id !== id))
    } else {
      setCheckedItems([...checkedItems, { id, label }])
    }
  }

  const handleCheckAllChange = () => {
    if (checkedItems.length > 0) {
      setCheckedItems([])
    }
  }

  const loadMoreItems = () =>
    fetchMore({
      query: GET_MORE_STRAINS_LIST,
      variables: {
        cursor: cursor,
      },
      updateQuery: (previousResult, { fetchMoreResult }) => {
        if (!fetchMoreResult) return previousResult
        const previousEntry = previousResult.listStrains
        const newStrains = fetchMoreResult.listStrains.strains
        const newCursor = fetchMoreResult.listStrains.nextCursor
        const allStrains = [...previousEntry.strains, ...newStrains]

        return {
          listStrains: {
            nextCursor: newCursor,
            strains: [...new Set(allStrains)], // remove any duplicate entries
            __typename: previousEntry.__typename,
          },
        }
      },
    })

  return (
    <Paper className={classes.catalogPaper}>
      <StrainCatalogListHeader
        checkedItems={checkedItems}
        setCheckedItems={setCheckedItems}
        handleCheckAllChange={handleCheckAllChange}
      />
      <AutoSizer>
        {({ height, width }) => (
          <InfiniteLoader
            isItemLoaded={({ index }) => !!data[index]}
            itemCount={30000}
            loadMoreItems={loadMoreItems}>
            {({ onItemsRendered, ref }) => (
              <FixedSizeList
                onItemsRendered={onItemsRendered}
                ref={ref}
                height={535}
                width={width}
                itemSize={50}
                itemCount={data.length}
                itemData={{
                  item: data,
                  handleCheckboxChange,
                  checkedItems,
                }}>
                {StrainCatalogListItem}
              </FixedSizeList>
            )}
          </InfiniteLoader>
        )}
      </AutoSizer>
    </Paper>
  )
}

export default StrainCatalogList
<commit_msg>refactor: remove hard-coded value from catalog item count<commit_after>// @flow
import React, { useState } from "react"
import gql from "graphql-tag"
import { FixedSizeList } from "react-window"
import AutoSizer from "react-virtualized-auto-sizer"
import InfiniteLoader from "react-window-infinite-loader"
import { makeStyles } from "@material-ui/styles"
import Paper from "@material-ui/core/Paper"
import StrainCatalogListHeader from "components/Stocks/Strains/Catalog/StrainCatalogListHeader"
import StrainCatalogListItem from "components/Stocks/Strains/Catalog/StrainCatalogListItem"

const GET_MORE_STRAINS_LIST = gql`
  query MoreStrainsList($cursor: Int!) {
    listStrains(input: { cursor: $cursor, limit: 10 }) {
      nextCursor
      strains {
        id
        label
        summary
        in_stock
      }
    }
  }
`

const useStyles = makeStyles({
  catalogPaper: {
    height: 600,
    width: "100%",
  },
})

type Props = {
  data: Array<{
    label: string,
    id: string,
    summary: string,
  }>,
  fetchMore: Function,
  cursor: number,
}

const StrainCatalogList = ({ data, fetchMore, cursor }: Props) => {
  const [checkedItems, setCheckedItems] = useState([])
  const classes = useStyles()

  const handleCheckboxChange = (id, label) => event => {
    // if checkbox is already checked, remove that item from state
    if (checkedItems.some(item => item.id === id)) {
      setCheckedItems(checkedItems.filter(item => item.id !== id))
    } else {
      setCheckedItems([...checkedItems, { id, label }])
    }
  }

  const handleCheckAllChange = () => {
    if (checkedItems.length > 0) {
      setCheckedItems([])
    }
  }

  const loadMoreItems = () =>
    fetchMore({
      query: GET_MORE_STRAINS_LIST,
      variables: {
        cursor: cursor,
      },
      updateQuery: (previousResult, { fetchMoreResult }) => {
        if (!fetchMoreResult) return previousResult
        const previousEntry = previousResult.listStrains
        const newStrains = fetchMoreResult.listStrains.strains
        const newCursor = fetchMoreResult.listStrains.nextCursor
        const allStrains = [...previousEntry.strains, ...newStrains]

        return {
          listStrains: {
            nextCursor: newCursor,
            strains: [...new Set(allStrains)], // remove any duplicate entries
            __typename: previousEntry.__typename,
          },
        }
      },
    })

  return (
    <Paper className={classes.catalogPaper}>
      <StrainCatalogListHeader
        checkedItems={checkedItems}
        setCheckedItems={setCheckedItems}
        handleCheckAllChange={handleCheckAllChange}
      />
      <AutoSizer>
        {({ height, width }) => (
          <InfiniteLoader
            isItemLoaded={({ index }) => !!data[index]}
            itemCount={data.length}
            loadMoreItems={loadMoreItems}>
            {({ onItemsRendered, ref }) => (
              <FixedSizeList
                onItemsRendered={onItemsRendered}
                ref={ref}
                height={535}
                width={width}
                itemSize={50}
                itemCount={data.length}
                itemData={{
                  item: data,
                  handleCheckboxChange,
                  checkedItems,
                }}>
                {StrainCatalogListItem}
              </FixedSizeList>
            )}
          </InfiniteLoader>
        )}
      </AutoSizer>
    </Paper>
  )
}

export default StrainCatalogList
<|endoftext|>


<commit_before>import React, {
  useEffect,
  useState,
  useCallback
} from 'react';
import PropTypes from 'prop-types';
import StyledSelectList from './select-list.style';
import updateListScrollTop from './update-list-scroll';
import getNextChildByText from '../utils/get-next-child-by-text';
import Portal from '../../portal/portal';
import { getNextIndexByKey } from '../utils/get-next-child-by-key';

const overhang = 4;

const SelectList = React.forwardRef(({
  id,
  labelId,
  children,
  onSelect,
  onSelectListClose,
  filterText,
  anchorElement,
  highlightedValue,
  repositionTrigger,
  ...listProps
}, listRef) => {
  const [currentOptionsListIndex, setCurrentOptionsListIndex] = useState(-1);

  const highlightItem = useCallback((newIndex, optionList) => {
    const { text, value } = optionList[newIndex].props;

    setCurrentOptionsListIndex(newIndex);
    updateListScrollTop(newIndex, listRef.current);
    onSelect({ text, value, selectionType: 'navigationKey' });
  }, [listRef, onSelect]);

  const handleGlobalKeydown = useCallback((event) => {
    const { key } = event;
    const optionList = React.Children.toArray(children);
    const lastIndex = optionList.length - 1;

    if (key === 'Tab' || key === 'Escape') {
      onSelectListClose();
    } else if (key === 'Enter') {
      const currentOption = optionList[currentOptionsListIndex];

      if (!currentOption) {
        onSelectListClose();

        return;
      }

      const { text, value } = currentOption.props;

      onSelect({ text, value, selectionType: 'enterKey' });
    } else if (isNavigationKey(key)) {
      const nextIndex = getNextIndexByKey(key, currentOptionsListIndex, lastIndex);

      highlightItem(nextIndex, optionList);
    }
  }, [currentOptionsListIndex, children, onSelectListClose, onSelect, highlightItem]);

  const repositionList = useCallback(() => {
    if (anchorElement) {
      const inputBoundingRect = anchorElement.getBoundingClientRect();

      const top = `${window.pageYOffset + inputBoundingRect.top + inputBoundingRect.height}px`;
      const width = `${inputBoundingRect.width + 2 * overhang}px`;
      const left = `${window.pageXOffset + inputBoundingRect.left - overhang}px`;

      listRef.current.setAttribute('style', `top: ${top}; width: ${width}; left: ${left}`);
    }
  }, [anchorElement, listRef]);

  const getIndexOfMatch = useCallback((valueToMatch) => {
    return React.Children.toArray(children).findIndex(child => child.props.value === valueToMatch);
  }, [children]);

  useEffect(() => {
    const keyboardEvent = 'keydown';

    document.addEventListener(keyboardEvent, handleGlobalKeydown);

    return function cleanup() {
      document.removeEventListener(keyboardEvent, handleGlobalKeydown);
    };
  }, [handleGlobalKeydown]);

  useEffect(() => {
    if (!filterText) {
      return;
    }

    setCurrentOptionsListIndex((previousIndex) => {
      const match = getNextChildByText(filterText, children, previousIndex);

      if (!match) {
        return previousIndex;
      }

      const indexOfMatch = getIndexOfMatch(match.props.value);

      updateListScrollTop(indexOfMatch, listRef.current);

      return indexOfMatch;
    });
  }, [children, filterText, getIndexOfMatch, listRef]);

  useEffect(() => {
    repositionList();
  }, [repositionList, repositionTrigger]);

  useEffect(() => {
    if (!highlightedValue) {
      return;
    }

    const indexOfMatch = getIndexOfMatch(highlightedValue);

    setCurrentOptionsListIndex(indexOfMatch);
    updateListScrollTop(indexOfMatch, listRef.current);
  }, [getIndexOfMatch, highlightedValue, listRef]);

  function getChildrenWithListProps() {
    return React.Children.map(children, (child, index) => {
      const newProps = {
        onSelect: handleSelect,
        isHighlighted: currentOptionsListIndex === index
      };

      return React.cloneElement(child, newProps);
    });
  }

  function handleSelect(optionData) {
    onSelect({ ...optionData, selectionType: 'click' });
  }

  function isNavigationKey(keyEvent) {
    return keyEvent === 'ArrowDown' || keyEvent === 'ArrowUp'
    || keyEvent === 'Home' || keyEvent === 'End';
  }

  return (
    <Portal onReposition={ repositionList }>
      <StyledSelectList
        id={ id }
        aria-labelledby={ labelId }
        data-element='select-list'
        role='listbox'
        ref={ listRef }
        tabIndex='0'
        { ...listProps }
      >
        { getChildrenWithListProps() }
      </StyledSelectList>
    </Portal>
  );
});

SelectList.propTypes = {
  /** The ID for the parent <div> */
  id: PropTypes.string,
  /** The Id of the label */
  labelId: PropTypes.string,
  /** Child components (such as <Option>) for the <ScrollableList> */
  children: PropTypes.node,
  /** DOM element to position the dropdown menu list relative to */
  anchorElement: PropTypes.object,
  /** A callback for when a child is selected */
  onSelect: PropTypes.func.isRequired,
  /** A callback for when the list should be closed */
  onSelectListClose: PropTypes.func.isRequired,
  /** Text value to highlight an option */
  filterText: PropTypes.string,
  /** Value of option to be highlighted on component render */
  highlightedValue: PropTypes.string,
  /** A trigger to manually reposition the list */
  repositionTrigger: PropTypes.bool
};

export default SelectList;
<commit_msg>refactor(select-list): add filter highlight for multiselect<commit_after>import React, {
  useEffect,
  useState,
  useCallback,
  useRef
} from 'react';
import PropTypes from 'prop-types';
import StyledSelectList from './select-list.style';
import updateListScrollTop from './update-list-scroll';
import getNextChildByText from '../utils/get-next-child-by-text';
import Portal from '../../portal/portal';
import { getNextIndexByKey } from '../utils/get-next-child-by-key';

const overhang = 4;

const SelectList = React.forwardRef(({
  id,
  labelId,
  children,
  onSelect,
  onSelectListClose,
  filterText,
  anchorElement,
  highlightedValue,
  repositionTrigger,
  ...listProps
}, listRef) => {
  const [currentOptionsListIndex, setCurrentOptionsListIndex] = useState(-1);
  const lastFilter = useRef('');

  const getIndexOfMatch = useCallback((valueToMatch) => {
    return React.Children.toArray(children).findIndex(child => child.props.value === valueToMatch);
  }, [children]);

  const highlightNextItem = useCallback((key, optionList) => {
    const lastIndex = optionList.length - 1;
    let nextIndex;

    if (highlightedValue) {
      const indexOfHighlighted = getIndexOfMatch(highlightedValue);

      nextIndex = getNextIndexByKey(key, indexOfHighlighted, lastIndex);
    } else {
      nextIndex = getNextIndexByKey(key, currentOptionsListIndex, lastIndex);
    }
    const { text, value } = optionList[nextIndex].props;

    setCurrentOptionsListIndex(nextIndex);
    updateListScrollTop(nextIndex, listRef.current);
    onSelect({ text, value, selectionType: 'navigationKey' });
  }, [currentOptionsListIndex, getIndexOfMatch, highlightedValue, listRef, onSelect]);

  const handleGlobalKeydown = useCallback((event) => {
    const { key } = event;
    const optionList = React.Children.toArray(children);

    if (key === 'Tab' || key === 'Escape') {
      onSelectListClose();
    } else if (key === 'Enter') {
      const currentOption = optionList[currentOptionsListIndex];

      if (!currentOption) {
        onSelectListClose();

        return;
      }

      const { text, value } = currentOption.props;

      onSelect({ text, value, selectionType: 'enterKey' });
    } else if (isNavigationKey(key)) {
      highlightNextItem(key, optionList);
    }
  }, [children, onSelectListClose, currentOptionsListIndex, onSelect, highlightNextItem]);

  const repositionList = useCallback(() => {
    if (anchorElement) {
      const inputBoundingRect = anchorElement.getBoundingClientRect();

      const top = `${window.pageYOffset + inputBoundingRect.top + inputBoundingRect.height}px`;
      const width = `${inputBoundingRect.width + 2 * overhang}px`;
      const left = `${window.pageXOffset + inputBoundingRect.left - overhang}px`;

      listRef.current.setAttribute('style', `top: ${top}; width: ${width}; left: ${left}`);
    }
  }, [anchorElement, listRef]);

  useEffect(() => {
    const keyboardEvent = 'keydown';

    document.addEventListener(keyboardEvent, handleGlobalKeydown);

    return function cleanup() {
      document.removeEventListener(keyboardEvent, handleGlobalKeydown);
    };
  }, [handleGlobalKeydown]);

  useEffect(() => {
    if (!filterText || filterText === lastFilter.current) {
      lastFilter.current = filterText;

      return;
    }

    lastFilter.current = filterText;

    setCurrentOptionsListIndex((previousIndex) => {
      const match = getNextChildByText(filterText, children, previousIndex);

      if (!match) {
        return previousIndex;
      }

      const indexOfMatch = getIndexOfMatch(match.props.value);

      updateListScrollTop(indexOfMatch, listRef.current);

      return indexOfMatch;
    });
  }, [children, filterText, getIndexOfMatch, lastFilter, listRef]);

  useEffect(() => {
    repositionList();
  }, [repositionList, repositionTrigger]);

  useEffect(() => {
    if (!highlightedValue) {
      return;
    }

    const indexOfMatch = getIndexOfMatch(highlightedValue);

    setCurrentOptionsListIndex(indexOfMatch);
    updateListScrollTop(indexOfMatch, listRef.current);
  }, [getIndexOfMatch, highlightedValue, listRef]);

  function getChildrenWithListProps() {
    return React.Children.map(children, (child, index) => {
      const newProps = {
        onSelect: handleSelect,
        isHighlighted: currentOptionsListIndex === index
      };

      return React.cloneElement(child, newProps);
    });
  }

  function handleSelect(optionData) {
    onSelect({ ...optionData, selectionType: 'click' });
  }

  function isNavigationKey(keyEvent) {
    return keyEvent === 'ArrowDown' || keyEvent === 'ArrowUp'
    || keyEvent === 'Home' || keyEvent === 'End';
  }

  return (
    <Portal onReposition={ repositionList }>
      <StyledSelectList
        id={ id }
        aria-labelledby={ labelId }
        data-element='select-list'
        role='listbox'
        ref={ listRef }
        tabIndex='0'
        { ...listProps }
      >
        { getChildrenWithListProps() }
      </StyledSelectList>
    </Portal>
  );
});

SelectList.propTypes = {
  /** The ID for the parent <div> */
  id: PropTypes.string,
  /** The Id of the label */
  labelId: PropTypes.string,
  /** Child components (such as <Option>) for the <ScrollableList> */
  children: PropTypes.node,
  /** DOM element to position the dropdown menu list relative to */
  anchorElement: PropTypes.object,
  /** A callback for when a child is selected */
  onSelect: PropTypes.func.isRequired,
  /** A callback for when the list should be closed */
  onSelectListClose: PropTypes.func.isRequired,
  /** Text value to highlight an option */
  filterText: PropTypes.string,
  /** Value of option to be highlighted on component render */
  highlightedValue: PropTypes.string,
  /** A trigger to manually reposition the list */
  repositionTrigger: PropTypes.bool
};

export default SelectList;
<|endoftext|>


<commit_before>var doc = require('doc-js'),
    EventEmitter = require('events').EventEmitter,
    interact = require('interact-js'),
    crel = require('crel'),
    venfix = require('venfix'),
    laidout = require('laidout');

function Flap(element){
    this.render(element);
    this.init();
}
Flap.prototype = Object.create(EventEmitter.prototype);

Flap.prototype.constructor = Flap;
Flap.prototype.distance = 0;
Flap.prototype.state = 'closed';
Flap.prototype.width = 280;
Flap.prototype.side = 'left';
Flap.prototype.gutter = 20;

Flap.prototype.render = function(element){
    this.element = element || crel('div',
        crel('div')
    );
    this.element.style.opacity = '0';

    this.content = this.element.childNodes[0];
    this.element.flap = this;
};
Flap.prototype.bind = function(){
    var flap = this,
        delegateTarget = doc(this.delegateTarget)[0] || document;

    // Allow starting the drag on a delegate target
    interact.on('start', delegateTarget, flap._start.bind(flap));

    // Still use document for the other events for robustness.
    interact.on('drag', document, flap._drag.bind(flap));
    interact.on('end', document, flap._end.bind(flap));
    interact.on('cancel', document, flap._end.bind(flap));

    doc(this.element).on('click', flap._activate.bind(flap));
};
Flap.prototype.init = function(){
    var flap = this;
    laidout(this.element, function(){
        flap.bind();
        if(this.enabled !== false){
            flap.enable();
        }else{
            flap.disable();
        }
        flap.emit('ready');
        flap.element.style.opacity = null;
    });
};
Flap.prototype.enable = function(){
    this.enabled = true;

    this.element.style.position = 'fixed';
    this.element.style.top = '0px';
    this.element.style.bottom = '0px';
    this.close();

    this.content.style[venfix('boxSizing')] = 'border-box';
    this.content.style.width = this.width + 'px';
    this.content.style.position = 'absolute';
    this.content.style.top = '0px';
    this.content.style.bottom = '0px';
    this.content.style.width = this.width + 'px';
    this.content.style['overflow-x'] = 'hidden';
    this.content.style['overflow-y'] = 'auto';

    if(this.side === 'left'){
        this.element.style.left = '0px';
        this.content.style.left = '0px';
    }else if(this.side === 'right'){
        this.element.style.right = '0px';
        this.content.style.left = '100%';
    }
    this.update();
};
Flap.prototype.disable = function(){
    this.enabled = false;

    this.element.style.position = null;
    this.element.style.top = null;
    this.element.style.bottom = null;
    this.element.style.width = null;
    this.element.style[venfix('pointerEvents')] = null;

    this.content.style[venfix('boxSizing')] = null;
    this.content.style[venfix('transform')] = null;
    this.content.style.width = null;
    this.content.style.position = null;
    this.content.style.top = null;
    this.content.style.bottom = null;
    this.content.style.width = null;
    this.content.style['overflow-x'] = null;
    this.content.style['overflow-y'] = null;

    this.element.style.left = null;
    this.content.style.left = null;
    this.element.style.right = null;
    this.content.style.left = null;
    this.update();
};
Flap.prototype._isValidInteraction = function(interaction){
    if(this.constructor.openFlap){
        return this.constructor.openFlap === this;
    }
    if(this.distance){
        return true;
    }
    if(this.side === 'left'){
        return interaction.pageX < this.distance + this.gutter;
    }else if(this.side === 'right'){
        return interaction.pageX > window.innerWidth - this.gutter;
    }
};
Flap.prototype._start = function(interaction){
    var flap = this;

    if(!this.enabled){
        return;
    }

    if(this._isValidInteraction(interaction)){
        this._setOpen();
    }
};
Flap.prototype._drag = function(interaction){
    var flap = this;

    if(this.constructor.openFlap === this){
        var angle = interaction.getCurrentAngle(true);
        if(angle && !this.beingDragged && ((angle > 45 && angle < 135) || (angle < -45 && angle > -135))){
            return;
        }

        interaction.preventDefault();

        flap.beingDragged = true;
        flap.startDistance = flap.startDistance || flap.distance;
        if(flap.side === 'left'){
            flap.distance = flap.startDistance + interaction.pageX - interaction.lastStart.pageX;
        }else{
            flap.distance = flap.startDistance - interaction.pageX + interaction.lastStart.pageX;
        }
        flap.distance = Math.max(Math.min(flap.distance, flap.width), 0);
        flap.update();
        flap.speed = flap.distance - flap.oldDistance;
        flap.oldDistance = flap.distance;
    }
};
Flap.prototype._end = function(interaction){
    if(this.constructor.openFlap !== this || !this.beingDragged){
        return;
    }

    this.startDistance = null;
    this.beingDragged = false;

    var direction = 'close';

    if(Math.abs(this.speed) >= 3){
        direction = this.speed < 0 ? 'close' : 'open';
    }else if(this.distance < this.width / 2){
        direction = 'close';
    }else{
        direction = 'open';
    }

    this.settle(direction);
};
Flap.prototype._activate = function(event){
    if(!this.enabled){
        return;
    }
    if(
        !doc(event.target).closest(this.content) &&
        this.constructor.openFlap === this
    ){
        event.preventDefault();
        this.beingDragged = false;
        this.settle('close');
    }
};
Flap.prototype._setOpen = function(){
    if(this.constructor.openFlap !== this){
        var flap = this;
        this.constructor.openFlap = this;
        this.element.style['width'] = '100%';
        this.state = 'open';
        this.emit('open');

        // This prevents the flap from screwing up
        // events on elements that may be under the swipe zone
        this._pointerEventTimeout = setTimeout(function(){
            flap.element.style[venfix('pointerEvents')] = 'all';
        },500);
    }
};
Flap.prototype._setClosed = function(){
    this.constructor.openFlap = null;
    clearTimeout(this._pointerEventTimeout);
    this.element.style[venfix('pointerEvents')] = 'none';
    this.element.style['width'] = this.gutter + 'px';
    this.state = 'closed';
    this.emit('close');
};
Flap.prototype.update = function(interaction){
    var flap = this;

    if(this.distance > 0){
        this._setOpen();
    }

    if(this.side === 'left'){
        this.displayPosition = flap.distance - flap.width;
    }else if(this.side === 'right'){
        this.displayPosition = -flap.distance;
    }

    if(flap.distance != flap.lastDistance){
        requestAnimationFrame(function(){
            flap.updateStyle(flap.displayPosition);
            flap.emit('move');
            flap.lastDistance = flap.distance;
        });
    }
};
Flap.prototype.updateStyle = function(displayPosition){
    if(this.enabled){
        this.content.style[venfix('transform')] = 'translate3d(' + (displayPosition) + 'px,0,0)';
    }
};
Flap.prototype.settle = function(direction){
    var flap = this;

    cancelAnimationFrame(this.settleFrame);

    if(this.beingDragged){
        return;
    }
    if(this.distance < 0){
        this.distance = 0;
        this._setClosed();
        this.update();
        this.emit('settle');
        return;
    }else if(this.distance > this.width){
        this.distance = this.width;
        this.update();
        this.emit('settle');
        return;
    }

    this.settleFrame = requestAnimationFrame(function(){
        var step = flap.tween(direction);
        flap.distance += direction === 'close' ? -step : step;
        flap.update();
        flap.settle(direction);
    });
};
Flap.prototype.tween = function(direction){
    return (this.width - this.distance) / 4 + 2;
};
Flap.prototype.percentOpen = function(){
    return parseInt(100 / this.width * this.distance);
};
Flap.prototype.open = function(){
    if(!this.enabled){
        return;
    }
    this.settle('open');
};
Flap.prototype.close = function(){
    if(!this.enabled){
        return;
    }
    this.settle('close');
};
module.exports = Flap;<commit_msg>Tweaked default settle animation, flap now hides when closed<commit_after>var doc = require('doc-js'),
    EventEmitter = require('events').EventEmitter,
    interact = require('interact-js'),
    crel = require('crel'),
    venfix = require('venfix'),
    laidout = require('laidout');

function Flap(element){
    this.render(element);
    this.init();
}
Flap.prototype = Object.create(EventEmitter.prototype);

Flap.prototype.constructor = Flap;
Flap.prototype.distance = 0;
Flap.prototype.state = 'closed';
Flap.prototype.width = 280;
Flap.prototype.side = 'left';
Flap.prototype.gutter = 20;

Flap.prototype.render = function(element){
    this.element = element || crel('div',
        crel('div')
    );
    this.element.style.opacity = '0';

    this.content = this.element.childNodes[0];
    this.element.flap = this;
};
Flap.prototype.bind = function(){
    var flap = this,
        delegateTarget = doc(this.delegateTarget)[0] || document;

    // Allow starting the drag on a delegate target
    interact.on('start', delegateTarget, flap._start.bind(flap));

    // Still use document for the other events for robustness.
    interact.on('drag', document, flap._drag.bind(flap));
    interact.on('end', document, flap._end.bind(flap));
    interact.on('cancel', document, flap._end.bind(flap));

    doc(this.element).on('click', flap._activate.bind(flap));
};
Flap.prototype.init = function(){
    var flap = this;
    laidout(this.element, function(){
        flap.bind();
        if(this.enabled !== false){
            flap.enable();
        }else{
            flap.disable();
        }
        flap.emit('ready');
        flap.element.style.opacity = null;
    });
};
Flap.prototype.enable = function(){
    this.enabled = true;

    this.element.style.position = 'fixed';
    this.element.style.top = '0px';
    this.element.style.bottom = '0px';
    this.close();

    this.content.style[venfix('boxSizing')] = 'border-box';
    this.content.style.width = this.width + 'px';
    this.content.style.position = 'absolute';
    this.content.style.top = '0px';
    this.content.style.bottom = '0px';
    this.content.style.width = this.width + 'px';
    this.content.style['overflow-x'] = 'hidden';
    this.content.style['overflow-y'] = 'auto';

    if(this.side === 'left'){
        this.element.style.left = '0px';
        this.content.style.left = '0px';
    }else if(this.side === 'right'){
        this.element.style.right = '0px';
        this.content.style.left = '100%';
    }
    this.update();
};
Flap.prototype.disable = function(){
    this.enabled = false;

    this.element.style.position = null;
    this.element.style.top = null;
    this.element.style.bottom = null;
    this.element.style.width = null;
    this.element.style[venfix('pointerEvents')] = null;
    this.element.style.display = null;

    this.content.style[venfix('boxSizing')] = null;
    this.content.style[venfix('transform')] = null;
    this.content.style.width = null;
    this.content.style.position = null;
    this.content.style.top = null;
    this.content.style.bottom = null;
    this.content.style.width = null;
    this.content.style['overflow-x'] = null;
    this.content.style['overflow-y'] = null;

    this.element.style.left = null;
    this.content.style.left = null;
    this.element.style.right = null;
    this.content.style.left = null;

    cancelAnimationFrame(this.settleFrame);

    this.update();
};
Flap.prototype._isValidInteraction = function(interaction){
    if(this.constructor.openFlap){
        return this.constructor.openFlap === this;
    }
    if(this.distance){
        return true;
    }
    if(this.side === 'left'){
        return interaction.pageX < this.distance + this.gutter;
    }else if(this.side === 'right'){
        return interaction.pageX > window.innerWidth - this.gutter;
    }
};
Flap.prototype._start = function(interaction){
    var flap = this;

    if(!this.enabled){
        return;
    }

    if(this._isValidInteraction(interaction)){
        this._setOpen();
    }
};
Flap.prototype._drag = function(interaction){
    var flap = this;

    if(this.constructor.openFlap === this){
        var angle = interaction.getCurrentAngle(true);
        if(angle && !this.beingDragged && ((angle > 45 && angle < 135) || (angle < -45 && angle > -135))){
            return;
        }

        interaction.preventDefault();

        flap.beingDragged = true;
        flap.startDistance = flap.startDistance || flap.distance;
        if(flap.side === 'left'){
            flap.distance = flap.startDistance + interaction.pageX - interaction.lastStart.pageX;
        }else{
            flap.distance = flap.startDistance - interaction.pageX + interaction.lastStart.pageX;
        }
        flap.distance = Math.max(Math.min(flap.distance, flap.width), 0);
        flap.update();
        flap.speed = flap.distance - flap.oldDistance;
        flap.oldDistance = flap.distance;
    }
};
Flap.prototype._end = function(interaction){
    if(this.constructor.openFlap !== this || !this.beingDragged){
        return;
    }

    this.startDistance = null;
    this.beingDragged = false;

    var direction = 'close';

    if(Math.abs(this.speed) >= 3){
        direction = this.speed < 0 ? 'close' : 'open';
    }else if(this.distance < this.width / 2){
        direction = 'close';
    }else{
        direction = 'open';
    }

    this.settle(direction);
};
Flap.prototype._activate = function(event){
    if(!this.enabled){
        return;
    }
    if(
        !doc(event.target).closest(this.content) &&
        this.constructor.openFlap === this
    ){
        event.preventDefault();
        this.beingDragged = false;
        this.settle('close');
    }
};
Flap.prototype._setOpen = function(){
    if(this.constructor.openFlap !== this){
        var flap = this;
        this.constructor.openFlap = this;
        this.element.style['display'] = null;
        this.state = 'open';
        this.emit('open');

        // This prevents the flap from screwing up
        // events on elements that may be under the swipe zone
        this._pointerEventTimeout = setTimeout(function(){
            flap.element.style[venfix('pointerEvents')] = 'all';
        },500);
    }
};
Flap.prototype._setClosed = function(){
    this.constructor.openFlap = null;
    clearTimeout(this._pointerEventTimeout);
    this.element.style[venfix('pointerEvents')] = 'none';
    this.element.style['display'] = 'none';
    this.state = 'closed';
    this.emit('close');
};
Flap.prototype.update = function(interaction){
    var flap = this;

    if(this.distance > 0){
        this._setOpen();
    }

    if(this.side === 'left'){
        this.displayPosition = flap.distance - flap.width;
    }else if(this.side === 'right'){
        this.displayPosition = -flap.distance;
    }

    if(flap.distance != flap.lastDistance){
        requestAnimationFrame(function(){
            flap.updateStyle(flap.displayPosition);
            flap.emit('move');
            flap.lastDistance = flap.distance;
        });
    }
};
Flap.prototype.updateStyle = function(displayPosition){
    if(this.enabled){
        this.content.style[venfix('transform')] = 'translate3d(' + (displayPosition) + 'px,0,0)';
    }
};
Flap.prototype.settle = function(direction){
    var flap = this;

    cancelAnimationFrame(this.settleFrame);

    if(this.beingDragged){
        return;
    }

    if(this.distance < 0){
        this.distance = 0;
        this._setClosed();
        this.update();
        this.emit('settle');
        return;
    }else if(this.distance > this.width){
        this.distance = this.width;
        this.update();
        this.emit('settle');
        return;
    }

    this.settleFrame = requestAnimationFrame(function(){
        var step = flap.tween(direction);
        flap.distance += direction === 'close' ? -step : step;
        flap.update();
        flap.settle(direction);
    });
};
Flap.prototype.tween = function(direction){
    return direction === 'open' ?
        (this.width - this.distance) / 3 + 1:
        this.distance / 3 + 1;
};
Flap.prototype.percentOpen = function(){
    return parseInt(100 / this.width * this.distance);
};
Flap.prototype.open = function(){
    if(!this.enabled){
        return;
    }
    this.settle('open');
};
Flap.prototype.close = function(){
    if(!this.enabled){
        return;
    }
    this.settle('close');
};
module.exports = Flap;<|endoftext|>


<commit_before>/*************************************************************************
 float.js 1.0 Copyright (c) 2013 Heinrich Schweitzer
 Contact me at hgs@hgsweb.de
 This copyright notice MUST stay intact for use.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 'Software'), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

/*//////////////////////////////////////////////////////////////
 Creates divs to mimic the table header.

 This header is allways displayed at the top of the table, if
 the original header is scrolled out of view.

 To use this funtion your table must have an id speficied.
 Once alle tables are rendered you call floatHeader(tableId),
 this returns the header object.

 /////////////////////////////////////////////////////////////*/

function floatHeader(tableId, head) {
    'use strict';
    function setAtt(s, o) {
        var opt;
        for (opt in o) {
            s[opt] = o[opt];
        }
        return s;
    }
    function absPos(obj) {
        var ob, pos = {};
        pos.x = obj.offsetLeft;
        pos.y = obj.offsetTop;
        ob = obj.offsetParent;
        while (ob.tagName !== 'BODY') {
            pos.x += ob.offsetLeft;
            pos.y += ob.offsetTop;
            ob = ob.offsetParent;
        }
        return pos;
    }
    function createDivHead(mytable, x) {
        var div = document.createElement('div');
        setAtt(div, {id: 'float_' + mytable.id,
            className: 'outerFloatHead'}
        );
        setAtt(div.style, {zIndex: 15,
            width: mytable.clientWidth + 'px',
            position: 'absolute',
            left: x + 'px'
        }
        );
        return div;
    }
    function createDivCornerHead(mytable, x) {
        var div = document.createElement('div');
        setAtt(div, {id: 'floatcorner_' + mytable.id,
            className: 'floatCorner'}
        );
        setAtt(div.style, {zIndex: 15,
            position: 'absolute',
            left: x + 'px',
            height: mytable.rows[0].cells[0].clientHeight + 'px'}
        );
        return div;
    }
    function createDivLeftColumn(mytable, x) {
        var div = document.createElement('div');
        setAtt(div, {id: 'floatleftcolumn_' + mytable.id,
            className: 'outerFloatHead'}
        );
        setAtt(div.style, {zIndex: 12,
            position: 'absolute',
            left: x + 'px',
            height: mytable.rows[0].cells[0].clientHeight + 'px'}
        );
        return div;
    }
    function copyHeaderCell(theCell, top, ci) {
        var div = document.createElement('div');
        setAtt(div, {className: 'floatHead',
            innerHTML: theCell.innerHTML,
            cellIndex: ci}
        );
        setAtt(div.style, {
            position: 'absolute',
            left: theCell.offsetLeft + 'px',
            top: top + 'px',
            width: theCell.clientWidth + 'px'
        }
        );
        return div;
    }
    function copyLeftColumn(theCell, top, ci, ri) {
        var div = document.createElement('div');
        setAtt(div, {className: 'floatCol',
            innerHTML: theCell.innerHTML,
            cellIndex: ci,
            rowIndex: ri}
        );
        setAtt(div.style, {
            position: 'absolute',
            left: theCell.offsetLeft + 'px',
            top: top + 'px',
            width: theCell.clientWidth + 'px'}
        );
        return div;
    }
    var mytable
            , row = [], floatPos
            , i, nc, nr, th,  height, delta
            , k, tf, tlc = {}, lc = {}, lcTop, lcw = 0
            , tlcw = 0;
    if (typeof head === 'undefined') {
        var head = {ncpth: [], nccol: 0};
    }

    mytable = document.getElementById(tableId);
    floatPos = absPos(mytable);
    tf = createDivHead(mytable, floatPos.x); // entire header

    if (typeof head === 'undefined') {
        var head = {ncpth: [], nccol: 0}; // default
    } else {
        tlc = createDivCornerHead(mytable, floatPos.x); // top left corener
        lc = createDivLeftColumn(mytable, floatPos.x); //  left column
        tlc.style.top = floatPos.y + 'px';
        tlc.x = 0;
    }
    //////////////////////////////
    /// header rows only
    /////////////////////////////
    document.body.appendChild(tf);
    tf.style.top = floatPos.y + 'px';
    nr = mytable.rows.length;
    if (head.nccol > 0) {
        document.body.appendChild(tlc);
    }
    for (k = 0; k < nr; k++) {
        if (mytable.rows[k].cells[0].tagName !== 'TH') {
            break;
        }
        row = mytable.rows[k];
        nc = row.cells.length;
        for (i = 0; i < nc; i++) { // copy content of header cells from table
            th = copyHeaderCell(row.cells[i], row.cells[i].offsetTop, i);
            tf.appendChild(th);
            th.style.height = row.cells[i].clientHeight + 'px';
            if (k < head.ncpth.length) {// copy cells into top left corner div
                if (i < head.ncpth[k]) {
                    th = copyHeaderCell(row.cells[i], row.cells[i].offsetTop, i);
                    tlc.appendChild(th);
                    th.style.height = row.cells[i].clientHeight + 'px';
                    tlcw = row.cells[i].offsetLeft + row.cells[i].clientWidth;
                }
            }
        }
    }
    tf.style.height = row.offsetTop + row.clientHeight +'px';
    tf.rightEdge = 0;
    ///////////////////////
    //// left column cells  only
    ///////////////////////
    if (head.nccol > 0) {
        document.body.appendChild(lc);
        lcTop = absPos(mytable.rows[k].cells[0]).y;
        lcw = 0;
        delta = mytable.rows[k].offsetTop;
        for (; k < nr; k++) {
            row = mytable.rows[k];
            nc = row.cells.length;
            for (i = 0; i < head.nccol; i++) { // copy content of column cells from table
                th = copyLeftColumn(row.cells[i], row.cells[i].offsetTop - delta, i, row.rowIndex);
                lc.appendChild(th);
            }
        }
        lcw = row.cells[head.nccol - 1].offsetLeft + row.cells[head.nccol - 1].clientWidth;
        height = row.offsetTop + row.clientHeight;
    }

    if (head.nccol > 0) {
        lc.style.top = lcTop + 'px';
        lc.style.height = height - delta + 'px';
        lc.style.width = lcw + 'px';
        lc.style.display = 'none';
        tlc.style.height = tf.style.height;
        tlc.rightEdge = floatPos.x + tf.clientWidth - lcw - /*lastcell*/ mytable.rows[nr - 1].cells[nc - 1].clientWidth;
        tlc.left = floatPos.x;
        tlc.x = floatPos.x;
        tlc.style.height = tf.style.heigh;
        tlc.style.width = tlcw + 2 + 'px';
        tlc.style.display = 'none';
        tf.rightEdge = tlc.rightEdge;
    }
    tf.ybottom = floatPos.y + mytable.clientHeight - tf.clientHeight - mytable.rows[nr - 1].clientHeight;
    tf.tabtop = floatPos.y;
    tf.x = floatPos.x;
    tf.y = floatPos.y;
    tf.left = floatPos.x;
    tf.top = floatPos.y;
    tf.right = tf.left + mytable.clientWidth;
    tf.bottom = tf.top + mytable.clientHeight;
    tf.style.display = 'none';

    function scroll() { // does the scrolling as event handler
        var y, x, ypx, xpx;
        y = window.pageYOffset;
        x = head.nccol > 0 ? window.pageXOffset : 0;
        /////////////////////////////////// vertical scrolling /////////////////////////
        if (y === 0) {
            if (tf.style.display !== 'none') {
                tf.style.display = 'none';
                tlc.style.display = 'none';
                tf.style.top = floatPos.y + 'px';
                tlc.style.top = floatPos.y + 'px';
            }
        } else {
            if (y > tf.ybottom) {
                return;
            }
            if (tf.tabtop - y < 0) {
                ypx = y + 'px';
                if (tf.y !== ypx) {
                    tf.style.top = ypx;
                    tlc.style.top = ypx;
                    tf.y = ypx;
                    if (tf.style.display === 'none') {
                        tf.style.display = 'block';
                        tlc.style.display = 'block';
                    }
                }
            } else {
                if (tf.style.display !== 'none') {
                    tf.style.display = 'none';
                    tlc.style.display = 'none';
                    tf.style.top = floatPos.y + 'px';
                    tlc.style.top = floatPos.y + 'px';
                }
            }
        }
        /////////////////////////////// horizontal scrolling //////////////////
        if (x === 0) {
            if (tlc.style.display !== 'none') {
                tlc.style.display = 'none';
                lc.style.display = 'none';
            }
            return;
        } else {
            if (x >= tf.rightEdge) {
                return;
            }
            if (tlc.left <= x && x < tf.rightEdge) {
                xpx = x + 'px';
                if (tlc.x !== xpx) {
                    tlc.style.left = xpx;
                    lc.style.left = xpx;
                    tlc.x = xpx;
                    if (tlc.style.display === 'none') {
                        tlc.style.display = 'block';
                        lc.style.display = 'block';
                    }
                } else if (tlc.style.display === 'none') {
                    tlc.style.display = 'block';
                }
                return;
            } else {
                if (tlc.style.display !== 'none') {
                    tlc.style.display = 'none';
                    lc.style.display = 'none';
                }
                return;
            }
        }

    }
    tf.sync = function() { // method to force a new layout of pseudo header
        var mytable, nc, k, i, l,theCell;
        mytable = document.getElementById(this.id.split('_')[1]);
        nr = mytable.rows.length;

        for (k = 0, l = 0; k < nr; k++) {
            if (mytable.rows[k].cells[0].tagName !== 'TH') {
                break;
            }
            nc = mytable.rows[k].cells.length;
            for (i = 0; i < nc; i++) {
                th = tf.childNodes[l];
                l++;
                theCell = mytable.rows[k].cells[i];
                th.innerHTML = theCell.innerHTML;
                th.style.left = theCell.offsetLeft + 'px';
                th.style.width = theCell.clientWidth + 'px';
            }
        }
    };
    function addEvent(obj, ev, fu) {
        if (obj.addEventListener) {
            obj.addEventListener(ev, fu, false);
        } else {
            var eev = 'on' + ev;
            obj.attachEvent(eev, fu);
        }
    }
    addEvent(window, 'scroll', scroll);
    // pointers to corner and left column;
    tf.tlc=tlc;
    tf.lc=lc;
    return tf;
}
<commit_msg>adde functions to keep floating elemnts in sync with any changes made insed tables<commit_after>/*************************************************************************
 float.js 1.0 Copyright (c) 2013 Heinrich Schweitzer
 Contact me at hgs@hgsweb.de
 This copyright notice MUST stay intact for use.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 'Software'), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

/*//////////////////////////////////////////////////////////////
 Creates divs to mimic the table header.

 This header is allways displayed at the top of the table, if
 the original header is scrolled out of view.

 To use this funtion your table must have an id speficied.
 Once alle tables are rendered you call floatHeader(tableId),
 this returns the header object.

 /////////////////////////////////////////////////////////////*/

function floatHeader(tableId, head) {
    'use strict';
    function setAtt(s, o) {
        var opt;
        for (opt in o) {
            s[opt] = o[opt];
        }
        return s;
    }
    function absPos(obj) {
        var ob, pos = {};
        pos.x = obj.offsetLeft;
        pos.y = obj.offsetTop;
        ob = obj.offsetParent;
        while (ob.tagName !== 'BODY') {
            pos.x += ob.offsetLeft;
            pos.y += ob.offsetTop;
            ob = ob.offsetParent;
        }
        return pos;
    }
    function createDivHead(mytable, x) {
        var div = document.createElement('div');
        setAtt(div, {id: 'float_' + mytable.id,
            className: 'outerFloatHead'}
        );
        setAtt(div.style, {zIndex: 15,
            width: mytable.clientWidth + 'px',
            left: x + 'px'
        }
        );
        return div;
    }
    function createDivCornerHead(mytable, x) {
        var div = document.createElement('div');
        setAtt(div, {id: 'floatcorner_' + mytable.id,
            className: 'floatCorner'}
        );
        setAtt(div.style, {zIndex: 15,
            left: x + 'px',
            height: mytable.rows[0].cells[0].clientHeight + 'px'}
        );
        return div;
    }
    function createDivLeftColumn(mytable, x) {
        var div = document.createElement('div');
        setAtt(div, {id: 'floatleftcolumn_' + mytable.id,
            className: 'outerFloatHead'}
        );
        setAtt(div.style, {zIndex: 12,
            left: x + 'px',
            height: mytable.rows[0].cells[0].clientHeight + 'px'}
        );
        return div;
    }
    function createHeaderCell(theCell, top, ci) {
        var div = document.createElement('div');
        updateHeaderCell(div, theCell, top, ci);
        return div;
    }
    function updateHeaderCell(div, theCell, top, ci) {
        setAtt(div, {className: 'floatHead',
            innerHTML: theCell.innerHTML,
            cellIndex: ci}
        );
        setAtt(div.style, {
            left: theCell.offsetLeft + 'px',
            top: top + 'px',
            width: theCell.clientWidth + 'px'
        }
        );
        return div;
    }
    function createLeftColumn(theCell, top, ci, ri) {
        var div = document.createElement('div');
        updateLeftColumn(div, theCell, top, ci, ri);
        return div;
    }
    function updateLeftColumn(div, theCell, top, ci, ri) {
        setAtt(div, {className: 'floatCol',
            innerHTML: theCell.innerHTML,
            cellIndex: ci,
            rowIndex: ri}
        );
        setAtt(div.style, {
            left: theCell.offsetLeft + 'px',
            top: top + 'px',
            width: theCell.clientWidth + 'px',
            height: theCell.clientHeight + 'px'}
        );
        return div;
    }
    function setLeftColumnGeomtry(head) {
        lc.style.top = absPos(mytable.rows[head.ncpth.length].cells[0]).y + 'px';
        lc.style.left = floatPos.x + 'px';
        lc.style.height = mytable.clientHeight - mytable.rows[head.ncpth.length].offsetTop + 'px';
        lc.style.width = lcw + 'px';
    }
    function setTopLeftCornerGeometry() {
        var nr, nc;
        nr = mytable.rows.length;
        nc = mytable.rows[nr - 1].cells.length;
        tlc.style.height = tf.style.height;
        tlc.rightEdge = floatPos.x + mytable.clientWidth - lcw - /*lastcell*/ mytable.rows[nr - 1].cells[nc - 1].clientWidth;
        tlc.left = floatPos.x;
        tlc.x = floatPos.x;
        tlc.style.left = floatPos.x + 'px';
        tlc.style.top = floatPos.y + 'px';
        tlc.style.height = tf.style.heigh;
        tlc.style.width = lcw + 2 + 'px';
        tf.rightEdge = tlc.rightEdge;
    }
    function setTableHeadGeometry() {
        tf.ybottom = floatPos.y + mytable.clientHeight - tf.clientHeight - /*last row*/ mytable.rows[nr - 1].clientHeight;
        tf.tabtop = floatPos.y;
        tf.x = floatPos.x;
        tf.y = floatPos.y;
        tf.left = floatPos.x;
        tf.top = floatPos.y;
        tf.right = tf.left + mytable.clientWidth;
        tf.bottom = tf.top + mytable.clientHeight;
        tf.style.left = floatPos.x + 'px';
        tf.style.top = floatPos.y + 'px';
        tf.style.width = mytable.clientWidth + 'px';
    }
    var mytable
            , row = [], floatPos
            , i, nc, nr, th, delta
            , k, tf, tlc = {}, lc = {}, lcw = 0;

    if (typeof head === 'undefined') {
        var head = {ncpth: [], nccol: 0};
    }

    mytable = document.getElementById(tableId);
    floatPos = absPos(mytable);
    tf = createDivHead(mytable, floatPos.x); // entire header

    if (typeof head === 'undefined') {
        var head = {ncpth: [], nccol: 0}; // default
    } else {
        tlc = createDivCornerHead(mytable, floatPos.x); // top left corener
        lc = createDivLeftColumn(mytable, floatPos.x); //  left column
        tlc.style.top = floatPos.y + 'px';
        tlc.x = 0;
    }
    //////////////////////////////
    /// header rows only
    /////////////////////////////
    document.body.appendChild(tf);
    tf.style.top = floatPos.y + 'px';
    nr = mytable.rows.length;
    if (head.nccol > 0) {
        document.body.appendChild(tlc);
    }
    for (k = 0; k < nr; k++) {
        if (mytable.rows[k].cells[0].tagName !== 'TH') {
            break;
        }
        row = mytable.rows[k];
        nc = row.cells.length;
        for (i = 0; i < nc; i++) { // copy content of header cells from table
            th = createHeaderCell(row.cells[i], row.cells[i].offsetTop, i);
            tf.appendChild(th);
            th.style.height = row.cells[i].clientHeight + 'px';
            if (k < head.ncpth.length && i < head.ncpth[k]) {// copy cells into top left corner div
                th = createHeaderCell(row.cells[i], row.cells[i].offsetTop, i);
                tlc.appendChild(th);
                th.style.height = row.cells[i].clientHeight + 'px';
            }
        }
    }
    tf.style.height = row.offsetTop + row.clientHeight + 'px';
    tf.rightEdge = 0;
    ///////////////////////
    //// left column cells  only
    ///////////////////////
    if (head.nccol > 0) {
        document.body.appendChild(lc);
        lcw = 0;
        delta = mytable.rows[head.ncpth.length].offsetTop;
        for (/*k from loop above*/; k < nr; k++) {
            row = mytable.rows[k];
            nc = row.cells.length;
            for (i = 0; i < head.nccol; i++) { // copy content of column cells from table
                th = createLeftColumn(row.cells[i], row.cells[i].offsetTop - delta, i, row.rowIndex);
                lc.appendChild(th);
            }
        }
        lcw = row.cells[head.nccol - 1].offsetLeft + row.cells[head.nccol - 1].clientWidth;
        setLeftColumnGeomtry(head);
        lc.style.display = 'none';
        setTopLeftCornerGeometry();
        tlc.style.display = 'none';
    }
    setTableHeadGeometry();
    tf.style.display = 'none';

    function scroll() { // does the scrolling as event handler
        var y, x, ypx, xpx;
        y = window.pageYOffset;
        x = head.nccol > 0 ? window.pageXOffset : 0;
        /////////////////////////////////// vertical scrolling /////////////////////////
        if (y === 0) {
            if (tf.style.display !== 'none') {
                tf.style.display = 'none';
                tlc.style.display = 'none';
                tf.style.top = tf.top + 'px';
                tlc.style.top = tf.style.top;
            }
        } else {
            if (y > tf.ybottom) {
                return;
            }
            if (tf.tabtop - y < 0) {
                ypx = y + 'px';
                if (tf.y !== ypx) {
                    tf.style.top = ypx;
                    tlc.style.top = ypx;
                    tf.y = ypx;
                    if (tf.style.display === 'none') {
                        tf.style.display = '';
                        tlc.style.display = '';
                    }
                }
            } else {
                if (tf.style.display !== 'none') {
                    tf.style.display = 'none';
                    tlc.style.display = 'none';
                    tf.style.top = tf.top + 'px';
                    tlc.style.top = tf.style.top;
                }
            }
        }
        /////////////////////////////// horizontal scrolling //////////////////
        if (x === 0) {
            if (tlc.style.display !== 'none') {
                tlc.style.display = 'none';
                lc.style.display = 'none';
            }
            return;
        } else {
            if (x >= tf.rightEdge) {
                return;
            }
            if (tlc.left <= x && x < tf.rightEdge) {
                xpx = x + 'px';
                if (tlc.x !== xpx) {
                    tlc.style.left = xpx;
                    lc.style.left = xpx;
                    tlc.x = xpx;
                    if (tlc.style.display === 'none') {
                        tlc.style.display = '';
                        lc.style.display = '';
                    }
                } else if (tlc.style.display === 'none') {
                    tlc.style.display = '';
                }
                return;
            } else {
                if (tlc.style.display !== 'none') {
                    tlc.style.display = 'none';
                    lc.style.display = 'none';
                }
                return;
            }
        }
    }
    tf.sync = function(ri, what) { // method to force a new layout of pseudo header
        var mytable, nc, nr, k, i, j, l, th, row;
        mytable = document.getElementById(this.id.split('_')[1]);
        nr = mytable.rows.length;
        floatPos = absPos(mytable);
        for (k = 0, j = 0, l = 0; k < nr; k++) {
            if (mytable.rows[k].cells[0].tagName !== 'TH') {
                break;
            }
            row = mytable.rows[k];
            nc = row.cells.length;
            for (i = 0; i < nc; i++) { // copy content of header cells from table
                th = updateHeaderCell(tf.childNodes[j++], row.cells[i], row.cells[i].offsetTop, i);
                th.style.height = row.cells[i].clientHeight + 'px';
                if (k < head.ncpth.length && i < head.ncpth[k]) {// copy cells into top left corner div
                    th = updateHeaderCell(tlc.childNodes[l++], row.cells[i], row.cells[i].offsetTop, i);
                    th.style.height = row.cells[i].clientHeight + 'px';
                }
            }
        }
        if (head.nccol > 0) {
            this.row(ri, what);
            row = mytable.rows[head.ncpth.length];
            lcw = row.cells[head.nccol - 1].offsetLeft + row.cells[head.nccol - 1].clientWidth;
            setLeftColumnGeomtry(head);
            setTopLeftCornerGeometry();
        }
        setTableHeadGeometry();
    };
    tf.row = function(ri, what) { // method to force a new layout of pseudo header
        var mytable, nc, k, row, j, i;
        mytable = document.getElementById(this.id.split('_')[1]);
        nr = mytable.rows.length;
        ri = ri * 1;
        what = what * 1;
        if (what === 1) {// insert
            row = mytable.rows[ri];
            nc = row.cells.length;
            for (i = 0; i < head.nccol; i++) { // copy content of column cells from table
                th = createLeftColumn(row.cells[i], row.cells[i].offsetTop - delta, i, ri);
                tf.lc.appendChild(th);
            }
        } else if (what === -1) {// delete
            // delete a pseudo row from left column
            for (k = 0; k < head.nccol; k++) {
                tf.lc.removeChild(tf.lc.childNodes[0]);
            }
        }
        //////////////////////////////
        /// brute force sync/rearange left columns
        /// //////////////////////////
        for (k = head.ncpth.length, j = 0; k < mytable.rows.length; k++) {
            row = mytable.rows[k];
            for (i = 0; i < head.nccol; i++) { // copy content of column cells from table
                updateLeftColumn(tf.lc.childNodes[j++], row.cells[i], row.cells[i].offsetTop - delta, i, row.rowIndex);
            }
        }
        return;
    };
    function addEvent(obj, ev, fu) {
        if (obj.addEventListener) {
            obj.addEventListener(ev, fu, false);
        } else {
            var eev = 'on' + ev;
            obj.attachEvent(eev, fu);
        }
    }
    addEvent(window, 'scroll', scroll);
    // pointers to corner and left column;
    tf.tlc = tlc;
    tf.lc = lc;
    return tf;
}<|endoftext|>


<commit_before>import React from 'react';

export default [
  { label: 'H1', button: H1, style: 'header-1' },
  { label: 'H2', button: H2, style: 'header-2' },
  { label: 'H3', button: H3, style: 'header-3' },
  { label: 'H4', button: H4, style: 'header-4' },
  { label: 'Blockquote', button: ", style: 'blockquote' },
  { label: 'UL', button: UL, style: 'unordered-list-item' },
  { label: 'OL', button: OL, style: 'ordered-list-item' },
  { label: 'Code Block', button: #, style: 'code-block' },
];
<commit_msg>fixed block type naming mistake<commit_after>import React from 'react';

export default [
  { label: 'H1', button: H1, style: 'header-one' },
  { label: 'H2', button: H2, style: 'header-two' },
  { label: 'H3', button: H3, style: 'header-three' },
  { label: 'H4', button: H4, style: 'header-four' },
  { label: 'Blockquote', button: ", style: 'blockquote' },
  { label: 'UL', button: UL, style: 'unordered-list-item' },
  { label: 'OL', button: OL, style: 'ordered-list-item' },
  { label: 'Code Block', button: #, style: 'code-block' },
];
<|endoftext|>


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

    function EditorContentHeader(serverValidationManager, localizationService, editorState) {

        function link(scope, el, attr, ctrl) {

            var unsubscribe = [];

            if (!scope.serverValidationNameField) {
                scope.serverValidationNameField = "Name";
            }
            if (!scope.serverValidationAliasField) {
                scope.serverValidationAliasField = "Alias";
            }

            scope.isNew = scope.content.state == "NotCreated";

            localizationService.localizeMany([
                    scope.isNew ? "placeholders_a11yCreateItem" : "placeholders_a11yEdit",
                    "placeholders_a11yName"]
            ).then(function (data) {
                scope.a11yMessage = data[0];
                scope.a11yName = data[1];
                if (!scope.isNew) {
                    scope.a11yMessage += " " + scope.content.name;

                } else {
                    var name = editorState.current.contentTypeName;
                    scope.a11yMessage += " " + name;
                    scope.a11yName = name + " " + scope.a11yName;
                }
            });
            scope.vm = {};
            scope.vm.dropdownOpen = false;
            scope.vm.currentVariant = "";
            scope.vm.variantsWithError = [];
            scope.vm.defaultVariant = null;

            scope.vm.errorsOnOtherVariants = false;// indicating wether to show that other variants, than the current, have errors.

            function checkErrorsOnOtherVariants() {
                var check = false;
                angular.forEach(scope.content.variants, function (variant) {
                    if (scope.openVariants.indexOf(variant.language.culture) === -1 && scope.variantHasError(variant.language.culture)) {
                        check = true;
                    }
                });
                scope.vm.errorsOnOtherVariants = check;
            }

            function onCultureValidation(valid, errors, allErrors, culture) {
                var index = scope.vm.variantsWithError.indexOf(culture);
                if(valid === true) {
                    if (index !== -1) {
                        scope.vm.variantsWithError.splice(index, 1);
                    }
                } else {
                    if (index === -1) {
                        scope.vm.variantsWithError.push(culture);
                    }
                }
                checkErrorsOnOtherVariants();
            }

            function onInit() {

                // find default.
                angular.forEach(scope.content.variants, function (variant) {
                    if (variant.language.isDefault) {
                        scope.vm.defaultVariant = variant;
                    }
                });

                setCurrentVariant();

                angular.forEach(scope.content.apps, (app) => {
                    if (app.alias === "umbContent") {
                        app.anchors = scope.content.tabs;
                    }
                });

                angular.forEach(scope.content.variants, function (variant) {
                    unsubscribe.push(serverValidationManager.subscribe(null, variant.language.culture, null, onCultureValidation));
                });

                unsubscribe.push(serverValidationManager.subscribe(null, null, null, onCultureValidation));

            }

            function setCurrentVariant() {
                angular.forEach(scope.content.variants, function (variant) {
                    if (variant.active) {
                        scope.vm.currentVariant = variant;
                        checkErrorsOnOtherVariants();
                    }
                });
            }

            scope.goBack = function () {
                if (scope.onBack) {
                    scope.onBack();
                }
            };

            scope.selectVariant = function (event, variant) {

                if (scope.onSelectVariant) {
                    scope.vm.dropdownOpen = false;
                    scope.onSelectVariant({ "variant": variant });
                }
            };

            scope.selectNavigationItem = function(item) {
                if(scope.onSelectNavigationItem) {
                    scope.onSelectNavigationItem({"item": item});
                }
            }

            scope.selectAnchorItem = function(item, anchor) {
                if(scope.onSelectAnchorItem) {
                    scope.onSelectAnchorItem({"item": item, "anchor": anchor});
                }
            }

            scope.closeSplitView = function () {
                if (scope.onCloseSplitView) {
                    scope.onCloseSplitView();
                }
            };

            scope.openInSplitView = function (event, variant) {
                if (scope.onOpenInSplitView) {
                    scope.vm.dropdownOpen = false;
                    scope.onOpenInSplitView({ "variant": variant });
                }
            };

            /**
             * keep track of open variants - this is used to prevent the same variant to be open in more than one split view
             * @param {any} culture
             */
            scope.variantIsOpen = function(culture) {
                return (scope.openVariants.indexOf(culture) !== -1);
            }

            /**
             * Check whether a variant has a error, used to display errors in variant switcher.
             * @param {any} culture
             */
            scope.variantHasError = function(culture) {
                // if we are looking for the default language we also want to check for invariant.
                if (culture === scope.vm.defaultVariant.language.culture) {
                    if(scope.vm.variantsWithError.indexOf("invariant") !== -1) {
                        return true;
                    }
                }
                if(scope.vm.variantsWithError.indexOf(culture) !== -1) {
                    return true;
                }
                return false;
            }

            onInit();

            //watch for the active culture changing, if it changes, update the current variant
            if (scope.content.variants) {
                scope.$watch(function () {
                    for (var i = 0; i < scope.content.variants.length; i++) {
                        var v = scope.content.variants[i];
                        if (v.active) {
                            return v.language.culture;
                        }
                    }
                    return scope.vm.currentVariant.language.culture; //should never get here
                }, function (newValue, oldValue) {
                    if (newValue !== scope.vm.currentVariant.language.culture) {
                        setCurrentVariant();
                    }
                });
            }

            scope.$on('$destroy', function () {
                for (var u in unsubscribe) {
                    unsubscribe[u]();
                }
            });
        }

        var directive = {
            transclude: true,
            restrict: 'E',
            replace: true,
            templateUrl: 'views/components/editor/umb-editor-content-header.html',
            scope: {
                name: "=",
                nameDisabled: "<?",
                menu: "=",
                hideActionsMenu: "<?",
                content: "=",
                openVariants: "<",
                hideChangeVariant: "<?",
                onSelectNavigationItem: "&?",
                onSelectAnchorItem: "&?",
                showBackButton: "<?",
                onBack: "&?",
                splitViewOpen: "=?",
                onOpenInSplitView: "&?",
                onCloseSplitView: "&?",
                onSelectVariant: "&?",
                serverValidationNameField: "@?",
                serverValidationAliasField: "@?"
            },
            link: link
        };

        return directive;
    }

    angular.module('umbraco.directives').directive('umbEditorContentHeader', EditorContentHeader);

})();
<commit_msg>First pass at set page title for content page<commit_after>(function () {
    'use strict';

    function EditorContentHeader(serverValidationManager, localizationService, editorState) {

        function link(scope, el, attr, ctrl) {

            var unsubscribe = [];

            if (!scope.serverValidationNameField) {
                scope.serverValidationNameField = "Name";
            }
            if (!scope.serverValidationAliasField) {
                scope.serverValidationAliasField = "Alias";
            }

            scope.isNew = scope.content.state == "NotCreated";

            localizationService.localizeMany([
                    scope.isNew ? "placeholders_a11yCreateItem" : "placeholders_a11yEdit",
                "placeholders_a11yName",
                    scope.isNew?"general_new":"general_edit"]
            ).then(function (data) {
                scope.a11yMessage = data[0];
                scope.a11yName = data[1];
                var title = data[2] +":";
                if (!scope.isNew) {
                    scope.a11yMessage += " " + scope.content.name;
                    title += scope.content.name;
                } else {
                    var name = editorState.current.contentTypeName;
                    scope.a11yMessage += " " + name;
                    scope.a11yName = name + " " + scope.a11yName;
                    title += name;
                }
                scope.$root.locationTitle = title + " - " + scope.$root.locationTitle ;
            });
            scope.vm = {};
            scope.vm.dropdownOpen = false;
            scope.vm.currentVariant = "";
            scope.vm.variantsWithError = [];
            scope.vm.defaultVariant = null;

            scope.vm.errorsOnOtherVariants = false;// indicating wether to show that other variants, than the current, have errors.

            function checkErrorsOnOtherVariants() {
                var check = false;
                angular.forEach(scope.content.variants, function (variant) {
                    if (scope.openVariants.indexOf(variant.language.culture) === -1 && scope.variantHasError(variant.language.culture)) {
                        check = true;
                    }
                });
                scope.vm.errorsOnOtherVariants = check;
            }

            function onCultureValidation(valid, errors, allErrors, culture) {
                var index = scope.vm.variantsWithError.indexOf(culture);
                if(valid === true) {
                    if (index !== -1) {
                        scope.vm.variantsWithError.splice(index, 1);
                    }
                } else {
                    if (index === -1) {
                        scope.vm.variantsWithError.push(culture);
                    }
                }
                checkErrorsOnOtherVariants();
            }

            function onInit() {

                // find default.
                angular.forEach(scope.content.variants, function (variant) {
                    if (variant.language.isDefault) {
                        scope.vm.defaultVariant = variant;
                    }
                });

                setCurrentVariant();

                angular.forEach(scope.content.apps, (app) => {
                    if (app.alias === "umbContent") {
                        app.anchors = scope.content.tabs;
                    }
                });

                angular.forEach(scope.content.variants, function (variant) {
                    unsubscribe.push(serverValidationManager.subscribe(null, variant.language.culture, null, onCultureValidation));
                });

                unsubscribe.push(serverValidationManager.subscribe(null, null, null, onCultureValidation));

            }

            function setCurrentVariant() {
                angular.forEach(scope.content.variants, function (variant) {
                    if (variant.active) {
                        scope.vm.currentVariant = variant;
                        checkErrorsOnOtherVariants();
                    }
                });
            }

            scope.goBack = function () {
                if (scope.onBack) {
                    scope.onBack();
                }
            };

            scope.selectVariant = function (event, variant) {

                if (scope.onSelectVariant) {
                    scope.vm.dropdownOpen = false;
                    scope.onSelectVariant({ "variant": variant });
                }
            };

            scope.selectNavigationItem = function(item) {
                if(scope.onSelectNavigationItem) {
                    scope.onSelectNavigationItem({"item": item});
                }
            }

            scope.selectAnchorItem = function(item, anchor) {
                if(scope.onSelectAnchorItem) {
                    scope.onSelectAnchorItem({"item": item, "anchor": anchor});
                }
            }

            scope.closeSplitView = function () {
                if (scope.onCloseSplitView) {
                    scope.onCloseSplitView();
                }
            };

            scope.openInSplitView = function (event, variant) {
                if (scope.onOpenInSplitView) {
                    scope.vm.dropdownOpen = false;
                    scope.onOpenInSplitView({ "variant": variant });
                }
            };

            /**
             * keep track of open variants - this is used to prevent the same variant to be open in more than one split view
             * @param {any} culture
             */
            scope.variantIsOpen = function(culture) {
                return (scope.openVariants.indexOf(culture) !== -1);
            }

            /**
             * Check whether a variant has a error, used to display errors in variant switcher.
             * @param {any} culture
             */
            scope.variantHasError = function(culture) {
                // if we are looking for the default language we also want to check for invariant.
                if (culture === scope.vm.defaultVariant.language.culture) {
                    if(scope.vm.variantsWithError.indexOf("invariant") !== -1) {
                        return true;
                    }
                }
                if(scope.vm.variantsWithError.indexOf(culture) !== -1) {
                    return true;
                }
                return false;
            }

            onInit();

            //watch for the active culture changing, if it changes, update the current variant
            if (scope.content.variants) {
                scope.$watch(function () {
                    for (var i = 0; i < scope.content.variants.length; i++) {
                        var v = scope.content.variants[i];
                        if (v.active) {
                            return v.language.culture;
                        }
                    }
                    return scope.vm.currentVariant.language.culture; //should never get here
                }, function (newValue, oldValue) {
                    if (newValue !== scope.vm.currentVariant.language.culture) {
                        setCurrentVariant();
                    }
                });
            }

            scope.$on('$destroy', function () {
                for (var u in unsubscribe) {
                    unsubscribe[u]();
                }
            });
        }

        var directive = {
            transclude: true,
            restrict: 'E',
            replace: true,
            templateUrl: 'views/components/editor/umb-editor-content-header.html',
            scope: {
                name: "=",
                nameDisabled: "<?",
                menu: "=",
                hideActionsMenu: "<?",
                content: "=",
                openVariants: "<",
                hideChangeVariant: "<?",
                onSelectNavigationItem: "&?",
                onSelectAnchorItem: "&?",
                showBackButton: "<?",
                onBack: "&?",
                splitViewOpen: "=?",
                onOpenInSplitView: "&?",
                onCloseSplitView: "&?",
                onSelectVariant: "&?",
                serverValidationNameField: "@?",
                serverValidationAliasField: "@?"
            },
            link: link
        };

        return directive;
    }

    angular.module('umbraco.directives').directive('umbEditorContentHeader', EditorContentHeader);

})();
<|endoftext|>


<commit_before>'use strict'

const startOfDay = require('date-fns/start_of_day')
const {waterfall, asyncify} = require('async')
const {assign, isFinite, round} = require('lodash')
const osom = require('osom')

const getReferralLink = require('./get-referral-link')
const getCondition = require('./get-condition')

const prettyTitle = require('./transform/pretty-title')
const isValidCondition = require('./validate/condition')
const isValidSailSize = require('./validate/sail-size')
const isValidTitle = require('./validate/title')
const isValidPrice = require('./validate/price')
const serializer = require('./serializer')
const isUrl = require('../util/is-url')

const validator = osom({
  /* common */
  title: {
    required: true,
    type: String,
    validate: isValidTitle
  },
  category: {
    required: true,
    type: Array
  },
  seller: {
    required: true,
    type: String
  },
  condition: {
    required: true,
    type: String,
    validate: isValidCondition
  },
  provider: {
    required: true,
    type: String
  },
  path: {
    type: String
  },
  link: {
    required: true,
    type: String,
    validate: isUrl
  },
  image: {
    type: String,
    validate: isUrl
  },
  createdAt: {
    type: Number
  },
  updatedAt: {
    type: Number
  },
  timestamp: {
    type: Number
  },
  isForced: {
    type: Boolean,
    default: false
  },

  /** identify:common **/
  brand: String,
  model: String,
  price: {
    required: true,
    type: Number,
    validate: isValidPrice,
    transform: [round]
  },

  year: Number,

  'mast size': Number,

  'sail size': {
    type: Number,
    validate: isValidSailSize
  },

  'board size': {
    type: Number,
    validate: isFinite
  },

  'boom size': String,
  'boom type': String,

  'fin size': {
    type: Number,
    validate: isFinite
  },

  'fin type': String,

  'mast carbon': Number,
  'mast type': String
})

const titleize = asyncify(prettyTitle)
const validate = asyncify(validator)

module.exports = function (schema, cb) {
  const now = Date.now()

  const doc = assign({}, schema, {
    condition: getCondition(schema),
    link: getReferralLink(schema),
    timestamp: now,
    updatedAt: startOfDay(now).getTime()
  })

  const schemaSerialized = serializer(doc)

  const tasks = [
    function validateSchema (next) {
      return validate(schemaSerialized, next)
    },
    function prettyTitle (doc, next) {
      return titleize(doc, (err, title) => next(err, doc, title))
    },
    function assignProps (doc, title, next) {
      const prettyDoc = assign({}, doc, {title})
      return next(null, prettyDoc)
    }
  ]

  return waterfall(tasks, cb)
}
<commit_msg>Group similar items<commit_after>'use strict'

const startOfDay = require('date-fns/start_of_day')
const {waterfall, asyncify} = require('async')
const {assign, isFinite, round} = require('lodash')
const osom = require('osom')

const getReferralLink = require('./get-referral-link')
const getCondition = require('./get-condition')

const prettyTitle = require('./transform/pretty-title')
const isValidCondition = require('./validate/condition')
const isValidSailSize = require('./validate/sail-size')
const isValidTitle = require('./validate/title')
const isValidPrice = require('./validate/price')
const serializer = require('./serializer')
const isUrl = require('../util/is-url')

const validator = osom({
  /* common */
  title: {
    required: true,
    type: String,
    validate: isValidTitle
  },
  category: {
    required: true,
    type: Array
  },
  seller: {
    required: true,
    type: String
  },
  condition: {
    required: true,
    type: String,
    validate: isValidCondition
  },
  provider: {
    required: true,
    type: String
  },
  path: {
    type: String
  },
  link: {
    required: true,
    type: String,
    validate: isUrl
  },
  image: {
    type: String,
    validate: isUrl
  },
  createdAt: {
    type: Number
  },
  updatedAt: {
    type: Number
  },
  timestamp: {
    type: Number
  },
  isForced: {
    type: Boolean,
    default: false
  },

  /** identify:common **/
  brand: String,
  model: String,
  price: {
    required: true,
    type: Number,
    validate: isValidPrice,
    transform: [round]
  },

  year: Number,

  'sail size': {
    type: Number,
    validate: isValidSailSize
  },

  'board size': {
    type: Number,
    validate: isFinite
  },

  'boom size': String,
  'boom type': String,

  'fin size': {
    type: Number,
    validate: isFinite
  },

  'fin type': String,

  'mast carbon': Number,
  'mast type': String,
  'mast size': Number
})

const titleize = asyncify(prettyTitle)
const validate = asyncify(validator)

module.exports = function (schema, cb) {
  const now = Date.now()

  const doc = assign({}, schema, {
    condition: getCondition(schema),
    link: getReferralLink(schema),
    timestamp: now,
    updatedAt: startOfDay(now).getTime()
  })

  const schemaSerialized = serializer(doc)

  const tasks = [
    function validateSchema (next) {
      return validate(schemaSerialized, next)
    },
    function prettyTitle (doc, next) {
      return titleize(doc, (err, title) => next(err, doc, title))
    },
    function assignProps (doc, title, next) {
      const prettyDoc = assign({}, doc, {title})
      return next(null, prettyDoc)
    }
  ]

  return waterfall(tasks, cb)
}
<|endoftext|>


<commit_before>// Generate Weierstrass Data

var count = 1e6,
  precision = 10000000,
  i = 0,
  a = 2, // Weierstrass a
  x, y;

//console.time('weierstrass');
console.log('var weierdata = [');

for (i = 1; i < count; i++) {
  x = -1 + i * 2 / count;
  y = 0;
  for (var k = 1; k < 50; k++) {
    y += Math.sin(Math.PI * Math.pow(k, a) * x) / (Math.PI * Math.pow(k,a));
  }
  x = Math.round(x*precision)/precision;
  y = Math.round(y*precision)/precision;
  console.log('[%d, %d],', x, y);
}

// Unfolded final loop (no trailing comma);
i = count;
x = -1 + i * 2 / 1e2;
y = 0;
for (var k = 1; k < 50; k++) {
  y += Math.sin(Math.PI * Math.pow(k, a) * x) / (Math.PI * Math.pow(k,a));
}
x = Math.round(x*10000)/10000;
y = Math.round(y*10000)/10000;
console.log('[%d, %d]', x, y);

console.log(']');
<commit_msg>Formatting.<commit_after>// Generate Weierstrass Data

var count = 1e6,
  precision = 10000000,
  i = 0,
  a = 2, // Weierstrass a
  x, y;

//console.time('weierstrass');
console.log('var weierdata = [');

for (i = 1; i < count; i++) {
  x = -1 + i * 2 / count;
  y = 0;
  for (var k = 1; k < 50; k++) {
    y +=

      Math.sin(Math.PI * Math.pow(k, a) * x) /
      (Math.PI * Math.pow(k,a));
  }
  x = Math.round(x*precision)/precision;
  y = Math.round(y*precision)/precision;
  console.log('[%d, %d],', x, y);
}

// Unfolded final loop (no trailing comma);
i = count;
x = -1 + i * 2 / 1e2;
y = 0;
for (var k = 1; k < 50; k++) {
  y += Math.sin(Math.PI * Math.pow(k, a) * x) / (Math.PI * Math.pow(k,a));
}
x = Math.round(x*10000)/10000;
y = Math.round(y*10000)/10000;
console.log('[%d, %d]', x, y);

console.log(']');
<|endoftext|>