<commit_before>import Vector2 from '../../../lib/src/math/Vector2.js';

const VECTOR2 = new Vector2();

const DOM_MATRIX_A = new DOMMatrix();
const DOM_MATRIX_B = new DOMMatrix();

export default class ViewportElement extends HTMLElement {
  constructor() {
    super();

    this._slotUID = 0;

    this.preventManipulation = function (event) {
      return false;
    };

    this.attachShadow({ mode: 'open' }).innerHTML = `

      <slot></slot>

    `;

    const content = this.shadowRoot.querySelector('#content');
    this._styleSheet = this.shadowRoot.querySelector('style').sheet;
    this._slots = new Set();
    const slotElementMap = new Map();
    const elementSlotMap = new Map();

    // Behaviour

    const pointerEventMap = new Map();
    const pointerTargetMap = new Map();
    const targetPointersMap = new Map();

    let previousPinchSize = 0;

    let firstClientX = 0;
    let firstClientY = 0;

    const zoom = (scale, x, y) => {
      DOM_MATRIX_B.setMatrixValue('');
      DOM_MATRIX_B.scaleSelf(scale);
      DOM_MATRIX_B.m41 = -x * (scale - 1);
      DOM_MATRIX_B.m42 = -y * (scale - 1);

      for (const slot of this._slots) {
        DOM_MATRIX_A.setMatrixValue(slot.style.transform);
        DOM_MATRIX_A.preMultiplySelf(DOM_MATRIX_B);
        slot.style.transformOrigin = 'top left';
        slot.style.transform = DOM_MATRIX_A.toString();
      }
    };

    const reset = () => {
      previousPinchSize = 0;
      firstClientX = 0;
      firstClientY = 0;
    };

    const onPointerDown = (event) => {
      reset();

      if (event.target !== event.currentTarget && event.target.scrollHeight > event.target.offsetHeight) {
        return;
      }
      if (pointerEventMap.has(event.pointerId)) {
        return;
      }
      if (this.preventManipulation(event)) {
        return;
      }

      if (!pointerEventMap.size) {
        window.addEventListener('pointermove', onPointerMove);
        window.addEventListener('pointerup', onPointerUp);
        window.addEventListener('pointerout', onPointerUp);
      }
      pointerEventMap.set(event.pointerId, event);
      pointerTargetMap.set(event.pointerId, event.currentTarget);
      let targetPointersSet = targetPointersMap.get(event.currentTarget);
      if (!targetPointersSet) {
        targetPointersSet = new Set();
        targetPointersMap.set(event.currentTarget, targetPointersSet);
        event.currentTarget.classList.add('disable-children');
      }
      targetPointersSet.add(event.pointerId);
    };

    const onPointerMove = (event) => {
      if (!pointerEventMap.has(event.pointerId)) {
        return;
      }

      pointerEventMap.set(event.pointerId, event);
      const pointerIds = [...pointerEventMap.keys()];

      let isViewport = false;
      for (const target of pointerTargetMap.values()) {
        if (target === this) {
          isViewport = true;
        }
      }

      if (isViewport) {
        let sumMovementX = 0;
        let sumMovementY = 0;
        for (const pointer of pointerEventMap.values()) {
          sumMovementX += pointer.movementX;
          sumMovementY += pointer.movementY;
        }
        sumMovementX /= pointerEventMap.size;
        sumMovementY /= pointerEventMap.size;

        for (const slot of this._slots) {
          this._offsetElement(slot, sumMovementX / window.devicePixelRatio, sumMovementY / window.devicePixelRatio);
        }
      } else if (!isViewport) {
        const slot = pointerTargetMap.get(event.pointerId);
        const targetPointersSet = targetPointersMap.get(slot);

        let sumMovementX = 0;
        let sumMovementY = 0;
        for (const pointer of targetPointersSet) {
          const pointerEvent = pointerEventMap.get(pointer);
          sumMovementX += pointerEvent.movementX;
          sumMovementY += pointerEvent.movementY;
        }
        sumMovementX /= targetPointersSet.size * targetPointersSet.size;
        sumMovementY /= targetPointersSet.size * targetPointersSet.size;
        sumMovementX /= window.devicePixelRatio;
        sumMovementY /= window.devicePixelRatio;

        this._offsetElement(slot, sumMovementX, sumMovementY);
        if (targetPointersSet.size === 2) {
          if (slot.style.resize === 'none') {
            isViewport = true;
          } else {
            const boundingClientRect = slot.getBoundingClientRect();

            DOM_MATRIX_A.setMatrixValue(slot.style.transform);

            let otherPointerEvent;

            for (const pointer of targetPointersSet) {
              const pointerEvent = pointerEventMap.get(pointer);
              if (pointerEvent !== event) {
                otherPointerEvent = pointerEvent;
              }
            }

            const pinchOffsetLeft = (event.clientX < otherPointerEvent.clientX ? event.movementX : 0) / window.devicePixelRatio;
            const pinchOffsetRight = (event.clientX > otherPointerEvent.clientX ? event.movementX : 0) / window.devicePixelRatio;
            const pinchOffsetTop = (event.clientY < otherPointerEvent.clientY ? event.movementY : 0) / window.devicePixelRatio;
            const pinchOffsetBottom = (event.clientY > otherPointerEvent.clientY ? event.movementY : 0) / window.devicePixelRatio;

            if (slot.style.resize === 'both' || slot.style.resize === 'horizontal') {
              slot.style.width = `${(boundingClientRect.width - pinchOffsetLeft + pinchOffsetRight) * (1 / DOM_MATRIX_A.a)}px`;
              DOM_MATRIX_A.m41 += pinchOffsetLeft - sumMovementX;
            }

            if (slot.style.resize === 'both' || slot.style.resize === 'vertical') {
              slot.style.height = `${(boundingClientRect.height - pinchOffsetTop + pinchOffsetBottom) * (1 / DOM_MATRIX_A.d)}px`;
              DOM_MATRIX_A.m42 += pinchOffsetTop - sumMovementY;
            }

            slot.style.transform = DOM_MATRIX_A.toString();
          }
        }
      }

      if (event.pointerId === pointerIds[0]) {
        firstClientX = event.clientX;
        firstClientY = event.clientY;
      }
      if (event.pointerId === pointerIds[1]) {
        if (firstClientX || firstClientY) {
          const x = (firstClientX + event.clientX) * .5 - this.clientWidth * .5;
          const y = (firstClientY + event.clientY) * .5 - this.clientHeight * .5;
          VECTOR2.x = firstClientX - event.clientX;
          VECTOR2.y = firstClientY - event.clientY;

          const pinchSize = VECTOR2.size;

          if (isViewport && previousPinchSize) {
            zoom(pinchSize / previousPinchSize, x, y);
          }

          previousPinchSize = pinchSize;
        }
      }
    };

    const onPointerUp = (event) => {
      reset();
      event.preventDefault();
      if (event.pointerType === 'mouse' && event.type === 'pointerout' || !pointerEventMap.has(event.pointerId)) {
        return;
      }
      const target = pointerTargetMap.get(event.pointerId);
      const targetPointersSet = targetPointersMap.get(target);
      targetPointersSet.delete(event.pointerId);
      if (!targetPointersSet.size) {
        targetPointersMap.delete(target);
        target.classList.remove('disable-children');
      }
      pointerEventMap.delete(event.pointerId);
      pointerTargetMap.delete(event.pointerId);
      if (!pointerEventMap.size) {
        window.removeEventListener('pointermove', onPointerMove);
        window.removeEventListener('pointerup', onPointerUp);
        window.removeEventListener('pointerout', onPointerUp);
      }
    };

    this.addEventListener('pointerdown', onPointerDown);

    this.addEventListener('wheel', (event) => {
      if (event.target.scrollHeight > event.target.clientHeight) {
        return;
      }
      const scale = 1 + (event.deltaY < 0 ? 1 : -1) * .1;
      const x = event.clientX - this.clientWidth * .5;
      const y = event.clientY - this.clientHeight * .5;
      zoom(scale, x, y);
    });

    // Mutation Observer
    const mutationCallback = (mutationsList) => {
      for (const mutation of mutationsList) {
        for (const node of mutation.addedNodes) {
          if (!(node instanceof HTMLElement)) {
            continue;
          }
          const boundingClientRect = node.getBoundingClientRect();
          const slot = document.createElement('slot');
          slot.name = `viewport-slot-${this._slotUID}`;
          slot.classList.add('viewport-slot');
          node.slot = slot.name;
          slot.style.transform = `translate(${boundingClientRect.x}px, ${boundingClientRect.y}px)`;
          const style = getComputedStyle(node);
          slot.style.resize = style.resize;
          if (style.resize !== 'none') {
            let ruleString = `[name="${slot.name}"]::slotted(*) {`;
            if (/both|horizontal/.test(style.resize)) {
              slot.style.width = `${boundingClientRect.width}px`;
              ruleString += 'width: 100% !important;';
            }
            if (/both|vertical/.test(style.resize)) {
              slot.style.height = `${boundingClientRect.height}px`;
              ruleString += 'height: 100% !important;';
            }
            ruleString += '}';
            this._styleSheet.insertRule(ruleString, this._styleSheet.cssRules.length);
          }
          content.appendChild(slot);
          this._slotUID++;
          this._slots.add(slot);
          slotElementMap.set(slot, node);
          elementSlotMap.set(node, slot);
          slot.addEventListener('pointerdown', onPointerDown);
        }
        for (const node of mutation.removedNodes) {
          if (!(node instanceof HTMLElement)) {
            continue;
          }
          const slot = elementSlotMap.get(node);
          slot.removeEventListener('pointerdown', onPointerDown);
          slotElementMap.delete(slot);
          this._slots.delete(slot);
          slot.remove();
          for (const [index, rule] of [...this._styleSheet.cssRules].entries()) {
            if (rule.selectorText === `[name="${slot.name}"]::slotted(*)`) {
              this._styleSheet.deleteRule(index);
            }
          }
        }
      }
    };
    mutationCallback([{
      addedNodes: this.children,
      removedNodes: [],
    }]);
    const observer = new MutationObserver(mutationCallback);
    observer.observe(this, { childList: true });
  }

  centerView() {
    const domRect = new DOMRect(Infinity, Infinity, 0, 0);
    for (const slot of this._slots) {
      const boundingClientRect = slot.getBoundingClientRect();
      domRect.x = Math.min(domRect.x, boundingClientRect.x);
      domRect.y = Math.min(domRect.y, boundingClientRect.y);
      domRect.width = Math.max(domRect.width, boundingClientRect.x + boundingClientRect.width - domRect.x);
      domRect.height = Math.max(domRect.height, boundingClientRect.y + boundingClientRect.height - domRect.y);
    }

    const offsetX = -domRect.x - domRect.width * .5 + this.clientWidth * .5;
    const offsetY = -domRect.y - domRect.height * .5 + this.clientHeight * .5;
    for (const slot of this._slots) {
      this._offsetElement(slot, offsetX, offsetY);
    }
  }

  _offsetElement(element, offsetX, offsetY) {
    DOM_MATRIX_A.setMatrixValue(element.style.transform);
    DOM_MATRIX_A.m41 += offsetX;
    DOM_MATRIX_A.m42 += offsetY;
    element.style.transform = DOM_MATRIX_A.toString();
  }
}
<commit_msg>add select<commit_after>import Vector2 from '../../../lib/src/math/Vector2.js';

const VECTOR2 = new Vector2();

const DOM_MATRIX_A = new DOMMatrix();
const DOM_MATRIX_B = new DOMMatrix();

export default class ViewportElement extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({ mode: 'open' }).innerHTML = `

      <slot></slot>

    `;

    const content = this.shadowRoot.querySelector('#content');
    this._styleSheet = this.shadowRoot.querySelector('style').sheet;
    this._slotUID = 0;
    this._slots = new Set();
    const slotElementMap = new Map();
    const elementSlotMap = new Map();

    this.preventManipulation = function (event) {
      return false;
    };

    this._selectedElements = new class extends Set {
      add(value) {
        // value.setAttribute('selected', '');
        return super.add(value);
      }
      delete(value) {
        // value.removeAttribute('selected');
        return super.delete(value);
      }
      clear() {
        for (const value of this) {
          this.delete(value);
        }
      }
    };

    // Drag/Zoom

    const pointerEventMap = new Map();
    const pointerTargetMap = new Map();
    const targetPointersMap = new Map();

    let dragged = false;

    let previousPinchSize = 0;

    let firstClientX = 0;
    let firstClientY = 0;

    const zoom = (scale, x, y) => {
      DOM_MATRIX_B.setMatrixValue('');
      DOM_MATRIX_B.scaleSelf(scale);
      DOM_MATRIX_B.m41 = -x * (scale - 1);
      DOM_MATRIX_B.m42 = -y * (scale - 1);

      for (const slot of this._slots) {
        DOM_MATRIX_A.setMatrixValue(slot.style.transform);
        DOM_MATRIX_A.preMultiplySelf(DOM_MATRIX_B);
        slot.style.transformOrigin = 'top left';
        slot.style.transform = DOM_MATRIX_A.toString();
      }
    };

    const reset = () => {
      previousPinchSize = 0;
      firstClientX = 0;
      firstClientY = 0;
    };

    const onPointerDown = (event) => {
      reset();

      if (event.target !== event.currentTarget && event.target.scrollHeight > event.target.offsetHeight) {
        return;
      }
      if (pointerEventMap.has(event.pointerId)) {
        return;
      }
      if (this.preventManipulation(event)) {
        return;
      }

      if (!pointerEventMap.size) {
        window.addEventListener('pointermove', onPointerMove);
        window.addEventListener('pointerup', onPointerUp);
        window.addEventListener('pointerout', onPointerUp);
      }
      pointerEventMap.set(event.pointerId, event);
      pointerTargetMap.set(event.pointerId, event.currentTarget);
      let targetPointersSet = targetPointersMap.get(event.currentTarget);
      if (!targetPointersSet) {
        targetPointersSet = new Set();
        targetPointersMap.set(event.currentTarget, targetPointersSet);
        if (!event.shiftKey && this._selectedElements.size <= 1 || event.currentTarget === this) {
          for (const element of this._selectedElements) {
            const slot = elementSlotMap.get(element);
            slot.removeAttribute('selected');
          }
          this._selectedElements.clear();
        }
        if (event.currentTarget !== this) {
          event.currentTarget.setAttribute('disabled', '');
          event.currentTarget.setAttribute('selected', '');
          this._selectedElements.add(slotElementMap.get(event.currentTarget));
        }
      }
      targetPointersSet.add(event.pointerId);
    };

    const onPointerMove = (event) => {
      if (!pointerEventMap.has(event.pointerId)) {
        return;
      }

      dragged = true;

      pointerEventMap.set(event.pointerId, event);
      const pointerIds = [...pointerEventMap.keys()];

      let isViewport = false;
      for (const target of pointerTargetMap.values()) {
        if (target === this) {
          isViewport = true;
        }
      }

      if (isViewport) {
        let sumMovementX = 0;
        let sumMovementY = 0;
        for (const pointer of pointerEventMap.values()) {
          sumMovementX += pointer.movementX;
          sumMovementY += pointer.movementY;
        }
        sumMovementX /= pointerEventMap.size;
        sumMovementY /= pointerEventMap.size;

        for (const slot of this._slots) {
          this._offsetElement(slot, sumMovementX / window.devicePixelRatio, sumMovementY / window.devicePixelRatio);
        }
      } else if (!isViewport) {
        const slot = pointerTargetMap.get(event.pointerId);
        const targetPointersSet = targetPointersMap.get(slot);

        let sumMovementX = 0;
        let sumMovementY = 0;
        for (const pointer of targetPointersSet) {
          const pointerEvent = pointerEventMap.get(pointer);
          sumMovementX += pointerEvent.movementX;
          sumMovementY += pointerEvent.movementY;
        }
        sumMovementX /= targetPointersSet.size * targetPointersSet.size;
        sumMovementY /= targetPointersSet.size * targetPointersSet.size;
        sumMovementX /= window.devicePixelRatio;
        sumMovementY /= window.devicePixelRatio;

        for (const element of this._selectedElements) {
          const slot = elementSlotMap.get(element);
          this._offsetElement(slot, sumMovementX, sumMovementY);
        }
        if (targetPointersSet.size === 2) {
          if (slot.style.resize === 'none') {
            isViewport = true;
          } else {
            const boundingClientRect = slot.getBoundingClientRect();

            DOM_MATRIX_A.setMatrixValue(slot.style.transform);

            let otherPointerEvent;

            for (const pointer of targetPointersSet) {
              const pointerEvent = pointerEventMap.get(pointer);
              if (pointerEvent !== event) {
                otherPointerEvent = pointerEvent;
              }
            }

            const pinchOffsetLeft = (event.clientX < otherPointerEvent.clientX ? event.movementX : 0) / window.devicePixelRatio;
            const pinchOffsetRight = (event.clientX > otherPointerEvent.clientX ? event.movementX : 0) / window.devicePixelRatio;
            const pinchOffsetTop = (event.clientY < otherPointerEvent.clientY ? event.movementY : 0) / window.devicePixelRatio;
            const pinchOffsetBottom = (event.clientY > otherPointerEvent.clientY ? event.movementY : 0) / window.devicePixelRatio;

            if (slot.style.resize === 'both' || slot.style.resize === 'horizontal') {
              slot.style.width = `${(boundingClientRect.width - pinchOffsetLeft + pinchOffsetRight) * (1 / DOM_MATRIX_A.a)}px`;
              DOM_MATRIX_A.m41 += pinchOffsetLeft - sumMovementX;
            }

            if (slot.style.resize === 'both' || slot.style.resize === 'vertical') {
              slot.style.height = `${(boundingClientRect.height - pinchOffsetTop + pinchOffsetBottom) * (1 / DOM_MATRIX_A.d)}px`;
              DOM_MATRIX_A.m42 += pinchOffsetTop - sumMovementY;
            }

            slot.style.transform = DOM_MATRIX_A.toString();
          }
        }
      }

      if (event.pointerId === pointerIds[0]) {
        firstClientX = event.clientX;
        firstClientY = event.clientY;
      }
      if (event.pointerId === pointerIds[1]) {
        if (firstClientX || firstClientY) {
          const x = (firstClientX + event.clientX) * .5 - this.clientWidth * .5;
          const y = (firstClientY + event.clientY) * .5 - this.clientHeight * .5;
          VECTOR2.x = firstClientX - event.clientX;
          VECTOR2.y = firstClientY - event.clientY;

          const pinchSize = VECTOR2.size;

          if (isViewport && previousPinchSize) {
            zoom(pinchSize / previousPinchSize, x, y);
          }

          previousPinchSize = pinchSize;
        }
      }
    };

    const onPointerUp = (event) => {
      reset();
      event.preventDefault();
      if (event.pointerType === 'mouse' && event.type === 'pointerout' || !pointerEventMap.has(event.pointerId)) {
        return;
      }
      const target = pointerTargetMap.get(event.pointerId);
      const targetPointersSet = targetPointersMap.get(target);
      targetPointersSet.delete(event.pointerId);
      if (!targetPointersSet.size) {
        targetPointersMap.delete(target);
        target.removeAttribute('disabled');
      }
      pointerEventMap.delete(event.pointerId);
      pointerTargetMap.delete(event.pointerId);
      if (!pointerEventMap.size) {
        window.removeEventListener('pointermove', onPointerMove);
        window.removeEventListener('pointerup', onPointerUp);
        window.removeEventListener('pointerout', onPointerUp);
        if (!dragged && !event.shiftKey && this._selectedElements.size > 1) {
          for (const element of this._selectedElements) {
            const slot = elementSlotMap.get(element);
            if (slot !== target) {
              slot.removeAttribute('selected');
              this._selectedElements.delete(element);
            }
          }
        }
        dragged = false;
      }
    };

    this.addEventListener('pointerdown', onPointerDown);

    this.addEventListener('wheel', (event) => {
      if (event.target.scrollHeight > event.target.clientHeight) {
        return;
      }
      const scale = 1 + (event.deltaY < 0 ? 1 : -1) * .1;
      const x = event.clientX - this.clientWidth * .5;
      const y = event.clientY - this.clientHeight * .5;
      zoom(scale, x, y);
    });

    // Mutation Observer
    const mutationCallback = (mutationsList) => {
      for (const mutation of mutationsList) {
        for (const node of mutation.addedNodes) {
          if (!(node instanceof HTMLElement)) {
            continue;
          }
          const boundingClientRect = node.getBoundingClientRect();
          const slot = document.createElement('slot');
          slot.name = `viewport-slot-${this._slotUID}`;
          node.slot = slot.name;
          slot.style.transform = `translate(${boundingClientRect.x}px, ${boundingClientRect.y}px)`;
          const style = getComputedStyle(node);
          slot.style.resize = style.resize;
          if (style.resize !== 'none') {
            let ruleString = `[name="${slot.name}"]::slotted(*) {`;
            if (/both|horizontal/.test(style.resize)) {
              slot.style.width = `${boundingClientRect.width}px`;
              ruleString += 'width: 100% !important;';
            }
            if (/both|vertical/.test(style.resize)) {
              slot.style.height = `${boundingClientRect.height}px`;
              ruleString += 'height: 100% !important;';
            }
            ruleString += '}';
            this._styleSheet.insertRule(ruleString, this._styleSheet.cssRules.length);
          }
          content.appendChild(slot);
          this._slotUID++;
          this._slots.add(slot);
          slotElementMap.set(slot, node);
          elementSlotMap.set(node, slot);
          slot.addEventListener('pointerdown', onPointerDown);
        }
        for (const node of mutation.removedNodes) {
          if (!(node instanceof HTMLElement)) {
            continue;
          }
          const slot = elementSlotMap.get(node);
          slot.removeEventListener('pointerdown', onPointerDown);
          slotElementMap.delete(slot);
          this._slots.delete(slot);
          slot.remove();
          for (const [index, rule] of [...this._styleSheet.cssRules].entries()) {
            if (rule.selectorText === `[name="${slot.name}"]::slotted(*)`) {
              this._styleSheet.deleteRule(index);
            }
          }
        }
      }
    };
    mutationCallback([{
      addedNodes: this.children,
      removedNodes: [],
    }]);
    const observer = new MutationObserver(mutationCallback);
    observer.observe(this, { childList: true });
  }

  get selectedElements() {
    return this._selectedElements;
  }

  centerView() {
    const domRect = new DOMRect(Infinity, Infinity, 0, 0);
    for (const slot of this._slots) {
      const boundingClientRect = slot.getBoundingClientRect();
      domRect.x = Math.min(domRect.x, boundingClientRect.x);
      domRect.y = Math.min(domRect.y, boundingClientRect.y);
      domRect.width = Math.max(domRect.width, boundingClientRect.x + boundingClientRect.width - domRect.x);
      domRect.height = Math.max(domRect.height, boundingClientRect.y + boundingClientRect.height - domRect.y);
    }

    const offsetX = -domRect.x - domRect.width * .5 + this.clientWidth * .5;
    const offsetY = -domRect.y - domRect.height * .5 + this.clientHeight * .5;
    for (const slot of this._slots) {
      this._offsetElement(slot, offsetX, offsetY);
    }
  }

  _offsetElement(element, offsetX, offsetY) {
    DOM_MATRIX_A.setMatrixValue(element.style.transform);
    DOM_MATRIX_A.m41 += offsetX;
    DOM_MATRIX_A.m42 += offsetY;
    element.style.transform = DOM_MATRIX_A.toString();
  }
}
<|endoftext|>


<commit_before>/* @flow */
// Fe was heavily inspired by glam, both the code as well as the name
// https://github.com/threepointone/glam/blob/master/packages/glam/src/index.js#L83
export default function feFactory(
  createElement: Function,
  FelaComponent: Function
) {
  return function fe(type: any, props: Object = {}, ...children: any) {
    if (props) {
      const { css, className, ...otherProps } = nonNullProps

      if (css) {
        return createElement(
          FelaComponent,
          {
            style: css,
          },
          renderProps =>
            createElement(
              type,
              {
                ...otherProps,
                className: className
                  ? className + ' ' + renderProps.className
                  : renderProps.className,
              },
              ...children
            )
        )
      }
    }

    return createElement(type, props, ...children)
  }
}
<commit_msg>fix code<commit_after>/* @flow */
// Fe was heavily inspired by glam, both the code as well as the name
// https://github.com/threepointone/glam/blob/master/packages/glam/src/index.js#L83
export default function feFactory(
  createElement: Function,
  FelaComponent: Function
) {
  return function fe(type: any, props: Object = {}, ...children: any) {
    if (props) {
      const { css, className, ...otherProps } = props

      if (css) {
        return createElement(
          FelaComponent,
          {
            style: css,
          },
          renderProps =>
            createElement(
              type,
              {
                ...otherProps,
                className: className
                  ? className + ' ' + renderProps.className
                  : renderProps.className,
              },
              ...children
            )
        )
      }
    }

    return createElement(type, props, ...children)
  }
}
<|endoftext|>


<commit_before>/* eslint-disable quote-props */

export default {
    'alert': require('./alert').default,
    'badge': require('./badge').default,
    'breadcrumb': require('./breadcrumb').default,
    'button': require('./button').default,
    'button-group': require('./button-group').default,
    'button-toolbar': require('./button-toolbar').default,
    'card': require('./card').default,
    // 'carousel': require('./carousel').default,
    'collapse': require('./collapse').default,
    'dropdown': require('./dropdown').default,
    'form': require('./form').default,
    'form-checkbox': require('./form-checkbox').default,
    'form-fieldset': require('./form-fieldset').default,
    'form-file': require('./form-file').default,
    'form-input': require('./form-input').default,
    'form-radio': require('./form-radio').default,
    'form-select': require('./form-select').default,
    'input-group': require('./input-group').default,
    'jumbotron': require('./jumbotron').default,
    'list-group': require('./list-group').default,
    'modal': require('./modal').default,
    'media': require('./media').default,
    'nav': require('./nav').default,
    'navbar': require('./navbar').default,
    'pagination': require('./pagination').default,
    'popover': require('./popover').default,
    'progress': require('./progress').default,
    'table': require('./table').default,
    'tabs': require('./tabs').default,
    'tooltip': require('./tooltip').default
};
<commit_msg>docs(carousel): Re-enable carousel docs<commit_after>/* eslint-disable quote-props */

export default {
    'alert': require('./alert').default,
    'badge': require('./badge').default,
    'breadcrumb': require('./breadcrumb').default,
    'button': require('./button').default,
    'button-group': require('./button-group').default,
    'button-toolbar': require('./button-toolbar').default,
    'card': require('./card').default,
    'carousel': require('./carousel').default,
    'collapse': require('./collapse').default,
    'dropdown': require('./dropdown').default,
    'form': require('./form').default,
    'form-checkbox': require('./form-checkbox').default,
    'form-fieldset': require('./form-fieldset').default,
    'form-file': require('./form-file').default,
    'form-input': require('./form-input').default,
    'form-radio': require('./form-radio').default,
    'form-select': require('./form-select').default,
    'input-group': require('./input-group').default,
    'jumbotron': require('./jumbotron').default,
    'list-group': require('./list-group').default,
    'modal': require('./modal').default,
    'media': require('./media').default,
    'nav': require('./nav').default,
    'navbar': require('./navbar').default,
    'pagination': require('./pagination').default,
    'popover': require('./popover').default,
    'progress': require('./progress').default,
    'table': require('./table').default,
    'tabs': require('./tabs').default,
    'tooltip': require('./tooltip').default
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

'use strict';

var _ = require('lodash');
var constants = require('./constants');

/**
 * Wrap a function to pass null-like values through without calling it. If no
 * function is given, just uses the identity.
 * @private
 * @param {?function} func The function to wrap
 * @return {function} The wrapped function
 */
exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
  if (!func) {
    return x => x;
  }
  return function(arg) {
    if (arg === null || arg === undefined) {
      return null;
    }
    return func(arg);
  };
};

/**
 * The logger object for the gRPC module. Defaults to console.
 * @private
 */
exports.logger = console;

/**
 * The current logging verbosity. 0 corresponds to logging everything
 * @private
 */
exports.logVerbosity = 0;

/**
 * Log a message if the severity is at least as high as the current verbosity
 * @private
 * @param {Number} severity A value of the grpc.logVerbosity map
 * @param {String} message The message to log
 */
exports.log = function log(severity, message) {
  if (severity >= exports.logVerbosity) {
    exports.logger.error(message);
  }
};

/**
 * Default options for loading proto files into gRPC
 * @alias grpc~defaultLoadOptions
 */
exports.defaultGrpcOptions = {
  convertFieldsToCamelCase: false,
  binaryAsBase64: false,
  longsAsStrings: true,
  enumsAsStrings: true,
  deprecatedArgumentOrder: false
};

/**
 * Create an Error object from a status object
 * @param {grpc~StatusObject} status The status object
 * @return {Error} The resulting Error
 */
exports.createStatusError = function(status) {
  let statusName = _.invert(constants.status)[status.code];
  let message = `${status.code} ${statusName}: ${status.details}`;
  let error = new Error(message);
  error.code = status.code;
  error.metadata = status.metadata;
  error.details = status.details;
  return error;
};

/**
 * Get a method's type from its definition
 * @param {grpc~MethodDefinition} method_definition
 * @return {number}
 */
exports.getMethodType = function(method_definition) {
  if (method_definition.requestStream) {
    if (method_definition.responseStream) {
      return constants.methodTypes.BIDI_STREAMING;
    } else {
      return constants.methodTypes.CLIENT_STREAMING;
    }
  } else {
    if (method_definition.responseStream) {
      return constants.methodTypes.SERVER_STREAMING;
    } else {
      return constants.methodTypes.UNARY;
    }
  }
};

/**
 * Iterate over a collection of items, and run the given handler.
 * Return the results as a flattened array of values.
 *
 * @private
 *
 * @param {Array} collection Array of items to process
 * @param {Function} handler The function to call on each element in the array
 * @return {Array} A flattened array of results.
 */
exports.flatMap = function(collection, handler) {
  const mapped = collection.map(handler);
  return mapped.reduce((acc, curr) => acc.concat(curr), []);
}

/**
 * Given an array of property names and an array of values,
 * combine the two into an object map.
 * Equivalent to _.zipObject.
 *
 * @private
 *
 * @param props {Array<String>} Array of property names
 * @param values {Array} Array of property values
 * @return {Object} An object with the combined values
 */
exports.zipObject = function(props, values) {
  return props.reduce((acc, curr, idx) => {
    return Object.assign(acc, { [curr]: values[idx] });
  }, {});
}

// JSDoc definitions that are used in multiple other modules

/**
 * Represents the status of a completed request. If `code` is
 * {@link grpc.status}.OK, then the request has completed successfully.
 * Otherwise, the request has failed, `details` will contain a description of
 * the error. Either way, `metadata` contains the trailing response metadata
 * sent by the server when it finishes processing the call.
 * @typedef {object} grpc~StatusObject
 * @property {number} code The error code, a key of {@link grpc.status}
 * @property {string} details Human-readable description of the status
 * @property {grpc.Metadata} metadata Trailing metadata sent with the status,
 *     if applicable
 */

/**
 * Describes how a request has failed. The member `message` will be the same as
 * `details` in {@link grpc~StatusObject}, and `code` and `metadata` are the
 * same as in that object.
 * @typedef {Error} grpc~ServiceError
 * @property {number} code The error code, a key of {@link grpc.status} that is
 *     not `grpc.status.OK`
 * @property {grpc.Metadata} metadata Trailing metadata sent with the status,
 *     if applicable
 */

/**
 * The EventEmitter class in the event standard module
 * @external EventEmitter
 * @see https://nodejs.org/api/events.html#events_class_eventemitter
 */

/**
 * The Readable class in the stream standard module
 * @external Readable
 * @see https://nodejs.org/api/stream.html#stream_readable_streams
 */

/**
 * The Writable class in the stream standard module
 * @external Writable
 * @see https://nodejs.org/api/stream.html#stream_writable_streams
 */

/**
 * The Duplex class in the stream standard module
 * @external Duplex
 * @see https://nodejs.org/api/stream.html#stream_class_stream_duplex
 */

/**
 * A serialization function
 * @callback grpc~serialize
 * @param {*} value The value to serialize
 * @return {Buffer} The value serialized as a byte sequence
 */

/**
 * A deserialization function
 * @callback grpc~deserialize
 * @param {Buffer} data The byte sequence to deserialize
 * @return {*} The data deserialized as a value
 */

/**
 * The deadline of an operation. If it is a date, the deadline is reached at
 * the date and time specified. If it is a finite number, it is treated as
 * a number of milliseconds since the Unix Epoch. If it is Infinity, the
 * deadline will never be reached. If it is -Infinity, the deadline has already
 * passed.
 * @typedef {(number|Date)} grpc~Deadline
 */

/**
 * An object that completely defines a service method signature.
 * @typedef {Object} grpc~MethodDefinition
 * @property {string} path The method's URL path
 * @property {boolean} requestStream Indicates whether the method accepts
 *     a stream of requests
 * @property {boolean} responseStream Indicates whether the method returns
 *     a stream of responses
 * @property {grpc~serialize} requestSerialize Serialization
 *     function for request values
 * @property {grpc~serialize} responseSerialize Serialization
 *     function for response values
 * @property {grpc~deserialize} requestDeserialize Deserialization
 *     function for request data
 * @property {grpc~deserialize} responseDeserialize Deserialization
 *     function for repsonse data
 */

/**
 * @function MetadataListener
 * @param {grpc.Metadata} metadata The response metadata.
 * @param {function} next Passes metadata to the next interceptor.
 */

/**
 * @function MessageListener
 * @param {jspb.Message} message The response message.
 * @param {function} next Passes a message to the next interceptor.
 */

/**
 * @function StatusListener
 * @param {grpc~StatusObject} status The response status.
 * @param {function} next Passes a status to the next interceptor.
 */

/**
 * A set of interceptor functions triggered by responses
 * @typedef {object} grpc~Listener
 * @property {MetadataListener=} onReceiveMetadata A function triggered by
 *     response metadata.
 * @property {MessageListener=} onReceiveMessage A function triggered by a
 *     response message.
 * @property {StatusListener=} onReceiveStatus A function triggered by a
 *     response status.
 */

/**
 * @function MetadataRequester
 * @param {grpc.Metadata} metadata The request metadata.
 * @param {grpc~Listener} listener A listener wired to the previous layers
 *     in the interceptor stack.
 * @param {function} next Passes metadata and a listener to the next
 *      interceptor.
 */

/**
 * @function MessageRequester
 * @param {jspb.Message} message The request message.
 * @param {function} next Passes a message to the next interceptor.
 */

/**
 * @function CloseRequester
 * @param {function} next Calls the next interceptor.
 */

/**
 * @function CancelRequester
 * @param {function} next Calls the next interceptor.
 */

/**
 * @function GetPeerRequester
 * @param {function} next Calls the next interceptor.
 * @return {string}
 */

/**
 * @typedef {object} grpc~Requester
 * @param {MetadataRequester=} start A function triggered when the call begins.
 * @param {MessageRequester=} sendMessage A function triggered by the request
 *     message.
 * @param {CloseRequester=} halfClose A function triggered when the client
 *     closes the call.
 * @param {CancelRequester=} cancel A function triggered when the call is
 *     cancelled.
 * @param {GetPeerRequester=} getPeer A function triggered when the endpoint is
 *     requested.
 */

/**
 * An object that completely defines a service.
 * @typedef {Object.<string, grpc~MethodDefinition>} grpc~ServiceDefinition
 */

/**
 * An object that defines a package hierarchy with multiple services
 * @typedef {Object.<string, grpc~ServiceDefinition>} grpc~PackageDefinition
 */

/**
 * A function for dynamically assigning an interceptor to a call.
 * @function InterceptorProvider
 * @param {grpc~MethodDefinition} method_definition The method to provide
 *     an interceptor for.
 * @return {Interceptor|null} The interceptor to provide or nothing
 */

/**
 * A function which can modify call options and produce methods to intercept
 * RPC operations.
 * @function Interceptor
 * @param {object} options The grpc call options
 * @param {NextCall} nextCall
 * @return {InterceptingCall}
 */

/**
 * A function which produces the next InterceptingCall.
 * @function NextCall
 * @param {object} options The grpc call options
 * @return {InterceptingCall|null}
 */
<commit_msg>refactor: drop usage of _.invert<commit_after>/**
 * @license
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

'use strict';

var _ = require('lodash');
var constants = require('./constants');

/**
 * Wrap a function to pass null-like values through without calling it. If no
 * function is given, just uses the identity.
 * @private
 * @param {?function} func The function to wrap
 * @return {function} The wrapped function
 */
exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
  if (!func) {
    return x => x;
  }
  return function(arg) {
    if (arg === null || arg === undefined) {
      return null;
    }
    return func(arg);
  };
};

/**
 * The logger object for the gRPC module. Defaults to console.
 * @private
 */
exports.logger = console;

/**
 * The current logging verbosity. 0 corresponds to logging everything
 * @private
 */
exports.logVerbosity = 0;

/**
 * Log a message if the severity is at least as high as the current verbosity
 * @private
 * @param {Number} severity A value of the grpc.logVerbosity map
 * @param {String} message The message to log
 */
exports.log = function log(severity, message) {
  if (severity >= exports.logVerbosity) {
    exports.logger.error(message);
  }
};

/**
 * Default options for loading proto files into gRPC
 * @alias grpc~defaultLoadOptions
 */
exports.defaultGrpcOptions = {
  convertFieldsToCamelCase: false,
  binaryAsBase64: false,
  longsAsStrings: true,
  enumsAsStrings: true,
  deprecatedArgumentOrder: false
};

/**
 * Create an Error object from a status object
 * @param {grpc~StatusObject} status The status object
 * @return {Error} The resulting Error
 */
exports.createStatusError = function(status) {
  let inverted = Object.keys(constants.status)
    .reduce((acc, key) => {
      acc[constants.status[key]] = key;
      return acc;
    }, {});
  let statusName = inverted[status.code];
  let message = `${status.code} ${statusName}: ${status.details}`;
  let error = new Error(message);
  error.code = status.code;
  error.metadata = status.metadata;
  error.details = status.details;
  return error;
};

/**
 * Get a method's type from its definition
 * @param {grpc~MethodDefinition} method_definition
 * @return {number}
 */
exports.getMethodType = function(method_definition) {
  if (method_definition.requestStream) {
    if (method_definition.responseStream) {
      return constants.methodTypes.BIDI_STREAMING;
    } else {
      return constants.methodTypes.CLIENT_STREAMING;
    }
  } else {
    if (method_definition.responseStream) {
      return constants.methodTypes.SERVER_STREAMING;
    } else {
      return constants.methodTypes.UNARY;
    }
  }
};

/**
 * Iterate over a collection of items, and run the given handler.
 * Return the results as a flattened array of values.
 *
 * @private
 *
 * @param {Array} collection Array of items to process
 * @param {Function} handler The function to call on each element in the array
 * @return {Array} A flattened array of results.
 */
exports.flatMap = function(collection, handler) {
  const mapped = collection.map(handler);
  return mapped.reduce((acc, curr) => acc.concat(curr), []);
}

/**
 * Given an array of property names and an array of values,
 * combine the two into an object map.
 * Equivalent to _.zipObject.
 *
 * @private
 *
 * @param props {Array<String>} Array of property names
 * @param values {Array} Array of property values
 * @return {Object} An object with the combined values
 */
exports.zipObject = function(props, values) {
  return props.reduce((acc, curr, idx) => {
    return Object.assign(acc, { [curr]: values[idx] });
  }, {});
}

// JSDoc definitions that are used in multiple other modules

/**
 * Represents the status of a completed request. If `code` is
 * {@link grpc.status}.OK, then the request has completed successfully.
 * Otherwise, the request has failed, `details` will contain a description of
 * the error. Either way, `metadata` contains the trailing response metadata
 * sent by the server when it finishes processing the call.
 * @typedef {object} grpc~StatusObject
 * @property {number} code The error code, a key of {@link grpc.status}
 * @property {string} details Human-readable description of the status
 * @property {grpc.Metadata} metadata Trailing metadata sent with the status,
 *     if applicable
 */

/**
 * Describes how a request has failed. The member `message` will be the same as
 * `details` in {@link grpc~StatusObject}, and `code` and `metadata` are the
 * same as in that object.
 * @typedef {Error} grpc~ServiceError
 * @property {number} code The error code, a key of {@link grpc.status} that is
 *     not `grpc.status.OK`
 * @property {grpc.Metadata} metadata Trailing metadata sent with the status,
 *     if applicable
 */

/**
 * The EventEmitter class in the event standard module
 * @external EventEmitter
 * @see https://nodejs.org/api/events.html#events_class_eventemitter
 */

/**
 * The Readable class in the stream standard module
 * @external Readable
 * @see https://nodejs.org/api/stream.html#stream_readable_streams
 */

/**
 * The Writable class in the stream standard module
 * @external Writable
 * @see https://nodejs.org/api/stream.html#stream_writable_streams
 */

/**
 * The Duplex class in the stream standard module
 * @external Duplex
 * @see https://nodejs.org/api/stream.html#stream_class_stream_duplex
 */

/**
 * A serialization function
 * @callback grpc~serialize
 * @param {*} value The value to serialize
 * @return {Buffer} The value serialized as a byte sequence
 */

/**
 * A deserialization function
 * @callback grpc~deserialize
 * @param {Buffer} data The byte sequence to deserialize
 * @return {*} The data deserialized as a value
 */

/**
 * The deadline of an operation. If it is a date, the deadline is reached at
 * the date and time specified. If it is a finite number, it is treated as
 * a number of milliseconds since the Unix Epoch. If it is Infinity, the
 * deadline will never be reached. If it is -Infinity, the deadline has already
 * passed.
 * @typedef {(number|Date)} grpc~Deadline
 */

/**
 * An object that completely defines a service method signature.
 * @typedef {Object} grpc~MethodDefinition
 * @property {string} path The method's URL path
 * @property {boolean} requestStream Indicates whether the method accepts
 *     a stream of requests
 * @property {boolean} responseStream Indicates whether the method returns
 *     a stream of responses
 * @property {grpc~serialize} requestSerialize Serialization
 *     function for request values
 * @property {grpc~serialize} responseSerialize Serialization
 *     function for response values
 * @property {grpc~deserialize} requestDeserialize Deserialization
 *     function for request data
 * @property {grpc~deserialize} responseDeserialize Deserialization
 *     function for repsonse data
 */

/**
 * @function MetadataListener
 * @param {grpc.Metadata} metadata The response metadata.
 * @param {function} next Passes metadata to the next interceptor.
 */

/**
 * @function MessageListener
 * @param {jspb.Message} message The response message.
 * @param {function} next Passes a message to the next interceptor.
 */

/**
 * @function StatusListener
 * @param {grpc~StatusObject} status The response status.
 * @param {function} next Passes a status to the next interceptor.
 */

/**
 * A set of interceptor functions triggered by responses
 * @typedef {object} grpc~Listener
 * @property {MetadataListener=} onReceiveMetadata A function triggered by
 *     response metadata.
 * @property {MessageListener=} onReceiveMessage A function triggered by a
 *     response message.
 * @property {StatusListener=} onReceiveStatus A function triggered by a
 *     response status.
 */

/**
 * @function MetadataRequester
 * @param {grpc.Metadata} metadata The request metadata.
 * @param {grpc~Listener} listener A listener wired to the previous layers
 *     in the interceptor stack.
 * @param {function} next Passes metadata and a listener to the next
 *      interceptor.
 */

/**
 * @function MessageRequester
 * @param {jspb.Message} message The request message.
 * @param {function} next Passes a message to the next interceptor.
 */

/**
 * @function CloseRequester
 * @param {function} next Calls the next interceptor.
 */

/**
 * @function CancelRequester
 * @param {function} next Calls the next interceptor.
 */

/**
 * @function GetPeerRequester
 * @param {function} next Calls the next interceptor.
 * @return {string}
 */

/**
 * @typedef {object} grpc~Requester
 * @param {MetadataRequester=} start A function triggered when the call begins.
 * @param {MessageRequester=} sendMessage A function triggered by the request
 *     message.
 * @param {CloseRequester=} halfClose A function triggered when the client
 *     closes the call.
 * @param {CancelRequester=} cancel A function triggered when the call is
 *     cancelled.
 * @param {GetPeerRequester=} getPeer A function triggered when the endpoint is
 *     requested.
 */

/**
 * An object that completely defines a service.
 * @typedef {Object.<string, grpc~MethodDefinition>} grpc~ServiceDefinition
 */

/**
 * An object that defines a package hierarchy with multiple services
 * @typedef {Object.<string, grpc~ServiceDefinition>} grpc~PackageDefinition
 */

/**
 * A function for dynamically assigning an interceptor to a call.
 * @function InterceptorProvider
 * @param {grpc~MethodDefinition} method_definition The method to provide
 *     an interceptor for.
 * @return {Interceptor|null} The interceptor to provide or nothing
 */

/**
 * A function which can modify call options and produce methods to intercept
 * RPC operations.
 * @function Interceptor
 * @param {object} options The grpc call options
 * @param {NextCall} nextCall
 * @return {InterceptingCall}
 */

/**
 * A function which produces the next InterceptingCall.
 * @function NextCall
 * @param {object} options The grpc call options
 * @return {InterceptingCall|null}
 */
<|endoftext|>


<commit_before>/**
 * offset all vertices in a geometry (positions) by the given 4x4 matrix
 * this returns a new geometry object, with changed positions
 * @param  {Object} geometry object containing positions data (flat array, flat typed array)
 * @param  {String} transformMat4 the 4x4 transformation matrix
 * @return {Object} the modified geometry with updated positions
 */
export default function applyMat4ToGeometry (geometry, transformMat4) {
  const vec3 = require('gl-vec3')

  // matrix
  const {positions} = geometry
  let transformedPositions = new Float32Array(positions.length)

  for (var i = 0; i < positions.length; i += 3) {
    let newPos = vec3.fromValues(positions[i], positions[i + 1], positions[i + 2])
    vec3.transformMat4(newPos, newPos, transformMat4)
    transformedPositions[i] = newPos[0]
    transformedPositions[i + 1] = newPos[1]
    transformedPositions[i + 2] = newPos[2]
  }
  return {...geometry, positions}
}
<commit_msg>fix(applyMat4ToGeometry): fixed wrong, unmodified data getting returned<commit_after>/**
 * offset all vertices in a geometry (positions) by the given 4x4 matrix
 * this returns a new geometry object, with changed positions
 * @param  {Object} geometry object containing positions data (flat array, flat typed array)
 * @param  {String} transformMat4 the 4x4 transformation matrix
 * @return {Object} the modified geometry with updated positions
 */
export default function applyMat4ToGeometry (geometry, transformMat4) {
  const vec3 = require('gl-vec3')

  // matrix
  const {positions} = geometry
  let transformedPositions = new Float32Array(positions.length)

  for (var i = 0; i < positions.length; i += 3) {
    let newPos = vec3.fromValues(positions[i], positions[i + 1], positions[i + 2])
    vec3.transformMat4(newPos, newPos, transformMat4)
    transformedPositions[i] = newPos[0]
    transformedPositions[i + 1] = newPos[1]
    transformedPositions[i + 2] = newPos[2]
  }
  return {...geometry, positions: transformedPositions}
}
<|endoftext|>


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

var fs = require("fs"),
    xlsx = require("xlsx"),
    _ = require("underscore"),
    csv = require("csv"),
    request = require("request");

var inputFileMPs = "data/processed/sexymp_enriched.json",
    inputFileLife= "data/processed/life_expectancy_enriched.json",
    outputFileJson = "data/processed/mp_with_life_expectancy.json",
    outputFileCsv  = "data/processed/mp_with_life_expectancy.csv";

var readJson = function(filename) {
  return JSON.parse(fs.readFileSync(filename));
};

console.log("Mapping MPs with life expectancy data...");

var mpData = readJson(inputFileMPs);
var lifeData = readJson(inputFileLife);

var lifeCodeMap = {};
var lifeCoveredByMap = {};
var lifeOverlappedByMap = {};
_.each(lifeData, function(life) {
  lifeCodeMap[life.code] = life;
  _.each(life.area_covers, function(covered) {
    var as = lifeCoveredByMap[covered] || [];
    as.push(life);
    lifeCoveredByMap[covered] = as;
  });
  _.each(life.area_overlaps, function(overlapped) {
    var as = lifeOverlappedByMap[overlapped] || [];
    as.push(life);
    lifeOverlappedByMap[overlapped] = as;
  });
});

var life_data_keys = [
      "life_exp_birth_male_years",
      "life_exp_birth_male_rank",
      "life_exp_birth_female_years",
      "life_exp_birth_female_rank",
      "life_exp_65_male_years",
      "life_exp_65_male_rank",
      "life_exp_65_female_years",
      "life_exp_65_female_rank"
      ];

var extractLifeData = function(life) {
  return _.pick(life, life_data_keys);
}

var avgLifeData = function(lifes) {
  var r = {};
  var len = lifes.length;
  _.each(life_data_keys, function(k) {
    var v = 0;
    _.each(lifes, function(life) {
      v += life[k];
    });
    r[k] = v / len;
  });
  return r;
};

var findMatchingLifeData = function(area_code) {
  if (lifeCodeMap[area_code]) {
    var life = lifeCodeMap[area_code];
    var r = extractLifeData(life);
    r.match_type = "perfect";
    r.matched_by = [life.code];
    return r;
  }
  if (lifeCoveredByMap[area_code]) {
    areas = lifeCoveredByMap[area_code];
    if (areas.length != 1)
      throw "Unexpected covered-by length for " + area_code + ": " + areas.length;
    var life = areas[0];
    var r = extractLifeData(life);
    r.match_type = "covered_by";
    r.matched_by = [life.code];
    return r;
  }
  if (lifeOverlappedByMap[area_code]) {
    areas = lifeOverlappedByMap[area_code];
    r = avgLifeData(areas);
    r.match_type = "overlapped_by (calculated average)";
    r.matched_by = _.pluck(areas, "code");
    return r;
  }
  return null;
};

var generateDummyLifeData = function(reason) {
  var r = {};
  _.each(life_data_keys, function(k) {
    r[k] = 0;
  });
  r.match_type = reason;
  r.matched_by = [];
  return r;
};

//throw "stop";

var data = []
var ok = 0, fail = 0;
_.each(mpData, function(mp) {
  var str = mp.name + ", " + mp.area_mapit_name + ", " + mp.area_gss_code;
  if (mp.country == "Scotland" || mp.country == "Northern Ireland") {
    console.log("== Data unavailable for " + mp.country + " " + str);
    var life = generateDummyLifeData("no match ("+mp.country+" unavailable)");
    data.push(_.defaults(mp, life));
    ok += 1;
  } else {
    var life = findMatchingLifeData(mp.area_gss_code);
    if (!life) {
      console.log("-- Could not find match for " + str);
      var life = generateDummyLifeData("no match");
      data.push(_.defaults(mp, life));
      fail += 1;
    } else {
      console.log("++ Could find match for " + str + ". Type: " + death.match_type);
      data.push(_.defaults(mp, life));
      ok += 1;
    }
  }
});

if (data.length != mpData.length)
  throw "data length does not match mpData length";

console.log("Ok: " + ok);
console.log("Fail: " + fail);

// Write to files
var jsonString = JSON.stringify(data, null, 2);
fs.writeFileSync(outputFileJson, jsonString);
csv().from(data).to.options({
  quoted: true,
  delimiter: ',',
  columns: _.keys(data[0]),
  header: true
}).to.string(function(csvString) {
  csvString = "sep=,\n" + csvString;
  fs.writeFileSync(outputFileCsv, csvString);
});

console.log("Data for " + data.length + " MPs mapped");
<commit_msg>Fix for copy-and-paste bug<commit_after>#! /usr/bin/env node

var fs = require("fs"),
    xlsx = require("xlsx"),
    _ = require("underscore"),
    csv = require("csv"),
    request = require("request");

var inputFileMPs = "data/processed/sexymp_enriched.json",
    inputFileLife= "data/processed/life_expectancy_enriched.json",
    outputFileJson = "data/processed/mp_with_life_expectancy.json",
    outputFileCsv  = "data/processed/mp_with_life_expectancy.csv";

var readJson = function(filename) {
  return JSON.parse(fs.readFileSync(filename));
};

console.log("Mapping MPs with life expectancy data...");

var mpData = readJson(inputFileMPs);
var lifeData = readJson(inputFileLife);

var lifeCodeMap = {};
var lifeCoveredByMap = {};
var lifeOverlappedByMap = {};
_.each(lifeData, function(life) {
  lifeCodeMap[life.code] = life;
  _.each(life.area_covers, function(covered) {
    var as = lifeCoveredByMap[covered] || [];
    as.push(life);
    lifeCoveredByMap[covered] = as;
  });
  _.each(life.area_overlaps, function(overlapped) {
    var as = lifeOverlappedByMap[overlapped] || [];
    as.push(life);
    lifeOverlappedByMap[overlapped] = as;
  });
});

var life_data_keys = [
      "life_exp_birth_male_years",
      "life_exp_birth_male_rank",
      "life_exp_birth_female_years",
      "life_exp_birth_female_rank",
      "life_exp_65_male_years",
      "life_exp_65_male_rank",
      "life_exp_65_female_years",
      "life_exp_65_female_rank"
      ];

var extractLifeData = function(life) {
  return _.pick(life, life_data_keys);
}

var avgLifeData = function(lifes) {
  var r = {};
  var len = lifes.length;
  _.each(life_data_keys, function(k) {
    var v = 0;
    _.each(lifes, function(life) {
      v += life[k];
    });
    r[k] = v / len;
  });
  return r;
};

var findMatchingLifeData = function(area_code) {
  if (lifeCodeMap[area_code]) {
    var life = lifeCodeMap[area_code];
    var r = extractLifeData(life);
    r.match_type = "perfect";
    r.matched_by = [life.code];
    return r;
  }
  if (lifeCoveredByMap[area_code]) {
    areas = lifeCoveredByMap[area_code];
    if (areas.length != 1)
      throw "Unexpected covered-by length for " + area_code + ": " + areas.length;
    var life = areas[0];
    var r = extractLifeData(life);
    r.match_type = "covered_by";
    r.matched_by = [life.code];
    return r;
  }
  if (lifeOverlappedByMap[area_code]) {
    areas = lifeOverlappedByMap[area_code];
    r = avgLifeData(areas);
    r.match_type = "overlapped_by (calculated average)";
    r.matched_by = _.pluck(areas, "code");
    return r;
  }
  return null;
};

var generateDummyLifeData = function(reason) {
  var r = {};
  _.each(life_data_keys, function(k) {
    r[k] = 0;
  });
  r.match_type = reason;
  r.matched_by = [];
  return r;
};

//throw "stop";

var data = []
var ok = 0, fail = 0;
_.each(mpData, function(mp) {
  var str = mp.name + ", " + mp.area_mapit_name + ", " + mp.area_gss_code;
  if (mp.country == "Scotland" || mp.country == "Northern Ireland") {
    console.log("== Data unavailable for " + mp.country + " " + str);
    var life = generateDummyLifeData("no match ("+mp.country+" unavailable)");
    data.push(_.defaults(mp, life));
    ok += 1;
  } else {
    var life = findMatchingLifeData(mp.area_gss_code);
    if (!life) {
      console.log("-- Could not find match for " + str);
      var life = generateDummyLifeData("no match");
      data.push(_.defaults(mp, life));
      fail += 1;
    } else {
      console.log("++ Could find match for " + str + ". Type: " + life.match_type);
      data.push(_.defaults(mp, life));
      ok += 1;
    }
  }
});

if (data.length != mpData.length)
  throw "data length does not match mpData length";

console.log("Ok: " + ok);
console.log("Fail: " + fail);

// Write to files
var jsonString = JSON.stringify(data, null, 2);
fs.writeFileSync(outputFileJson, jsonString);
csv().from(data).to.options({
  quoted: true,
  delimiter: ',',
  columns: _.keys(data[0]),
  header: true
}).to.string(function(csvString) {
  csvString = "sep=,\n" + csvString;
  fs.writeFileSync(outputFileCsv, csvString);
});

console.log("Data for " + data.length + " MPs mapped");
<|endoftext|>


<commit_before>/*
 * Copyright 2012 LinkedIn, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

$.namespace('azkaban');

var schedulePanelView;
azkaban.SchedulePanelView= Backbone.View.extend({
  events : {
  	"click .closeSchedule": "hideSchedulePanel",
  	"click #schedule-button": "scheduleFlow"
  },
  initialize : function(settings) {
 	$("#datepicker").css("backgroundColor", "transparent");
	$( "#datepicker" ).datepicker();
	$( "#datepicker" ).datepicker('setDate', new Date());
	$( "#datepicker" ).datepicker("hide");
  },
  render: function() {
  },
  showSchedulePanel: function() {
  	$('#scheduleModalBackground').show();
  	$('#schedule-panel').show();
  },
  hideSchedulePanel: function() {
  	$('#scheduleModalBackground').hide();
  	$('#schedule-panel').hide();
  },
  scheduleFlow: function() {
	var hourVal = $('#hour').val();
	var minutesVal = $('#minutes').val();
	var ampmVal = $('#am_pm').val();
	var timezoneVal = $('#timezone').val();
	var dateVal = $('#datepicker').val();
	var is_recurringVal = $('#is_recurring').val();
	var periodVal = $('#period').val();
	var periodUnits = $('#period_units').val();

  	var scheduleURL = contextURL + "/schedule"

  	var scheduleData = flowExecuteDialogView.getExecutionOptionData();
  	 console.log("Creating schedule for "+projectName+"."+scheduleData.flow);
	var scheduleTime = $('#hour').val() + "," + $('#minutes').val() + "," + $('#am_pm').val() + "," + $('#timezone').val();
	var scheduleDate = $('#datepicker').val();
	var is_recurring = $('#is_recurring').val();
	var period = $('#period').val() + $('#period_units').val();

	scheduleData.ajax = "scheduleFlow";
	scheduleData.projectName = projectName;
	scheduleData.scheduleTime = scheduleTime;
	scheduleData.scheduleDate = scheduleDate;
	scheduleData.is_recurring = is_recurring;
	scheduleData.period = period;

	$.post(
			scheduleURL,
			scheduleData,
			function(data) {
				if (data.error) {
					messageDialogView.show("Error Scheduling Flow", data.message);
				}
				else {
					messageDialogView.show("Flow Scheduled", data.message,
					function() {
						window.location.href = scheduleURL;
					}
					);
				}
			},
			"json"
	);
  }
});

$(function() {
	schedulePanelView =  new azkaban.SchedulePanelView({el:$('#scheduleModalBackground')});
});<commit_msg>fix the bug for non-recurring schedules to be scheduled correctly<commit_after>/*
 * Copyright 2012 LinkedIn, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

$.namespace('azkaban');

var schedulePanelView;
azkaban.SchedulePanelView= Backbone.View.extend({
  events : {
  	"click .closeSchedule": "hideSchedulePanel",
  	"click #schedule-button": "scheduleFlow"
  },
  initialize : function(settings) {
 	$("#datepicker").css("backgroundColor", "transparent");
	$( "#datepicker" ).datepicker();
	$( "#datepicker" ).datepicker('setDate', new Date());
	$( "#datepicker" ).datepicker("hide");
  },
  render: function() {
  },
  showSchedulePanel: function() {
  	$('#scheduleModalBackground').show();
  	$('#schedule-panel').show();
  },
  hideSchedulePanel: function() {
  	$('#scheduleModalBackground').hide();
  	$('#schedule-panel').hide();
  },
  scheduleFlow: function() {
	var hourVal = $('#hour').val();
	var minutesVal = $('#minutes').val();
	var ampmVal = $('#am_pm').val();
	var timezoneVal = $('#timezone').val();
	var dateVal = $('#datepicker').val();
	var is_recurringVal = $('#is_recurring').val();
	var periodVal = $('#period').val();
	var periodUnits = $('#period_units').val();

  	var scheduleURL = contextURL + "/schedule"

  	var scheduleData = flowExecuteDialogView.getExecutionOptionData();
  	 console.log("Creating schedule for "+projectName+"."+scheduleData.flow);
	var scheduleTime = $('#hour').val() + "," + $('#minutes').val() + "," + $('#am_pm').val() + "," + $('#timezone').val();
	var scheduleDate = $('#datepicker').val();
	var is_recurring = document.getElementById('is_recurring').checked ? 'on' : 'off';
	var period = $('#period').val() + $('#period_units').val();

	scheduleData.ajax = "scheduleFlow";
	scheduleData.projectName = projectName;
	scheduleData.scheduleTime = scheduleTime;
	scheduleData.scheduleDate = scheduleDate;
	scheduleData.is_recurring = is_recurring;
	scheduleData.period = period;

	$.post(
			scheduleURL,
			scheduleData,
			function(data) {
				if (data.error) {
					messageDialogView.show("Error Scheduling Flow", data.message);
				}
				else {
					messageDialogView.show("Flow Scheduled", data.message,
					function() {
						window.location.href = scheduleURL;
					}
					);
				}
			},
			"json"
	);
  }
});

$(function() {
	schedulePanelView =  new azkaban.SchedulePanelView({el:$('#scheduleModalBackground')});
});<|endoftext|>


<commit_before>var DataModel = require('loopback').DataModel;
var utils = require('./utils');

/*!
 * Default ApplicationCredential properties.
 */
var properties = {
  provider: {type: String, required: true}, // facebook, google, twitter, linkedIn
  authScheme: {type: String}, // oAuth, oAuth 2.0, OpenID, OpenID Connect
  credentials: Object,
  // appId: String, // To be injected by belongsTo relation
  created: Date,
  modified: Date
};

var options = {
  relations: {
    application: {
      type: 'belongsTo',
      model: 'Application',
      foreignKey: 'appId'
    }
  }
};

/**
 * Credentials associated with the LoopBack client application, such as oAuth 2.0
 * client ID/secret, or SSL keys
 *
 * @param{String} provider: The auth provider name, such as facebook, google, twitter, linkedin
 * @param{String} authScheme: The auth scheme, such as oAuth, oAuth 2.0, OpenID, OpenID Connect
 * @param{Object} credentials: Provider-specific credentials.  Actual properties depend on scheme being used:
 *
 *   - openId: {returnURL: String, realm: String}
 *   - oAuth2: {clientID: String, clientSecret: String, callbackURL: String}
 *   - oAuth: {consumerKey: String, consumerSecret: String, callbackURL: String}
 * @param{Date} created: The created date
 * @param{Date} modified: The last modified date
 *
 * @class
 * @inherits {DataModel}
 */
var ApplicationCredential = DataModel.extend('ApplicationCredential', properties, options);
module.exports = ApplicationCredential;

/**
 * Link a third-party application credential with the LoopBack application.
 * @param {String} appId The LoopBack application iID.
 * @param {String} provider The third party provider name.
 * @param {String} authScheme The authentication scheme.
 * @param {Object} credentials Credentials for the given scheme.
 * @callback {Function} cb The callback function.
 * @param {Error|String} err The error object or string.
 * @param {Object} user The user object.
 * @param {Object} [info] The auth info object.
 *
 * -  identity: UserIdentity object
 * -  accessToken: AccessToken object
 */
ApplicationCredential.link = function (appId, provider, authScheme, credentials, cb) {
  var appCredentialModel = utils.getModel(this, ApplicationCredential);
  appCredentialModel.findOne({where: {
    appId: appId,
    provider: provider
  }}, function (err, extCredential) {
    if (err) {
      return cb(err);
    }

    var date = new Date();
    if (extCredential) {
      // Find the app for the given extCredential
      extCredential.credentials = credentials;
      return extCredential.updateAttributes({
        credentials: credentials, modified: date}, cb);
    }

    // Create the linked account
    appCredentialModel.create({
      provider: provider,
      authScheme: authScheme,
      credentials: credentials,
      appId: appId,
      created: date,
      modified: date
    }, function (err, i) {
      cb(err, i);
    });

  });
}
<commit_msg>Add support for loopback 2.x<commit_after>var loopback = require('loopback');
var DataModel = loopback.PersistedModel || loopback.DataModel;
var utils = require('./utils');

/*!
 * Default ApplicationCredential properties.
 */
var properties = {
  provider: {type: String, required: true}, // facebook, google, twitter, linkedIn
  authScheme: {type: String}, // oAuth, oAuth 2.0, OpenID, OpenID Connect
  credentials: Object,
  // appId: String, // To be injected by belongsTo relation
  created: Date,
  modified: Date
};

var options = {
  relations: {
    application: {
      type: 'belongsTo',
      model: 'Application',
      foreignKey: 'appId'
    }
  }
};

/**
 * Credentials associated with the LoopBack client application, such as oAuth 2.0
 * client ID/secret, or SSL keys
 *
 * @param{String} provider: The auth provider name, such as facebook, google, twitter, linkedin
 * @param{String} authScheme: The auth scheme, such as oAuth, oAuth 2.0, OpenID, OpenID Connect
 * @param{Object} credentials: Provider-specific credentials.  Actual properties depend on scheme being used:
 *
 *   - openId: {returnURL: String, realm: String}
 *   - oAuth2: {clientID: String, clientSecret: String, callbackURL: String}
 *   - oAuth: {consumerKey: String, consumerSecret: String, callbackURL: String}
 * @param{Date} created: The created date
 * @param{Date} modified: The last modified date
 *
 * @class
 * @inherits {DataModel}
 */
var ApplicationCredential = DataModel.extend('ApplicationCredential', properties, options);
module.exports = ApplicationCredential;

/**
 * Link a third-party application credential with the LoopBack application.
 * @param {String} appId The LoopBack application iID.
 * @param {String} provider The third party provider name.
 * @param {String} authScheme The authentication scheme.
 * @param {Object} credentials Credentials for the given scheme.
 * @callback {Function} cb The callback function.
 * @param {Error|String} err The error object or string.
 * @param {Object} user The user object.
 * @param {Object} [info] The auth info object.
 *
 * -  identity: UserIdentity object
 * -  accessToken: AccessToken object
 */
ApplicationCredential.link = function (appId, provider, authScheme, credentials, cb) {
  var appCredentialModel = utils.getModel(this, ApplicationCredential);
  appCredentialModel.findOne({where: {
    appId: appId,
    provider: provider
  }}, function (err, extCredential) {
    if (err) {
      return cb(err);
    }

    var date = new Date();
    if (extCredential) {
      // Find the app for the given extCredential
      extCredential.credentials = credentials;
      return extCredential.updateAttributes({
        credentials: credentials, modified: date}, cb);
    }

    // Create the linked account
    appCredentialModel.create({
      provider: provider,
      authScheme: authScheme,
      credentials: credentials,
      appId: appId,
      created: date,
      modified: date
    }, function (err, i) {
      cb(err, i);
    });

  });
}
<|endoftext|>


<commit_before>//<!--  Contains functions to splatter stuff onto overlay based on game events -->
//

function splat(x, y, color, size) {
	this.xOrigin = x;
	this.yOrigin = y;
	this.colorOrigin = color;
	this.color = randomAnalogue(color);
	this.sizeOrigin = size;
	this.bounceDistance = Math.random() * size * 5;
	this.bounceDirection = to_rad(Math.random() * 360);
	this.size = (size * Math.random());
	this.x = this.xOrigin + (this.bounceDistance * Math.sin(this.bounceDirection));
	this.y = this.yOrigin + (-1 * this.bounceDistance * Math.cos(this.bounceDirection));

	splatterCircle(this.x, this.y, this.color, this.size);

};

function splatterSplash(x, y, color, size) {

	var splats = [];

	splatterCircle((x + 10), (y + 10), randomAnalogue(color), size);
};

function splatterCircle(x, y, color, size) {
	console.log("splatterCircle called");
	overlayCtx.beginPath();
  overlayCtx.arc(x, y, size, 0, 2 * Math.PI, false);
  overlayCtx.fillStyle = color;
  overlayCtx.fill();
};

function randomSaturate(color) {
	var _number = (Math.random() * 100) - 50;
	return tinycolor.saturate(color, _number).toHexString();
};

function randomAnalogue(color) {
	var _colors = tinycolor.analogous(color, results = 5, slices = 10)
	var _number = to_i((Math.random() * 6));
	return _colors[_number].toHexString();
};

function to_i(_value)  {
  // uses Bitwise operator to convert value to int. Allegedly faster than Math methods.
  return _value | 0
};

randomAnalog('green');
randomAnalog('green');
randomAnalog('green');
randomAnalog('green');
randomAnalog('green');
randomAnalog('green');
randomAnalog('green');
function to_rad(_degrees){
  return _degrees * (Math.PI / 180)
};
<commit_msg>cleanup<commit_after>//<!--  Contains functions to splatter stuff onto overlay based on game events -->
//

function splat(x, y, color, size) {
	this.xOrigin = x;
	this.yOrigin = y;
	this.colorOrigin = color;
	this.color = randomAnalogue(color);
	this.sizeOrigin = size;
	this.bounceDistance = Math.random() * size * 5;
	this.bounceDirection = to_rad(Math.random() * 360);
	this.size = (size * Math.random());
	this.x = this.xOrigin + (this.bounceDistance * Math.sin(this.bounceDirection));
	this.y = this.yOrigin + (-1 * this.bounceDistance * Math.cos(this.bounceDirection));

	splatterCircle(this.x, this.y, this.color, this.size);

};

function splatterSplash(x, y, color, size) {

	var splats = [];

	splatterCircle((x + 10), (y + 10), randomAnalogue(color), size);
};

function splatterCircle(x, y, color, size) {
	console.log("splatterCircle called");
	overlayCtx.beginPath();
  overlayCtx.arc(x, y, size, 0, 2 * Math.PI, false);
  overlayCtx.fillStyle = color;
  overlayCtx.fill();
};

function randomSaturate(color) {
	var _number = (Math.random() * 100) - 50;
	return tinycolor.saturate(color, _number).toHexString();
};

function randomAnalogue(color) {
	var _colors = tinycolor.analogous(color, results = 5, slices = 10)
	var _number = to_i((Math.random() * 6));
	return _colors[_number].toHexString();
};

function to_i(_value)  {
  // uses Bitwise operator to convert value to integer. Allegedly faster than Math methods.
  return _value | 0
};

function to_rad(_degrees){
  return _degrees * (Math.PI / 180)
};
<|endoftext|>


<commit_before>/**
 * Copyright 2015-2021 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import FormUtils from "../../webcomponents/commons/forms/form-utils.js";
import NotificationUtils from "../commons/utils/notification-utils.js";
import Types from "../commons/types.js";

export default class FamilyUpdate extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            family: {
                type: Object
            },
            familyId: {
                type: String
            },
            opencgaSession: {
                type: Object
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this.family = {};
        this.updateParams = {};
        this.phenotype = {};
    }

    connectedCallback() {
        super.connectedCallback();

        this.updateParams = {};
        this._config = {...this.getDefaultConfig(), ...this.config};
    }

    update(changedProperties) {
        if (changedProperties.has("family")) {
            this.familyObserver();
        }

        if (changedProperties.has("familyId")) {
            this.familyIdObserver();
        }

        super.update(changedProperties);
    }

    familyObserver() {
        if (this.family) {
            this._family = JSON.parse(JSON.stringify(this.family));
        }
    }

    familyIdObserver() {
        if (this.opencgaSession && this.familyId) {
            const query = {
                study: this.opencgaSession.study.fqn
            };
            this.opencgaSession.opencgaClient.families().info(this.familyId, query)
                .then(response => {
                    this.family = response.responses[0].results[0];
                })
                .catch(reason => {
                    console.error(reason);
                });
        }
    }

    onFieldChange(e) {
        switch (e.detail.param) {
            case "id":
            case "name":
            case "description":
            case "expectedSize":
                this.updateParams = FormUtils.updateScalar(
                    this._family,
                    this.family,
                    this.updateParams,
                    e.detail.param,
                    e.detail.value);
                break;
            case "status.name":
            case "status.description":
                this.updateParams = FormUtils.updateObjectWithProps(
                    this._family,
                    this.family,
                    this.updateParams,
                    e.detail.param,
                    e.detail.value
                );
                break;
        }
        this.requestUpdate();
    }

    onClear() {
        this._config = this.getDefaultConfig();
        this.family = JSON.parse(JSON.stringify(this._family));
        this.updateParams = {};
        this.familyId = "";
    }

    onSubmit() {
        const params = {
            study: this.opencgaSession.study.fqn,
            annotationSetsAction: "SET",
            updateRoles: false,
            // incVersion: false
        };

        this.opencgaSession.opencgaClient.families().update(this.family.id, this.updateParams, params)
            .then(res => {
                this._family = JSON.parse(JSON.stringify(this.family));
                this.updateParams = {};
                NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_SUCCESS, {
                    title: "Update Family",
                    message: "family updated correctly"
                });
                // FormUtils.showAlert("Update Family", "Family updated correctly", "success");
            })
            .catch(err => {
                // console.error(err);
                NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_RESPONSE, err);
                // FormUtils.showAlert("Update Family", "Family not updated correctly", "error");
            });
    }

    render() {
        return html`
            <data-form
                    .data=${this.family}
                    .config="${this._config}"
                    .updateParams=${this.updateParams}
                    @fieldChange="${e => this.onFieldChange(e)}"
                    @clear="${this.onClear}"
                    @submit="${this.onSubmit}">
            </data-form>
        `;
    }

    getDefaultConfig() {
        return Types.dataFormConfig({
            title: "Edit",
            icon: "fas fa-edit",
            type: "form",
            display: {
                buttonsVisible: true,
                buttonOkText: "Save",
                buttonClearText: "Cancel",
                style: "margin: 10px",
                titleWidth: 3,
                // labelAlign: "right",
                defaultLayout: "horizontal",
                defaultValue: "",
                // help: {
                //     mode: "block",
                // }
            },
            sections: [
                {
                    title: "Family General Information",
                    elements: [
                        {
                            title: "Family ID",
                            field: "id",
                            type: "input-text",
                            display: {
                                placeholder: "Add a short ID...",
                                disabled: true,
                                helpMessage: "short family id ",
                                validation: {}
                            },
                        },
                        {
                            title: "Name",
                            field: "name",
                            type: "input-text",
                            display: {
                                placeholder: "Add a family name...",
                            }
                        },
                        {
                            title: "Description",
                            field: "description",
                            type: "input-text",
                            display: {
                                rows: 3,
                                placeholder: "Add a Family description...",
                            }
                        },
                        {
                            title: "Individual ID",
                            field: "individualId",
                            type: "custom",
                            display: {
                                placeholder: "e.g. Homo sapiens, ...",
                                render: () => html`
                                    <individual-id-autocomplete
                                        .value="${this.members}"
                                        .opencgaSession="${this.opencgaSession}"
                                        @filterChange="${e => this.onSync(e, "members")}">
                                    </individual-id-autocomplete>`
                            }
                        },
                        {
                            title: "Creation Date",
                            field: "creationDate",
                            type: "input-date",
                            display: {
                                render: date =>
                                    moment(date, "YYYYMMDDHHmmss").format(
                                        "DD/MM/YYYY"
                                    )
                            }
                        },
                        {
                            title: "Modification Date",
                            field: "modificationDate",
                            type: "input-date",
                            display: {
                                render: date =>
                                    moment(date, "YYYYMMDDHHmmss").format(
                                        "DD/MM/YYYY"
                                    )
                            }
                        },
                        {
                            title: "Expected Size",
                            field: "expectedSize",
                            type: "input-text",
                            display: {
                                placeholder: "Add a expected size...",
                            }
                        },
                        {
                            title: "Status name",
                            field: "status.name",
                            type: "input-text",
                            display: {
                                placeholder: "Add status name..."
                            }
                        },
                        {
                            title: "Status Description",
                            field: "status.description",
                            type: "input-text",
                            display: {
                                rows: 3,
                                placeholder: "Add a status description..."
                            }
                        },
                    ]
                },
                // {
                //     title: "Annotations Sets",
                //     elements: [
                //         {
                //             field: "annotationSets",
                //             type: "custom",
                //             display: {
                //                 layout: "vertical",
                //                 defaultLayout: "vertical",
                //                 width: 12,
                //                 style: "padding-left: 0px",
                //                 render: family => html`
                //                     <annotation-set-update
                //                         .annotationSets="${family?.annotationSets}"
                //                         .opencgaSession="${this.opencgaSession}"
                //                         @changeAnnotationSets="${e => this.onSync(e, "annotationsets")}">
                //                     </annotation-set-update>
                //                 `
                //             }
                //         }
                //     ]
                // }
            ]
        });
    }

}

customElements.define("family-update", FamilyUpdate);
<commit_msg>:bug: wc: fixed display family members (#276)<commit_after>/**
 * Copyright 2015-2021 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import FormUtils from "../../webcomponents/commons/forms/form-utils.js";
import NotificationUtils from "../commons/utils/notification-utils.js";
import Types from "../commons/types.js";

export default class FamilyUpdate extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            family: {
                type: Object
            },
            familyId: {
                type: String
            },
            opencgaSession: {
                type: Object
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this.family = {};
        this.updateParams = {};
        this.phenotype = {};
    }

    connectedCallback() {
        super.connectedCallback();

        this.updateParams = {};
        this._config = {...this.getDefaultConfig(), ...this.config};
    }

    update(changedProperties) {
        if (changedProperties.has("family")) {
            this.familyObserver();
        }

        if (changedProperties.has("familyId")) {
            this.familyIdObserver();
        }

        super.update(changedProperties);
    }

    familyObserver() {
        if (this.family) {
            this._family = JSON.parse(JSON.stringify(this.family));
        }
    }

    familyIdObserver() {
        if (this.opencgaSession && this.familyId) {
            const query = {
                study: this.opencgaSession.study.fqn
            };
            this.opencgaSession.opencgaClient.families().info(this.familyId, query)
                .then(response => {
                    this.family = response.responses[0].results[0];
                })
                .catch(reason => {
                    console.error(reason);
                });
        }
    }

    onFieldChange(e) {
        switch (e.detail.param) {
            case "id":
            case "name":
            case "description":
            case "expectedSize":
                this.updateParams = FormUtils.updateScalar(
                    this._family,
                    this.family,
                    this.updateParams,
                    e.detail.param,
                    e.detail.value);
                break;
            case "status.name":
            case "status.description":
                this.updateParams = FormUtils.updateObjectWithProps(
                    this._family,
                    this.family,
                    this.updateParams,
                    e.detail.param,
                    e.detail.value
                );
                break;
        }
        this.requestUpdate();
    }

    onClear() {
        this._config = this.getDefaultConfig();
        this.family = JSON.parse(JSON.stringify(this._family));
        this.updateParams = {};
        this.familyId = "";
    }

    onSubmit() {
        const params = {
            study: this.opencgaSession.study.fqn,
            annotationSetsAction: "SET",
            updateRoles: false,
            // incVersion: false
        };

        this.opencgaSession.opencgaClient.families().update(this.family.id, this.updateParams, params)
            .then(res => {
                this._family = JSON.parse(JSON.stringify(this.family));
                this.updateParams = {};
                NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_SUCCESS, {
                    title: "Update Family",
                    message: "family updated correctly"
                });
                // FormUtils.showAlert("Update Family", "Family updated correctly", "success");
            })
            .catch(err => {
                // console.error(err);
                NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_RESPONSE, err);
                // FormUtils.showAlert("Update Family", "Family not updated correctly", "error");
            });
    }

    render() {
        return html`
            <data-form
                    .data=${this.family}
                    .config="${this._config}"
                    .updateParams=${this.updateParams}
                    @fieldChange="${e => this.onFieldChange(e)}"
                    @clear="${this.onClear}"
                    @submit="${this.onSubmit}">
            </data-form>
        `;
    }

    getDefaultConfig() {
        return Types.dataFormConfig({
            type: "form",
            display: {
                buttonsVisible: true,
                buttonOkText: "Save",
                buttonClearText: "Cancel",
                style: "margin: 10px",
                titleWidth: 3,
                defaultLayout: "horizontal",
                defaultValue: "",
            },
            sections: [
                {
                    title: "Family General Information",
                    elements: [
                        {
                            title: "Family ID",
                            field: "id",
                            type: "input-text",
                            display: {
                                placeholder: "Add a short ID...",
                                disabled: true,
                                helpMessage: "short family id ",
                                validation: {}
                            },
                        },
                        {
                            title: "Name",
                            field: "name",
                            type: "input-text",
                            display: {
                                placeholder: "Add a family name...",
                            }
                        },
                        {
                            title: "Description",
                            field: "description",
                            type: "input-text",
                            display: {
                                rows: 3,
                                placeholder: "Add a Family description...",
                            }
                        },
                        {
                            title: "Members",
                            field: "members",
                            type: "custom",
                            display: {
                                placeholder: "e.g. Homo sapiens, ...",
                                render: members => {
                                    const individualIds = members.map(member => member.id).join(",");
                                    return html`
                                        <individual-id-autocomplete
                                            .value="${individualIds}"
                                            .opencgaSession="${this.opencgaSession}"
                                            .config="${{multiple: true}}"
                                            @filterChange="${e => this.onSync(e, "members")}">
                                        </individual-id-autocomplete>`;
                                }
                            },
                        },
                        // {
                        //     title: "Individual ID",
                        //     field: "individualId",
                        //     type: "custom",
                        //     display: {
                        //         placeholder: "e.g. Homo sapiens, ...",
                        //         render: () => html`
                        //             <individual-id-autocomplete
                        //                 .value="${this.members}"
                        //                 .opencgaSession="${this.opencgaSession}"
                        //                 @filterChange="${e => this.onSync(e, "members")}">
                        //             </individual-id-autocomplete>`
                        //     }
                        // },
                        // {
                        //     title: "Creation Date",
                        //     field: "creationDate",
                        //     type: "input-date",
                        //     display: {
                        //         render: date =>
                        //             moment(date, "YYYYMMDDHHmmss").format(
                        //                 "DD/MM/YYYY"
                        //             )
                        //     }
                        // },
                        // {
                        //     title: "Modification Date",
                        //     field: "modificationDate",
                        //     type: "input-date",
                        //     display: {
                        //         render: date =>
                        //             moment(date, "YYYYMMDDHHmmss").format(
                        //                 "DD/MM/YYYY"
                        //             )
                        //     }
                        // },
                        {
                            title: "Expected Size",
                            field: "expectedSize",
                            type: "input-text",
                            display: {
                                placeholder: "Add a expected size...",
                            }
                        },
                        {
                            title: "Status name",
                            field: "status.name",
                            type: "input-text",
                            display: {
                                placeholder: "Add status name..."
                            }
                        },
                        {
                            title: "Status Description",
                            field: "status.description",
                            type: "input-text",
                            display: {
                                rows: 3,
                                placeholder: "Add a status description..."
                            }
                        },
                    ]
                },
                // {
                //     title: "Annotations Sets",
                //     elements: [
                //         {
                //             field: "annotationSets",
                //             type: "custom",
                //             display: {
                //                 layout: "vertical",
                //                 defaultLayout: "vertical",
                //                 width: 12,
                //                 style: "padding-left: 0px",
                //                 render: family => html`
                //                     <annotation-set-update
                //                         .annotationSets="${family?.annotationSets}"
                //                         .opencgaSession="${this.opencgaSession}"
                //                         @changeAnnotationSets="${e => this.onSync(e, "annotationsets")}">
                //                     </annotation-set-update>
                //                 `
                //             }
                //         }
                //     ]
                // }
            ]
        });
    }

}

customElements.define("family-update", FamilyUpdate);
<|endoftext|>