<commit_before>
import React from 'react';

import decouple from 'decouple';

const CONTENT_DEFAULT_STYLE = {
  position: 'relative'
};

const MENU_DEFAULT_STYLE = {
  bottom: 0,
  left: 0,
  MozOverflowScrolling: 'touch',
  OOverflowScrolling: 'touch',
  overflowY: 'auto',
  overflowScrolling: 'touch',
  position: 'absolute',
  top: 0,
  WebkitOverflowScrolling: 'touch',
  zIndex: 0
};

const PANEL_DEFAULT_STYLE = {
  position: 'relative',
  zIndex: 1
};

const VEIL_INITIAL_STYLE = {
  bottom: 0,
  left: 0,
  position: 'absolute',
  right: 0,
  top: 0
};

const VEIL_DEFAULT_PROPS = {
  opacity: 0.5
};

const VEIL_DEFAULT_STYLE = {
  backgroundColor: 'black'
};

// Definition of modes
const BEHIND = 'behind';
const OVER = 'over';
const PUSH = 'push';

// Definition of sides
const LEFT = 'left';
const RIGHT = 'right';

const buildTransform = (duration, fx) => {
  return 'transform ' + duration + 'ms ' + fx;
};

const buildTranslate3d = translateX => {
  return 'translate3d(' + translateX + 'px, 0, 0)';
};

const prefixes = [ 'Moz', 'ms', 'O', 'WebKit' ];
const extendWithPrefix = (object = {}, property, value) => {
  const prefixObj = {};

  prefixObj[property.toLowerCase()] = value;
  prefixes.map(prefix => {prefixObj[prefix + property] = value; return; });
  return Object.assign(object, prefixObj);
};

class SideBar extends React.Component {

  constructor(props) {
    super(props);
    this.displayName = 'SideBar';

    this.state = {
      _alpha: props.veilStyle.opacity || VEIL_DEFAULT_PROPS.opacity,
      _currentOffsetX: 0,
      _moved: false,
      _opening: false,
      _orientation: this.getOrientation(),
      _preventOpen: false,
      _scrolling: false,
      _startOffsetX: 0,
      _transform: '',
      _transition: '',
      _translateTo: this.getOrientation() * parseInt(props.size, 10),
      _translateX: 0,
      opened: props.opened
    };
  }

  componentDidMount() {
    this.initTouchEvents();
  }

  componentWillReceiveProps(nextProps = {}) {
    if (nextProps.hasOwnProperty('opened')) {
      if (nextProps.opened === true) {
        this.open();
      } else {
        this.close();
      }
    }
    if (nextProps.hasOwnProperty('size')) {
      this.setState({
        _translateTo: this.getOrientation() * parseInt(nextProps.size, 10)
      });
    }
    if (nextProps.hasOwnProperty('side')) {
      this.setState({
        _orientation: this.getOrientation(nextProps.side),
        _translateTo:
          this.getOrientation(nextProps.side) * parseInt(nextProps.size, 10)
      });
    }
  }

  close() {
    if (!this.isOpen() && !this.state._opening) return;

    this.setTransition();
    this.translateXTo(0);

    let newState = {
      _moved: false,
      _opening: false,
      _transition: '',
      _transform: '',
      _translateX: 0,
      opened: false
    };

    window.setTimeout(() => {
      this.setState(newState);
    }, this.props.duration + 50);
  }

  getOrientation(side = this.props.side) {
    return side === LEFT ? 1 : -1;
  }

  getVeilOpacity() {
    const { _alpha, _currentOffsetX, _startOffsetX } = this.state;
    const { size } = this.props;
    let opacity = 0;

    if (_startOffsetX < size) {
      opacity = 0;
      if (_currentOffsetX > 0) {
        opacity = (_currentOffsetX * _alpha) / size;
      }
    } else {
      opacity = _alpha;
      if (_currentOffsetX <= 0) {
        opacity = ((size + _currentOffsetX) * _alpha) / size;
      }
    }

    if (opacity > _alpha) {
      opacity = _alpha;
    }

    if (this.props.side === RIGHT) {
      opacity = (_alpha - opacity);
    }

    return opacity;
  }

  handleClickPanel() {
    if (!this.state._opening) {
      this.close();
      if (this.props.onClose) {
        this.props.onClose();
      }
    }
  }

  initTouchEvents() {
    this.onScrollFn();
    window.document.addEventListener('touchmove', this.preventMove.bind(this));
  }

  isOpen() {
    return this.state.opened;
  }

  onScrollFn() {
    return decouple(window.document, 'scroll', () => {
      if (!this.state._moved) {
        window.clearTimeout(this.state.scrollTimeout);
        this.setState({ scrolling: true });

        let timeout = window.setTimeout(() => {
          this.setState({
            scrolling: false
          });
        }, 250);

        this.setState({ scrollTimeout: timeout });
      }
    });
  }

  onTouchCancelFn() {
    this.setState({
      _moved: false,
      _opening: false
    });
  }

  onTouchEndFn(e) {
    const { onOpen, onClose, tolerance } = this.props;

    if (this.state._moved) {
      if (this.state._opening &&
        tolerance < (this.state._orientation * this.state._currentOffsetX)) {
        this.open();
        if (onOpen) {
          onOpen();
        }
      } else {
        this.close();
        if (onClose) {
          onClose();
        }
      }
      this.setState({ _opening: false });
    }
  }

  onTouchMoveFn(e) {
    if (this.state._scrolling || this.state._preventOpen || !e.touches) return;

    let diffX = e.touches[0].clientX - this.state._startOffsetX;
    let translateX = diffX;

    this.setState({ _currentOffsetX: diffX });

    if (this.props.size < Math.abs(translateX)) return;

    if (Math.abs(diffX) > 20) {
      let orientedDiffX = diffX * this.state._orientation;

      if (this.state.opened && orientedDiffX > 0 || !this.state.opened &&
      orientedDiffX < 0) {
        return;
      }

      if (orientedDiffX <= 0) {
        translateX = diffX + this.props.size * this.state._orientation;
        this.setState({ _opening: false });
      }

      this.setState({
        _moved: true,
        _opening: true,
        _transform: buildTranslate3d(translateX),
        _translateX: translateX
      });
    }
  }

  open() {
    this.setTransition();
    this.translateXTo(this.state._translateTo);
    this.setState({
      opened: true
    });

    let newState = {
      _moved: false,
      _transition: ''
    };

    window.setTimeout(() => {
      this.setState(newState);
    }, this.props.duration + 50);
  }

  preventMove(e) {
    if (this.state._moved) {
      e.preventDefault();
    }
  }

  resetTouchFn(e) {
    if (!e.touches) return;

    const { side, touch, touchSize } = this.props;
    const clientX = e.touches[0].clientX;
    const clientWidth = this._wrapper.clientWidth;
    const isOpen = this.isOpen();
    const isLeft = (side === LEFT);
    const isRight = (side === RIGHT);

    const _preventOpen =
      (!touch) || (!isOpen && touchSize !== 0 && (
        (isLeft && clientX > touchSize) ||
        (isRight && clientX < clientWidth - touchSize)
      ));

    this.setState({
      _moved: false,
      _opening: false,
      _preventOpen: _preventOpen,
      _startOffsetX: e.touches[0].pageX
    });
  }

  setTransition() {
    this.setState({
      _transition: buildTransform(this.props.duration, this.props.fx)
    });
  }

  translateXTo(translateX) {
    this.setState({
      _currentOffsetX: translateX,
      _transform: buildTranslate3d(translateX),
      _translateX: translateX
    });
  }

  render() {
    const { children, bar, mode, side, size, topBar } = this.props;
    const { _currentOffsetX, _moved, _opening, _transition, _transform,
      _translateX } = this.state;
    const barStyle = Object.assign({}, MENU_DEFAULT_STYLE, { width: size });

    if (side === RIGHT) {
      delete barStyle.left;
      barStyle.right = 0;
    }

    if (~[PUSH, OVER].indexOf(mode)) {
      delete barStyle.left;
      delete barStyle.right;

      let _transformMode = buildTranslate3d(_translateX - size);

      if (side === RIGHT) {
        const end = this._wrapper.clientWidth + _translateX;

        _transformMode = buildTranslate3d(end);
      }

      extendWithPrefix(barStyle, 'Transition', _transition);
      extendWithPrefix(barStyle, 'Transform', _transformMode);
      barStyle.zIndex = 2;
    }

    const panelStyle = Object.assign({}, PANEL_DEFAULT_STYLE);

    if (mode !== OVER) {
      extendWithPrefix(panelStyle, 'Transition', _transition);
      extendWithPrefix(panelStyle, 'Transform', _transform);
    }

    const veilStyle = Object.assign({}, VEIL_DEFAULT_STYLE,
      this.props.veilStyle, VEIL_INITIAL_STYLE,
      { opacity: this.getVeilOpacity() });

    const wrapperStyle = {},
          opened = this.isOpen();

    if (opened || _moved) {
      panelStyle.overflow = 'hidden';
      wrapperStyle.overflow = 'hidden';
    }

    // Build props for bar
    const contentProps = {
      className: `side-bar-content${ opened ? ' opened' : '' }`,
      style: CONTENT_DEFAULT_STYLE
    };

    // Build props for bar
    const barProps = {
      className: 'side-bar',
      style: barStyle
    };

    // Build props for panel
    const panelProps = {
      className: 'side-bar-panel',
      style: panelStyle,
      onTouchStart: this.resetTouchFn.bind(this),
      onTouchCancel: this.onTouchCancelFn.bind(this),
      onTouchEnd: this.onTouchEndFn.bind(this),
      onTouchMove: this.onTouchMoveFn.bind(this),
      ref: (comp => (this._panel = comp))
    };

    const topBarProps = {
      className: 'side-bar-topBar'
    };

    // Build props for veil
    const veilProps = {
      style: veilStyle,
      onClick: this.handleClickPanel.bind(this)
    };

    // Build props for wrapper
    const wrapperProps = {
      ref: (comp => (this._wrapper = comp)),
      style: wrapperStyle
    };

    return (

        { topBar &&
{topBar}
 }

{ bar }

            { (_currentOffsetX !== 0 || _opening) &&
 }
            { children }

    );
  }
}

SideBar.propTypes = {
  children: React.PropTypes.array,
  bar: React.PropTypes.element.isRequired,
  duration: React.PropTypes.number,
  fx: React.PropTypes.string,
  mode: React.PropTypes.string,
  onClose: React.PropTypes.func,
  onOpen: React.PropTypes.func,
  opened: React.PropTypes.bool,
  tolerance: React.PropTypes.number,
  touch: React.PropTypes.bool,
  touchSize: React.PropTypes.number,
  size: React.PropTypes.number,
  side: React.PropTypes.string,
  topBar: React.PropTypes.any,
  veilStyle: React.PropTypes.object
};

SideBar.defaultProps = {
  duration: 150,
  fx: 'cubic-bezier(0, 1, 0.85, 1)',
  mode: OVER,
  opened: false,
  side: LEFT,
  size: 256,
  tolerance: 70,
  touch: true,
  touchSize: 80,
  veilStyle: {}
};

SideBar.MODES = { BEHIND, OVER, PUSH };

SideBar.SIDES = { LEFT, RIGHT };

export default SideBar;
<commit_msg>Closed style add, little refactoring<commit_after>
import React from 'react';

import decouple from 'decouple';

const CONTENT_DEFAULT_STYLE = {
  position: 'relative'
};

const MENU_DEFAULT_STYLE = {
  bottom: 0,
  left: 0,
  MozOverflowScrolling: 'touch',
  OOverflowScrolling: 'touch',
  overflowY: 'auto',
  overflowScrolling: 'touch',
  position: 'absolute',
  top: 0,
  WebkitOverflowScrolling: 'touch',
  zIndex: 0
};

const PANEL_DEFAULT_STYLE = {
  position: 'relative',
  zIndex: 1
};

const VEIL_INITIAL_STYLE = {
  bottom: 0,
  left: 0,
  position: 'absolute',
  right: 0,
  top: 0
};

const VEIL_DEFAULT_PROPS = {
  opacity: 0.5
};

const VEIL_DEFAULT_STYLE = {
  backgroundColor: 'black'
};

// Definition of modes
const BEHIND = 'behind';
const OVER = 'over';
const PUSH = 'push';

// Definition of sides
const LEFT = 'left';
const RIGHT = 'right';

const buildTransform = (duration, fx) => {
  return 'transform ' + duration + 'ms ' + fx;
};

const buildTranslate3d = translateX => {
  return 'translate3d(' + translateX + 'px, 0, 0)';
};

const prefixes = [ 'Moz', 'ms', 'O', 'WebKit' ];
const extendWithPrefix = (object = {}, property, value) => {
  const prefixObj = {};

  prefixObj[property.toLowerCase()] = value;
  prefixes.map(prefix => {prefixObj[prefix + property] = value; return; });
  return Object.assign(object, prefixObj);
};

class SideBar extends React.Component {

  constructor(props) {
    super(props);
    this.displayName = 'SideBar';

    this.state = {
      _alpha: props.veilStyle.opacity || VEIL_DEFAULT_PROPS.opacity,
      _currentOffsetX: 0,
      _moved: false,
      _opening: false,
      _orientation: this.getOrientation(),
      _preventOpen: false,
      _scrolling: false,
      _startOffsetX: 0,
      _transform: '',
      _transition: '',
      _translateTo: this.getOrientation() * parseInt(props.size, 10),
      _translateX: 0,
      opened: props.opened
    };
  }

  componentDidMount() {
    this.initTouchEvents();
  }

  componentWillReceiveProps(nextProps = {}) {
    if (nextProps.hasOwnProperty('opened')) {
      if (nextProps.opened === true) {
        this.open();
      } else {
        this.close();
      }
    }
    if (nextProps.hasOwnProperty('size')) {
      this.setState({
        _translateTo: this.getOrientation() * parseInt(nextProps.size, 10)
      });
    }
    if (nextProps.hasOwnProperty('side')) {
      this.setState({
        _orientation: this.getOrientation(nextProps.side),
        _translateTo:
          this.getOrientation(nextProps.side) * parseInt(nextProps.size, 10)
      });
    }
  }

  close() {
    if (!this.isOpen() && !this.state._opening) return;

    this.setTransition();
    this.translateXTo(0);

    let newState = {
      _moved: false,
      _opening: false,
      _transition: '',
      _transform: '',
      _translateX: 0,
      opened: false
    };

    window.setTimeout(() => {
      this.setState(newState);
    }, this.props.duration + 50);
  }

  getOrientation(side = this.props.side) {
    return side === LEFT ? 1 : -1;
  }

  getVeilOpacity() {
    const { _alpha, _currentOffsetX, _startOffsetX } = this.state;
    const { size } = this.props;
    let opacity = 0;

    if (_startOffsetX < size) {
      opacity = 0;
      if (_currentOffsetX > 0) {
        opacity = (_currentOffsetX * _alpha) / size;
      }
    } else {
      opacity = _alpha;
      if (_currentOffsetX <= 0) {
        opacity = ((size + _currentOffsetX) * _alpha) / size;
      }
    }

    if (opacity > _alpha) {
      opacity = _alpha;
    }

    if (this.props.side === RIGHT) {
      opacity = (_alpha - opacity);
    }

    return opacity;
  }

  handleClickPanel() {
    if (!this.state._opening) {
      this.close();
      if (this.props.onClose) {
        this.props.onClose();
      }
    }
  }

  initTouchEvents() {
    this.onScrollFn();
    window.document.addEventListener('touchmove', this.preventMove.bind(this));
  }

  isOpen() {
    return this.state.opened;
  }

  onScrollFn() {
    return decouple(window.document, 'scroll', () => {
      if (!this.state._moved) {
        window.clearTimeout(this.state.scrollTimeout);
        this.setState({ scrolling: true });

        let timeout = window.setTimeout(() => {
          this.setState({
            scrolling: false
          });
        }, 250);

        this.setState({ scrollTimeout: timeout });
      }
    });
  }

  onTouchCancelFn() {
    this.setState({
      _moved: false,
      _opening: false
    });
  }

  onTouchEndFn(e) {
    const { onOpen, onClose, tolerance } = this.props;

    if (this.state._moved) {
      if (this.state._opening &&
        tolerance < (this.state._orientation * this.state._currentOffsetX)) {
        this.open();
        if (onOpen) {
          onOpen();
        }
      } else {
        this.close();
        if (onClose) {
          onClose();
        }
      }
      this.setState({ _opening: false });
    }
  }

  onTouchMoveFn(e) {
    if (this.state._scrolling || this.state._preventOpen || !e.touches) return;

    let diffX = e.touches[0].clientX - this.state._startOffsetX;
    let translateX = diffX;

    this.setState({ _currentOffsetX: diffX });

    if (this.props.size < Math.abs(translateX)) return;

    if (Math.abs(diffX) > 20) {
      let orientedDiffX = diffX * this.state._orientation;

      if (this.state.opened && orientedDiffX > 0 || !this.state.opened &&
      orientedDiffX < 0) {
        return;
      }

      if (orientedDiffX <= 0) {
        translateX = diffX + this.props.size * this.state._orientation;
        this.setState({ _opening: false });
      }

      this.setState({
        _moved: true,
        _opening: true,
        _transform: buildTranslate3d(translateX),
        _translateX: translateX
      });
    }
  }

  open() {
    this.setTransition();
    this.translateXTo(this.state._translateTo);
    this.setState({
      opened: true
    });

    let newState = {
      _moved: false,
      _transition: ''
    };

    window.setTimeout(() => {
      this.setState(newState);
    }, this.props.duration + 50);
  }

  preventMove(e) {
    if (this.state._moved) {
      e.preventDefault();
    }
  }

  resetTouchFn(e) {
    if (!e.touches) return;

    const { side, touch, touchSize } = this.props;
    const clientX = e.touches[0].clientX;
    const clientWidth = this._wrapper.clientWidth;
    const isOpen = this.isOpen();
    const isLeft = (side === LEFT);
    const isRight = (side === RIGHT);

    const _preventOpen =
      (!touch) || (!isOpen && touchSize !== 0 && (
        (isLeft && clientX > touchSize) ||
        (isRight && clientX < clientWidth - touchSize)
      ));

    this.setState({
      _moved: false,
      _opening: false,
      _preventOpen: _preventOpen,
      _startOffsetX: e.touches[0].pageX
    });
  }

  setTransition() {
    this.setState({
      _transition: buildTransform(this.props.duration, this.props.fx)
    });
  }

  translateXTo(translateX) {
    this.setState({
      _currentOffsetX: translateX,
      _transform: buildTranslate3d(translateX),
      _translateX: translateX
    });
  }

  render() {
    const { children, bar, mode, side, size, topBar } = this.props;
    const { _currentOffsetX, _moved, _opening, _transition, _transform,
      _translateX } = this.state;
    const barStyle = Object.assign({}, MENU_DEFAULT_STYLE, { width: size });

    if (side === RIGHT) {
      delete barStyle.left;
      barStyle.right = 0;
    }

    if (~[PUSH, OVER].indexOf(mode)) {
      delete barStyle.left;
      delete barStyle.right;

      let _transformMode = buildTranslate3d(_translateX - size);

      if (side === RIGHT) {
        const end = this._wrapper.clientWidth + _translateX;

        _transformMode = buildTranslate3d(end);
      }

      extendWithPrefix(barStyle, 'Transition', _transition);
      extendWithPrefix(barStyle, 'Transform', _transformMode);
      barStyle.zIndex = 2;
    }

    const panelStyle = Object.assign({}, PANEL_DEFAULT_STYLE);

    if (mode !== OVER) {
      extendWithPrefix(panelStyle, 'Transition', _transition);
      extendWithPrefix(panelStyle, 'Transform', _transform);
    }

    const veilStyle = Object.assign({}, VEIL_DEFAULT_STYLE,
      this.props.veilStyle, VEIL_INITIAL_STYLE,
      { opacity: this.getVeilOpacity() });

    const wrapperStyle = {};
    const opened = this.isOpen();

    if (opened || _moved) {
      panelStyle.overflow = 'hidden';
      wrapperStyle.overflow = 'hidden';
    }

    // Build props for bar
    const contentProps = {
      className: `side-bar-content${ opened ? ' opened' : ' closed' }`,
      style: CONTENT_DEFAULT_STYLE
    };

    // Build props for bar
    const barProps = {
      className: 'side-bar',
      style: barStyle
    };

    // Build props for panel
    const panelProps = {
      className: 'side-bar-panel',
      style: panelStyle,
      onTouchStart: this.resetTouchFn.bind(this),
      onTouchCancel: this.onTouchCancelFn.bind(this),
      onTouchEnd: this.onTouchEndFn.bind(this),
      onTouchMove: this.onTouchMoveFn.bind(this),
      ref: (comp => (this._panel = comp))
    };

    const topBarProps = {
      className: 'side-bar-topBar'
    };

    // Build props for veil
    const veilProps = {
      style: veilStyle,
      onClick: this.handleClickPanel.bind(this)
    };

    // Build props for wrapper
    const wrapperProps = {
      ref: (comp => (this._wrapper = comp)),
      style: wrapperStyle
    };

    return (

        { topBar &&
{topBar}
 }

{ bar }

            { (_currentOffsetX !== 0 || _opening) &&
 }
            { children }

    );
  }
}

SideBar.propTypes = {
  children: React.PropTypes.array,
  bar: React.PropTypes.element.isRequired,
  duration: React.PropTypes.number,
  fx: React.PropTypes.string,
  mode: React.PropTypes.string,
  onClose: React.PropTypes.func,
  onOpen: React.PropTypes.func,
  opened: React.PropTypes.bool,
  tolerance: React.PropTypes.number,
  touch: React.PropTypes.bool,
  touchSize: React.PropTypes.number,
  size: React.PropTypes.number,
  side: React.PropTypes.string,
  topBar: React.PropTypes.any,
  veilStyle: React.PropTypes.object
};

SideBar.defaultProps = {
  duration: 150,
  fx: 'cubic-bezier(0, 1, 0.85, 1)',
  mode: OVER,
  opened: false,
  side: LEFT,
  size: 256,
  tolerance: 70,
  touch: true,
  touchSize: 80,
  veilStyle: {}
};

SideBar.MODES = { BEHIND, OVER, PUSH };

SideBar.SIDES = { LEFT, RIGHT };

export default SideBar;
<|endoftext|>


<commit_before>/*
The slicing class contains pure functions for computing and rendering
anything related to the right side of the screen (slices of higher dimensional objects)
*/
var Slicing = (function (scope) {
	function Slicing(){

	}

	Slicing.prototype.Slice2DMesh = function(mesh,uniforms,color){
		/* Takes a mesh and returns a version of it with a shader material that slices */
		vertexShader = `
			varying vec4 vertexPosition;
			void main() {
				vertexPosition = modelMatrix * vec4(position,1.0);
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
			}
  		`;

  		var fragmentShader =`
        varying vec4 vertexPosition;
        uniform vec2 axisValue;
        uniform float axis; // 0 is x, 1 is y
        uniform float slice;
        uniform float renderWholeShape;

        void main(){
        	vec4 color = vec4(${color.r/255},${color.g/255},${color.b/255},1.0);
        	vec2 p = vec2(vertexPosition.x,vertexPosition.y);

        	gl_FragColor = color;
 			if(slice == 0.0) return;
 			// Slicing code
 			gl_FragColor.a = 1.0;
 			float sliceThickness = 0.1;
        	if(axis == 0.0){
        		if(abs(p.x) > sliceThickness) {
        			if(renderWholeShape == 1.0){
        				gl_FragColor.a = 0.15;
        			}
        			else {
        				discard;
        			}
        		}
        	}
        	if(axis == 1.0){
        		if(abs(p.y) > sliceThickness) {
        			if(renderWholeShape == 1.0){
        				gl_FragColor.a = 0.15;
        			}
        			else {
        				discard;
        			}
        		}
        	}

        }
        `;

		var geometry = mesh.geometry.clone();
		var material = new THREE.ShaderMaterial({
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            uniforms: uniforms
        });
        material.transparent = true;
		var mesh = new THREE.Mesh( geometry, material );

		return mesh;
	}

	Slicing.prototype.CartesianSlice3D = function(glslFuncString,uniforms,color){
		/*
			Takes in a glsl function and an operator (>,< or =) and renders that
		*/

  		vertexShader = `
			varying vec4 vertexPosition;
			void main() {
				vertexPosition = modelMatrix * vec4(position,1.0);
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
			}
  		`;

        var fragmentShader =`
        varying vec4 vertexPosition;
        uniform float axisValue;

        float eq(float x,float y,float axisValue){
        	${glslFuncString}
        }

        void main(){
        	vec4 color = vec4(${color.r/255},${color.g/255},${color.b/255},1.0);
        	vec2 p = vec2(vertexPosition.x,vertexPosition.y);

        	float val = eq(p.x,p.y,axisValue);
        	if(val > 0.0) discard;

        	gl_FragColor = color;

        }
        `;

        var geometry = new THREE.PlaneBufferGeometry(20, 20);
        var material = new THREE.ShaderMaterial({
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            uniforms: uniforms
        });

        var mesh = new THREE.Mesh(geometry, material);

        return mesh;
	}

	Slicing.prototype.CreateSliceShader3D = function(uniforms,color){
		vertexShader = `
			varying vec4 vertexPosition;
			void main() {
				vertexPosition = modelMatrix * vec4(position,1.0);
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
			}
  		`;

  		var fragmentShader =`
        varying vec4 vertexPosition;
        uniform float axisValue;

        void main(){
        	vec4 color = vec4(${color.r/255},${color.g/255},${color.b/255},1.0);
        	vec3 p = vertexPosition.xyz;
        	float threshold = 0.1;
        	// Offset shape
        	p.z -= axisValue;

        	if(p.z > threshold || p.z < -threshold) discard;

        	gl_FragColor = color;
        }
        `;

        var material = new THREE.ShaderMaterial({
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            uniforms: uniforms,
            side:THREE.DoubleSide
        });

        return material;
	}

	Slicing.prototype.SliceConvex3D = function(mesh,axis,axisValue,color,outlineOnly){
		// Go through all the faces of the mesh
		var triangleArray = [];
		var container = new THREE.Object3D();

		if(mesh.geometry.faces == null){
			// var vertArray = mesh.geometry.attributes.position.array;
			// var indices = mesh.geometry.index.array;
			// var maxNum = 0;
			// console.log("vertArray.length: ",vertArray.length);
			// console.log("indices.length: ",indices.length);
			// for(var i=0;i<indices.length;i++){
			// 	if(indices[i] > maxNum) maxNum = indices[i];
			// }
			// console.log("Max index: ",maxNum);
			return container;
		}

		var faces = mesh.geometry.faces;
		var verts = mesh.geometry.vertices;

		for(var i=0;i<faces.length;i++){
			var f = faces[i];
			var v1 = verts[f.a];
			var v2 = verts[f.b];
			var v3 = verts[f.c];

			triangleArray.push([v1,v2,v3]);
		}

		var vectorArray = [];

		for(var i=0;i<triangleArray.length;i++){
			var p1 = triangleArray[i][0];
			var p2 = triangleArray[i][1];
			var p3 = triangleArray[i][2];

			var pToArr = function(p){
				return [p.x,p.y,p.z];
			}

			var points = this.CalculateIntersectionPoints(pToArr(p1),pToArr(p2),pToArr(p3),axis,axisValue);
			if(points.length == 0) continue; // This happens if there's no intersection
			// Intersect the points and get two points
			var Z = Math.random() * 0.01;
			var v1 = new THREE.Vector3(points[0],points[1],Z);
			var v2 = new THREE.Vector3(points[2],points[3],Z);
			// Draw a line between those two points
			if(outlineOnly){
				var geometry = new THREE.Geometry();
				geometry.vertices.push( v1 );
				geometry.vertices.push( v2 );
				var line = new MeshLine();
				line.setGeometry( geometry );
				var material = new MeshLineMaterial({color:new THREE.Color(color),lineWidth:0.1});
				var mesh = new THREE.Mesh( line.geometry, material );
				container.add(mesh);
			} else {
				vectorArray.push(v1);
				vectorArray.push(v2);
			}

		}

		if(outlineOnly){
			return container;
		} else {
			var geometry = new THREE.ConvexGeometry( vectorArray );
			var material = new THREE.MeshBasicMaterial( {color: color} );
			var mesh = new THREE.Mesh( geometry, material );
			return mesh;
		}

	}

	Slicing.prototype.CalculateIntersectionPoints = function(p1,p2,p3,axis,axis_value) {
		/*
		Given a triangle (as 3 points) and a line (an axis), return the two points of intersection
			Input:
				p1,p2,p3 = [Number,Number,Number] representing 3D points
				axis = "X" | "Y" | "Z"
				axis_value = Number
			Output:
				[x,y,x,y]
		*/
		var axis_conv = {'X':0, 'Y':1, 'Z':2}
		var chosen_axis = 1;
		var other_axis_one = 0;
		var other_axis_two = 2;
		if(axis == "X"){
			chosen_axis = 0;
			other_axis_one = 2;
			other_axis_two = 1;
		}
		if(axis == "Z"){
			chosen_axis = 2;
			other_axis_one = 1;
			other_axis_two = 0;
		}

		//if (axis == 'Y') { // currently only handles Y axis. Needs to be generalized to X and Y

		var intersection_point = [];

		var above = [];
		var below = [];
		if (p1[axis_conv[axis]] > axis_value) above.push(p1);
		else below.push(p1);

		if (p2[axis_conv[axis]] > axis_value) above.push(p2);
		else below.push(p2);

		if (p3[axis_conv[axis]] > axis_value) above.push(p3);
		else below.push(p3);

		// If completely above or completely below, then no intersection
		if(below.length == 3 || above.length == 3) return [];

		if (below.length > 1) {

		  var direction = [3];
		  direction[0] = below[0][axis_conv['X']] - above[0][axis_conv['X']];
		  direction[1] = below[0][axis_conv['Y']] - above[0][axis_conv['Y']];
		  direction[2] = below[0][axis_conv['Z']] - above[0][axis_conv['Z']];

		  var t = (below[0][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[0] = below[0][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[1] = axis_value;
		  intersection_point[1] = below[0][other_axis_two] + t * direction[other_axis_two];

		  direction[0] = below[1][axis_conv['X']] - above[0][axis_conv['X']];
		  direction[1] = below[1][axis_conv['Y']] - above[0][axis_conv['Y']];
		  direction[2] = below[1][axis_conv['Z']] - above[0][axis_conv['Z']];

		  t = (below[1][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[2] = below[1][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[4] = axis_value;
		  intersection_point[3] = below[1][other_axis_two] + t * direction[other_axis_two];

		  return intersection_point;
		}
		else {
		  var direction = [3];
		  direction[0] = above[0][axis_conv['X']] - below[0][axis_conv['X']];
		  direction[1] = above[0][axis_conv['Y']] - below[0][axis_conv['Y']];
		  direction[2] = above[0][axis_conv['Z']] - below[0][axis_conv['Z']];

		  var t = (above[0][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[0] = above[0][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[1] = axis_value;
		  intersection_point[1] = above[0][other_axis_two] + t * direction[other_axis_two];

		  direction[0] = above[1][axis_conv['X']] - below[0][axis_conv['X']];
		  direction[1] = above[1][axis_conv['Y']] - below[0][axis_conv['Y']];
		  direction[2] = above[1][axis_conv['Z']] - below[0][axis_conv['Z']];

		  var t = (above[1][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[2] = above[1][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[4] = axis_value;
		  intersection_point[3] = above[1][other_axis_two] + t * direction[other_axis_two];

		  return intersection_point;
		}
	}
	scope.Slicing = Slicing;
	return Slicing;
})(typeof exports === 'undefined' ? {} : exports);<commit_msg>Made CPU parametric intersection lightning fast<commit_after>/*
The slicing class contains pure functions for computing and rendering
anything related to the right side of the screen (slices of higher dimensional objects)
*/
var Slicing = (function (scope) {
	function Slicing(){

	}

	Slicing.prototype.Slice2DMesh = function(mesh,uniforms,color){
		/* Takes a mesh and returns a version of it with a shader material that slices */
		vertexShader = `
			varying vec4 vertexPosition;
			void main() {
				vertexPosition = modelMatrix * vec4(position,1.0);
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
			}
  		`;

  		var fragmentShader =`
        varying vec4 vertexPosition;
        uniform vec2 axisValue;
        uniform float axis; // 0 is x, 1 is y
        uniform float slice;
        uniform float renderWholeShape;

        void main(){
        	vec4 color = vec4(${color.r/255},${color.g/255},${color.b/255},1.0);
        	vec2 p = vec2(vertexPosition.x,vertexPosition.y);

        	gl_FragColor = color;
 			if(slice == 0.0) return;
 			// Slicing code
 			gl_FragColor.a = 1.0;
 			float sliceThickness = 0.1;
        	if(axis == 0.0){
        		if(abs(p.x) > sliceThickness) {
        			if(renderWholeShape == 1.0){
        				gl_FragColor.a = 0.15;
        			}
        			else {
        				discard;
        			}
        		}
        	}
        	if(axis == 1.0){
        		if(abs(p.y) > sliceThickness) {
        			if(renderWholeShape == 1.0){
        				gl_FragColor.a = 0.15;
        			}
        			else {
        				discard;
        			}
        		}
        	}

        }
        `;

		var geometry = mesh.geometry.clone();
		var material = new THREE.ShaderMaterial({
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            uniforms: uniforms
        });
        material.transparent = true;
		var mesh = new THREE.Mesh( geometry, material );

		return mesh;
	}

	Slicing.prototype.CartesianSlice3D = function(glslFuncString,uniforms,color){
		/*
			Takes in a glsl function and an operator (>,< or =) and renders that
		*/

  		vertexShader = `
			varying vec4 vertexPosition;
			void main() {
				vertexPosition = modelMatrix * vec4(position,1.0);
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
			}
  		`;

        var fragmentShader =`
        varying vec4 vertexPosition;
        uniform float axisValue;

        float eq(float x,float y,float axisValue){
        	${glslFuncString}
        }

        void main(){
        	vec4 color = vec4(${color.r/255},${color.g/255},${color.b/255},1.0);
        	vec2 p = vec2(vertexPosition.x,vertexPosition.y);

        	float val = eq(p.x,p.y,axisValue);
        	if(val > 0.0) discard;

        	gl_FragColor = color;

        }
        `;

        var geometry = new THREE.PlaneBufferGeometry(20, 20);
        var material = new THREE.ShaderMaterial({
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            uniforms: uniforms
        });

        var mesh = new THREE.Mesh(geometry, material);

        return mesh;
	}

	Slicing.prototype.CreateSliceShader3D = function(uniforms,color){
		vertexShader = `
			varying vec4 vertexPosition;
			void main() {
				vertexPosition = modelMatrix * vec4(position,1.0);
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
			}
  		`;

  		var fragmentShader =`
        varying vec4 vertexPosition;
        uniform float axisValue;

        void main(){
        	vec4 color = vec4(${color.r/255},${color.g/255},${color.b/255},1.0);
        	vec3 p = vertexPosition.xyz;
        	float threshold = 0.1;
        	// Offset shape
        	p.z -= axisValue;

        	if(p.z > threshold || p.z < -threshold) discard;

        	gl_FragColor = color;
        }
        `;

        var material = new THREE.ShaderMaterial({
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            uniforms: uniforms,
            side:THREE.DoubleSide
        });

        return material;
	}

	Slicing.prototype.SliceConvex3D = function(mesh,axis,axisValue,color,outlineOnly){
		// Go through all the faces of the mesh
		var triangleArray = [];
		var container = new THREE.Object3D();

		var faces = mesh.geometry.faces;
		var verts = mesh.geometry.vertices;

		for(var i=0;i<faces.length;i++){
			var f = faces[i];
			var v1 = verts[f.a];
			var v2 = verts[f.b];
			var v3 = verts[f.c];

			triangleArray.push([v1,v2,v3]);
		}

		var vectorArray = [];
		var geometry = new THREE.Geometry();

		for(var i=0;i<triangleArray.length;i++){
			var p1 = triangleArray[i][0];
			var p2 = triangleArray[i][1];
			var p3 = triangleArray[i][2];

			var pToArr = function(p){
				return [p.x,p.y,p.z];
			}

			var points = this.CalculateIntersectionPoints(pToArr(p1),pToArr(p2),pToArr(p3),axis,axisValue);
			if(points.length == 0) continue; // This happens if there's no intersection
			// Intersect the points and get two points
			var Z = Math.random() * 0.01;
			var v1 = new THREE.Vector3(points[0],points[1],Z);
			var v2 = new THREE.Vector3(points[2],points[3],Z);
			// Draw a line between those two points
			if(outlineOnly){

				geometry.vertices.push( v1 );
				geometry.vertices.push( v2 );

			} else {
				vectorArray.push(v1);
				vectorArray.push(v2);
			}

		}

		if(outlineOnly){
			var material = new MeshLineMaterial({color:new THREE.Color(color),lineWidth:0.1});
			var mesh = new THREE.LineSegments(geometry,material);
			return mesh;
		} else {
			var geometry = new THREE.ConvexGeometry( vectorArray );
			var material = new THREE.MeshBasicMaterial( {color: color} );
			var mesh = new THREE.Mesh( geometry, material );
			return mesh;
		}

	}

	Slicing.prototype.CalculateIntersectionPoints = function(p1,p2,p3,axis,axis_value) {
		/*
		Given a triangle (as 3 points) and a line (an axis), return the two points of intersection
			Input:
				p1,p2,p3 = [Number,Number,Number] representing 3D points
				axis = "X" | "Y" | "Z"
				axis_value = Number
			Output:
				[x,y,x,y]
		*/
		var axis_conv = {'X':0, 'Y':1, 'Z':2}
		var chosen_axis = 1;
		var other_axis_one = 0;
		var other_axis_two = 2;
		if(axis == "X"){
			chosen_axis = 0;
			other_axis_one = 2;
			other_axis_two = 1;
		}
		if(axis == "Z"){
			chosen_axis = 2;
			other_axis_one = 1;
			other_axis_two = 0;
		}

		//if (axis == 'Y') { // currently only handles Y axis. Needs to be generalized to X and Y

		var intersection_point = [];

		var above = [];
		var below = [];
		if (p1[axis_conv[axis]] > axis_value) above.push(p1);
		else below.push(p1);

		if (p2[axis_conv[axis]] > axis_value) above.push(p2);
		else below.push(p2);

		if (p3[axis_conv[axis]] > axis_value) above.push(p3);
		else below.push(p3);

		// If completely above or completely below, then no intersection
		if(below.length == 3 || above.length == 3) return [];

		if (below.length > 1) {

		  var direction = [3];
		  direction[0] = below[0][axis_conv['X']] - above[0][axis_conv['X']];
		  direction[1] = below[0][axis_conv['Y']] - above[0][axis_conv['Y']];
		  direction[2] = below[0][axis_conv['Z']] - above[0][axis_conv['Z']];

		  var t = (below[0][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[0] = below[0][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[1] = axis_value;
		  intersection_point[1] = below[0][other_axis_two] + t * direction[other_axis_two];

		  direction[0] = below[1][axis_conv['X']] - above[0][axis_conv['X']];
		  direction[1] = below[1][axis_conv['Y']] - above[0][axis_conv['Y']];
		  direction[2] = below[1][axis_conv['Z']] - above[0][axis_conv['Z']];

		  t = (below[1][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[2] = below[1][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[4] = axis_value;
		  intersection_point[3] = below[1][other_axis_two] + t * direction[other_axis_two];

		  return intersection_point;
		}
		else {
		  var direction = [3];
		  direction[0] = above[0][axis_conv['X']] - below[0][axis_conv['X']];
		  direction[1] = above[0][axis_conv['Y']] - below[0][axis_conv['Y']];
		  direction[2] = above[0][axis_conv['Z']] - below[0][axis_conv['Z']];

		  var t = (above[0][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[0] = above[0][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[1] = axis_value;
		  intersection_point[1] = above[0][other_axis_two] + t * direction[other_axis_two];

		  direction[0] = above[1][axis_conv['X']] - below[0][axis_conv['X']];
		  direction[1] = above[1][axis_conv['Y']] - below[0][axis_conv['Y']];
		  direction[2] = above[1][axis_conv['Z']] - below[0][axis_conv['Z']];

		  var t = (above[1][chosen_axis] - axis_value)/(direction[chosen_axis]*-1);

		  intersection_point[2] = above[1][other_axis_one] + t * direction[other_axis_one];
		  //intersection_point[4] = axis_value;
		  intersection_point[3] = above[1][other_axis_two] + t * direction[other_axis_two];

		  return intersection_point;
		}
	}
	scope.Slicing = Slicing;
	return Slicing;
})(typeof exports === 'undefined' ? {} : exports);<|endoftext|>


<commit_before>// *************************************************************************
// Copyright (c) 2014, SUSE LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of SUSE LLC nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// *************************************************************************
//
// html.js - functions that generate HTML source code
//
"use strict";

define ([
    'cf',
    'current-user',
    'lib',
    'app/lib',
    'target'
], function (
    cf,
    currentUser,
    lib,
    appLib,
    target
) {
    var
        //
        // "Your choice" section at the bottom - shared by all target types
        //
        yourChoice = function () {
            return '
Your choice: <input name="sel" size=3 maxlength=2> ' +
                   '<input id="submitButton" type="submit" value="Submit">

'
        },
        //
        // miniMenu is shared by dform and dbrowser
        //
        miniMenu = function (mm) {
            // mm is the dbrowser miniMenu object
            var len = mm.entries.length,
                entry,
                i,
                r;
            console.log("miniMenu is ", mm);
            console.log("miniMenu length is " + len);
            if (len > 0) {
                r = 'Menu:        ';
                for (i = 0; i < len; i += 1) {
                    //console.log("i === " + i);
                    console.log("Attempting to pull target " + mm.entries[i] + " from miniMenu");
                    entry = target.pull(mm.entries[i]);
                    if (lib.privCheck(entry.aclProfile)) {
                        r += i + '. ' + entry.menuText + '  ';
                    }
                }
                r += 'X. ' + mm.back[0];
            } else {
                r = mm.back[0];
            }
            return r;
        },
        browserNavMenu = function (len, pos) {
            var r = '',
                context = {
                    forward: 0,
                    back: 0,
                    jumpToEnd: 0,
                    jumpToBegin: 0
                };
	    // context-sensitive navigation menu: selections are based on
	    // set length and cursor position:
            //   if set.length <= 1: no navigation menu at all
            //   if 1 < set.length <= 5: forward, back
            //   if set.length > 5: forward, back, jump to end/beginning
            //   if pos == 1 then back and jump to beginning are deactivated
            //   if pos == set.length then forward and jump to end are deactivated
            // here in html.js, we add  elements for each context-sensitive
            // selection. Each such element has a unique identifier, so that in
            // start.js we can check for the presence of each and handle accordingly
            if (len > 1) {
                //
                // there is at least one record to display:
                // (a) determine context
                //
                if (len > 1) {
                    context.forward = 1;
                    context.back = 1;
                }
                if (len > 5) {
                    context.jumpToEnd = 1;
                    context.jumpToBegin = 1;
                }
                if (pos === 0) {
                    context.back = 0;
                    context.jumpToBegin = 0;
                }
                if (pos === len - 1) {
                    context.forward = 0;
                    context.jumpToEnd = 0;
                }
                //
                // (b) construct navigation menu
                //
                r += 'Navigation:  ';
                if (context.back) {
                    r += '[\u2190] Previous ';
                }
                if (context.forward) {
                    r += '[\u2192] Next ';
                }
                if (context.jumpToBegin) {
                    r += '[\u2303\u2190] Jump to first ';
                }
                if (context.jumpToEnd) {
                    r += '[\u2303\u2192] Jump to last ';
                }
                r += '
';
            } else {
                r = '';
            }
            return r;
        };

    return {
        demoActionFromMenu: function () {
            return '

SAMPLE ACTION - SOMETHING IS HAPPENING

';
        },
        demoActionFromSubmenu: function () {
            return '

SAMPLE ACTION - foo bar actioning bazness

';
        },
        loginDialog: function () {
            var r = '';
            r += '<form id="loginform">';
            r += '

';
            r += cf('loginDialogChallengeText');
            r += '

';
            r += 'Username: <input name="nam" size="' + cf('loginDialogMaxLengthUsername') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthUsername') + '" />
';
            r += 'Password: <input name="pwd" type="password" size="' + cf('loginDialogMaxLengthPassword') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthPassword') + '" />

';
            r += '          ';
            r += '<input type="submit" value="Submit">

';
            r += '</form>';
            return r;
        },
        logout: function () {
            var r = '';
            r += '

';
            r += 'You have been logged out of our humble application

';
            r += 'Have a lot of fun!

';
            return r;
        },
        body: function () {
            var r = '';
            r += '
';

            r += '
';
            r += cf('appName');
            r += ' ';
            r += cf('appVersion');
            r += '';
            r += '
';

            r += '
';
            r += appLib.fillUserBox();
            r += '
';

            r += '
';

            r += '
';
            r += '   If application appears';
            r += '   unresponsive, make sure browser window is active and press \'TAB\'';
            r += '
';

            r += '

';

            r += '

';

            r += '
';
            // r += appLib.fillNoticesLine();
            r += '
';
            return r;
        },
        //
        // dmenu target
        //
        dmenu: function (dmn) {
            console.log("Entering html.dmenu with argument " + dmn);
            // dmn is dmenu name
            // dmo is dmenu object
            var dmo = target.pull(dmn),
                r = '',
                len = dmo.entries.length,
                i,
                back = target.pull(dmo.back),
                entry;

            r += '<form id="' + dmn + '">
' + dmo.title + '

';

            for (i = 0; i < len; i += 1) {
                // the entries are names of targets
                console.log("Attempting to pull target " + dmo.entries[i]);
                entry = target.pull(dmo.entries[i]);
                if (lib.privCheck(entry.aclProfile)) {
                    r += i + '. ' + entry.menuText + '
';
                }
            }
            r += 'X. ' + back.menuText + '
';

            r += yourChoice();

            r += '</form>';
            return r;
        },
        //
        // dform target
        //
        dform: function (dfn) {
            // dfn is dform name
            // dfo is dform object
            var dfo = target.pull(dfn);
            return function (obj) {

                console.log("Generating source code of dform " + dfn);
                var r = '<form id="' + dfo.name + '">',
                    len,
                    i,
                    entry;

                r += '
' + dfo.title + '

';

                if (dfo.preamble) {
                    r += dfo.preamble + '

';
                }

                // READ-ONLY entries first
                len = dfo.entriesRead ? dfo.entriesRead.length : 0;
                if (len > 0) {
                    for (i = 0; i < len; i += 1) {
                        entry = dfo.entriesRead[i];
                        if (lib.privCheck(entry.aclProfileRead)) {
                            r += lib.rightPadSpaces(entry.text.concat(':'), 13);
                            r += '' + (obj[entry.prop] || '') + '
';
                        }
                    }
                    r += '
';
                }

                // READ-WRITE entries second
                len = dfo.entriesWrite ? dfo.entriesWrite.length : 0;
                if (len > 0) {
                    for (i = 0; i < len; i += 1) {
                        entry = dfo.entriesWrite[i];
                        if (lib.privCheck(entry.aclProfileWrite)) {
                            r += lib.rightPadSpaces(entry.text.concat(':'), 13);
                            r += '<input id="' + entry.name + '" ';
                            r += 'name="entry' + i + '" ';
                            r += 'value="' + (obj[entry.prop] || '') + '" ';
                            r += 'size="' + entry.maxlen + '" ';
                            r += 'maxlength="' + entry.maxlen + '">
';
                        }
                    }
                    r += '
';
                }

                // miniMenu at the bottom
                r += miniMenu(dfo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                //console.log("Assembled source code for " + dfn + " - it has " + r.length + " characters");
                return r;
            };
        },
        dbrowser: function (dbn) {
            // dfn is dform name
            // dfo is dform object
            var dbo = target.pull(dbn);
            return function (set, pos) {

                //console.log("Generating source code of dbrowser " + dbn);
                var r = '<form id="' + dbo.name + '">',
                    len,
                    i,
                    obj,
                    entry;

                r += '
' + dbo.title + '

';

                if (dbo.preamble) {
                    r += dbo.preamble + '

';
                }

                // display entries
                len = dbo.entries ? dbo.entries.length : 0;
                obj = set[pos];
                console.log('Browsing object', obj);
                if (len > 0) {
                    for (i = 0; i < len; i += 1) {
                        entry = dbo.entries[i];
                        if (lib.privCheck(entry.aclProfile)) {
                            r += lib.rightPadSpaces(entry.text.concat(':'), 13);
                            r += '' + (obj[entry.prop] || '') + '
';
                        }
                    }
                    r += '
';
                }

		// context-sensitive navigation menu: selections are based on
		// set length and cursor position
                r += browserNavMenu(set.length, pos);

		// miniMenu at the bottom: selections are target names defined
		// in the 'miniMenu' property of the dform object
                r += miniMenu(dbo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                console.log("Assembled source code for " + dbn + " - it has " + r.length + " characters");
                return r;
            };
        },
        //
        // dnotice target
        //
        dnotice: function (dnn) {
            console.log("Entering html.dnotice with argument " + dnn);
            // dnn is dnotice name
            // dno is dnotice object
            var dno = target.pull(dnn);
            return function () {
                var r = '';
                r += '

' + dno.title + '

';
                r += dno.preamble + '
';
                r += '

';
                r += "To leave this page, press ENTER or click the Submit button";
                r += yourChoice();
                r += '
';
                return r;
            };
        }
    };
});
<commit_msg>dform: calculate length of form entry text<commit_after>// *************************************************************************
// Copyright (c) 2014, SUSE LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of SUSE LLC nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// *************************************************************************
//
// html.js - functions that generate HTML source code
//
"use strict";

define ([
    'cf',
    'current-user',
    'lib',
    'app/lib',
    'target'
], function (
    cf,
    currentUser,
    lib,
    appLib,
    target
) {
    var
        //
        // "Your choice" section at the bottom - shared by all target types
        //
        yourChoice = function () {
            return '
Your choice: <input name="sel" size=3 maxlength=2> ' +
                   '<input id="submitButton" type="submit" value="Submit">

'
        },
        //
        // miniMenu is shared by dform and dbrowser
        //
        miniMenu = function (mm) {
            // mm is the dbrowser miniMenu object
            var len = mm.entries.length,
                entry,
                i,
                r;
            console.log("miniMenu is ", mm);
            console.log("miniMenu length is " + len);
            if (len > 0) {
                r = 'Menu:        ';
                for (i = 0; i < len; i += 1) {
                    //console.log("i === " + i);
                    console.log("Attempting to pull target " + mm.entries[i] + " from miniMenu");
                    entry = target.pull(mm.entries[i]);
                    if (lib.privCheck(entry.aclProfile)) {
                        r += i + '. ' + entry.menuText + '  ';
                    }
                }
                r += 'X. ' + mm.back[0];
            } else {
                r = mm.back[0];
            }
            return r;
        },
        browserNavMenu = function (len, pos) {
            var r = '',
                context = {
                    forward: 0,
                    back: 0,
                    jumpToEnd: 0,
                    jumpToBegin: 0
                };
	    // context-sensitive navigation menu: selections are based on
	    // set length and cursor position:
            //   if set.length <= 1: no navigation menu at all
            //   if 1 < set.length <= 5: forward, back
            //   if set.length > 5: forward, back, jump to end/beginning
            //   if pos == 1 then back and jump to beginning are deactivated
            //   if pos == set.length then forward and jump to end are deactivated
            // here in html.js, we add  elements for each context-sensitive
            // selection. Each such element has a unique identifier, so that in
            // start.js we can check for the presence of each and handle accordingly
            if (len > 1) {
                //
                // there is at least one record to display:
                // (a) determine context
                //
                if (len > 1) {
                    context.forward = 1;
                    context.back = 1;
                }
                if (len > 5) {
                    context.jumpToEnd = 1;
                    context.jumpToBegin = 1;
                }
                if (pos === 0) {
                    context.back = 0;
                    context.jumpToBegin = 0;
                }
                if (pos === len - 1) {
                    context.forward = 0;
                    context.jumpToEnd = 0;
                }
                //
                // (b) construct navigation menu
                //
                r += 'Navigation:  ';
                if (context.back) {
                    r += '[\u2190] Previous ';
                }
                if (context.forward) {
                    r += '[\u2192] Next ';
                }
                if (context.jumpToBegin) {
                    r += '[\u2303\u2190] Jump to first ';
                }
                if (context.jumpToEnd) {
                    r += '[\u2303\u2192] Jump to last ';
                }
                r += '
';
            } else {
                r = '';
            }
            return r;
        };

    return {
        demoActionFromMenu: function () {
            return '

SAMPLE ACTION - SOMETHING IS HAPPENING

';
        },
        demoActionFromSubmenu: function () {
            return '

SAMPLE ACTION - foo bar actioning bazness

';
        },
        loginDialog: function () {
            var r = '';
            r += '<form id="loginform">';
            r += '

';
            r += cf('loginDialogChallengeText');
            r += '

';
            r += 'Username: <input name="nam" size="' + cf('loginDialogMaxLengthUsername') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthUsername') + '" />
';
            r += 'Password: <input name="pwd" type="password" size="' + cf('loginDialogMaxLengthPassword') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthPassword') + '" />

';
            r += '          ';
            r += '<input type="submit" value="Submit">

';
            r += '</form>';
            return r;
        },
        logout: function () {
            var r = '';
            r += '

';
            r += 'You have been logged out of our humble application

';
            r += 'Have a lot of fun!

';
            return r;
        },
        body: function () {
            var r = '';
            r += '
';

            r += '
';
            r += cf('appName');
            r += ' ';
            r += cf('appVersion');
            r += '';
            r += '
';

            r += '
';
            r += appLib.fillUserBox();
            r += '
';

            r += '
';

            r += '
';
            r += '   If application appears';
            r += '   unresponsive, make sure browser window is active and press \'TAB\'';
            r += '
';

            r += '

';

            r += '

';

            r += '
';
            // r += appLib.fillNoticesLine();
            r += '
';
            return r;
        },
        //
        // dmenu target
        //
        dmenu: function (dmn) {
            console.log("Entering html.dmenu with argument " + dmn);
            // dmn is dmenu name
            // dmo is dmenu object
            var dmo = target.pull(dmn),
                r = '',
                len = dmo.entries.length,
                i,
                back = target.pull(dmo.back),
                entry;

            r += '<form id="' + dmn + '">
' + dmo.title + '

';

            for (i = 0; i < len; i += 1) {
                // the entries are names of targets
                console.log("Attempting to pull target " + dmo.entries[i]);
                entry = target.pull(dmo.entries[i]);
                if (lib.privCheck(entry.aclProfile)) {
                    r += i + '. ' + entry.menuText + '
';
                }
            }
            r += 'X. ' + back.menuText + '
';

            r += yourChoice();

            r += '</form>';
            return r;
        },
        //
        // dform target
        //
        dform: function (dfn) {
            // dfn is dform name
            // dfo is dform object
            var dfo = target.pull(dfn);
            return function (obj) {

                console.log("Generating source code of dform " + dfn);
                var r = '<form id="' + dfo.name + '">',
                    len,
                    i,
                    allEntries,
                    longest,
                    entry;

                r += '
' + dfo.title + '

';

                if (dfo.preamble) {
                    r += dfo.preamble + '

';
                }

                // determine longest entry
                allEntries = dfo.entriesRead.concat(dfo.entriesWrite);
                len = allEntries ? allEntries.length : 0;
                console.log("allEntries has " + len + " members");
                longest = allEntries[0].name.length;
                for (i = 1; i < len; i += 1) {
                    if (allEntries[i].text.length > longest) {
                        longest = allEntries[i].text.length;
                    }
                }
                longest += 2; // ': '
                console.log("The longest entry needs " + longest + " characters total");

                // READ-ONLY entries first
                len = dfo.entriesRead ? dfo.entriesRead.length : 0;
                for (i = 0; i < len; i += 1) {
                    entry = dfo.entriesRead[i];
                    if (lib.privCheck(entry.aclProfileRead)) {
                        r += lib.rightPadSpaces(entry.text.concat(':'), longest);
                        r += '' + (obj[entry.prop] || '') + '
';
                    }
                }
                r += '
';

                // READ-WRITE entries second
                len = dfo.entriesWrite ? dfo.entriesWrite.length : 0;
                for (i = 0; i < len; i += 1) {
                    entry = dfo.entriesWrite[i];
                    if (lib.privCheck(entry.aclProfileWrite)) {
                        r += lib.rightPadSpaces(entry.text.concat(':'), longest);
                        r += '<input id="' + entry.name + '" ';
                        r += 'name="entry' + i + '" ';
                        r += 'value="' + (obj[entry.prop] || '') + '" ';
                        r += 'size="' + entry.maxlen + '" ';
                        r += 'maxlength="' + entry.maxlen + '">
';
                    }
                }
                r += '
';

                // miniMenu at the bottom
                r += miniMenu(dfo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                //console.log("Assembled source code for " + dfn + " - it has " + r.length + " characters");
                return r;
            };
        },
        dbrowser: function (dbn) {
            // dfn is dform name
            // dfo is dform object
            var dbo = target.pull(dbn);
            return function (set, pos) {

                //console.log("Generating source code of dbrowser " + dbn);
                var r = '<form id="' + dbo.name + '">',
                    len,
                    i,
                    obj,
                    entry;

                r += '
' + dbo.title + '

';

                if (dbo.preamble) {
                    r += dbo.preamble + '

';
                }

                // display entries
                len = dbo.entries ? dbo.entries.length : 0;
                obj = set[pos];
                console.log('Browsing object', obj);
                if (len > 0) {
                    for (i = 0; i < len; i += 1) {
                        entry = dbo.entries[i];
                        if (lib.privCheck(entry.aclProfile)) {
                            r += lib.rightPadSpaces(entry.text.concat(':'), 13);
                            r += '' + (obj[entry.prop] || '') + '
';
                        }
                    }
                    r += '
';
                }

		// context-sensitive navigation menu: selections are based on
		// set length and cursor position
                r += browserNavMenu(set.length, pos);

		// miniMenu at the bottom: selections are target names defined
		// in the 'miniMenu' property of the dform object
                r += miniMenu(dbo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                console.log("Assembled source code for " + dbn + " - it has " + r.length + " characters");
                return r;
            };
        },
        //
        // dnotice target
        //
        dnotice: function (dnn) {
            console.log("Entering html.dnotice with argument " + dnn);
            // dnn is dnotice name
            // dno is dnotice object
            var dno = target.pull(dnn);
            return function () {
                var r = '';
                r += '

' + dno.title + '

';
                r += dno.preamble + '
';
                r += '

';
                r += "To leave this page, press ENTER or click the Submit button";
                r += yourChoice();
                r += '
';
                return r;
            };
        }
    };
});
<|endoftext|>


<commit_before>/**
 * The ParseContent Utility - Parse the content of a Node so that all of the
 * javascript contained in that Node will be executed according to the order
 * that it appears.
 *
 * @module aui-parse-content
 */

/*
* NOTE: The inspiration of ParseContent cames from the "Caridy Patino" Node Dispatcher Plugin
* 		http://github.com/caridy/yui3-gallery/blob/master/src/gallery-dispatcher/
*/

var L = A.Lang,
	isString = L.isString,

	DOC = A.config.doc,

	APPEND = 'append',
	DOCUMENT_ELEMENT = 'documentElement',
	FIRST_CHILD = 'firstChild',
	HEAD = 'head',
	HOST = 'host',
	INNER_HTML = 'innerHTML',
	PADDING_NODE = '
_
',
	PARSE_CONTENT = 'ParseContent',
	QUEUE = 'queue',
	SCRIPT = 'script',
	SEMICOLON = ';',
	SRC = 'src',

	SCRIPT_TYPES = {
		'': 1,
		'text/javascript': 1
	};

/**
 * A base class for ParseContent, providing:
 *

 *
After plug ParseContent on a A.Node instance the javascript chunks will be executed (remote and inline scripts)

 *
All the javascripts within a content will be executed according to the order of apparition

 *

 *
 *
NOTE: For performance reasons on DOM manipulation,
 * ParseContent only parses the content passed to the
 * setContent,
 * prepend and
 * append methods.

 *
 * Quick Example:

 *
 *
node.plug(A.Plugin.ParseContent);

 *
 * Check the list of Configuration Attributes available for
 * ParseContent.
 *
 * @param config {Object} Object literal specifying widget configuration properties.
 *
 * @class ParseContent
 * @constructor
 * @extends Plugin.Base
 */
var ParseContent = A.Component.create(
	{
		/**
		 * Static property provides a string to identify the class.
		 *
		 * @property ParseContent.NAME
		 * @type String
		 * @static
		 */
		NAME: PARSE_CONTENT,

		/**
		 * Static property provides a string to identify the namespace.
		 *
		 * @property ParseContent.NS
		 * @type String
		 * @static
		 */
		NS: PARSE_CONTENT,

		/**
		 * Static property used to define the default attribute
		 * configuration for the ParseContent.
		 *
		 * @property ParseContent.ATTRS
		 * @type Object
		 * @static
		 */
		ATTRS: {
			queue: {
				value: null
			}
		},

		EXTENDS: A.Plugin.Base,

		prototype: {
			/**
			 * Construction logic executed during ParseContent instantiation. Lifecycle.
			 *
			 * @method initializer
			 * @protected
			 */
			initializer: function() {
				var instance = this;

				ParseContent.superclass.initializer.apply(this, arguments);

				instance.set(
					QUEUE,
					new A.AsyncQueue()
				);

				instance._bindAOP();
			},

			/**
			 * Global eval the <data>data</data> passed.
			 *
			 * @method globalEval
			 * @param {String} data JavaScript String.
			 */
			globalEval: function(data) {
				var doc = A.getDoc();
				var head = doc.one(HEAD) || doc.get(DOCUMENT_ELEMENT);

				// NOTE: A.Node.create('') doesn't work correctly on Opera
				var newScript = DOC.createElement(SCRIPT);

				newScript.type = 'text/javascript';

				if (data) {
					// NOTE: newScript.set(TEXT, data) breaks on IE, YUI BUG.
					newScript.text = L.trim(data);
				}

				head.appendChild(newScript).remove(); //removes the script node immediately after executing it
			},

			/**
			 * Extract the script tags from the string content and
			 * evaluate the chunks.
			 *
			 * @method parseContent
			 * @param {String} content HTML string
			 * @return {String}
			 */
			parseContent: function(content) {
				var instance = this;

				var output = instance._clean(content);

				instance._dispatch(output);

				return output;
			},

			/**
			 * Add inline script data to the queue.
			 *
			 * @method _addInlineScript
			 * @param {String} data The script content which should be added to the queue
			 * @protected
			 */
			_addInlineScript: function(data) {
				var instance = this;

				instance.get(QUEUE).add(
					{
						args: data,
						context: instance,
						fn: instance.globalEval,
						timeout: 0
					}
				);
			},

			/**
			 * Bind listeners on the insert and setContent
		     * methods of the Node instance where you are plugging the ParseContent.
		     * These listeners are responsible for intercept the HTML passed and parse
		     * them.
			 *
			 * @method _bindAOP
			 * @protected
			 */
			_bindAOP: function() {
				var instance = this;

				var cleanFirstArg = function(content) {
					var args = Array.prototype.slice.call(arguments);
					var output = instance.parseContent(content);

					// replace the first argument with the clean fragment
					args.splice(0, 1, output.fragment);

					return new A.Do.AlterArgs(null, args);
				};

				this.doBefore('insert', cleanFirstArg);
				this.doBefore('replaceChild', cleanFirstArg);

				var cleanArgs = function(content) {
					var output = instance.parseContent(content);

					return new A.Do.AlterArgs(null, [output.fragment]);
				};

				this.doBefore('replace', cleanArgs);
				this.doBefore('setContent', cleanArgs);
			},

			/**
			 * Create an HTML fragment with the String passed, extract all the script
		     * tags and return an Object with a reference for the extracted scripts and
		     * the fragment.
			 *
			 * @method clean
			 * @param {String} content HTML content.
			 * @protected
			 * @return {Object}
			 */
			_clean: function(content) {
				var output = {};

				var fragment = A.Node.create('

');

				// For PADDING_NODE, instead of fixing all tags in the content to be "XHTML"-style,
				// we make the firstChild be a valid non-empty tag, then we remove it later

				if (isString(content)) {
					content = PADDING_NODE + content;

					// create fragment from {String}
					A.DOM.addHTML(fragment, content, APPEND);
				}
				else {
					fragment.append(PADDING_NODE);

					// create fragment from {Y.Node | HTMLElement}
					fragment.append(content);
				}

				output.js = fragment.all(SCRIPT).filter(function(script) {
					return SCRIPT_TYPES[script.getAttribute('type').toLowerCase()];
				});

				output.js.each(
					function(node, i) {
						node.remove();
					}
				);

				// remove PADDING_NODE
				fragment.get(FIRST_CHILD).remove();

				output.fragment = fragment.get('childNodes').toFrag();

				return output;
			},

			/**
			 * Loop trough all extracted script tags and evaluate them.
			 *
			 * @method _dispatch
			 * @param {Object} output Object containing the reference for the fragment and the extracted script tags.
			 * @protected
			 * @return {String}
			 */
			_dispatch: function(output) {
				var instance = this;

				var queue = instance.get(QUEUE);

				var scriptContent = [];

				output.js.each(function(node, i) {
					var src = node.get(SRC);

					if (src) {
						if (scriptContent.length) {
							instance._addInlineScript(scriptContent.join(SEMICOLON));

							scriptContent.length = 0;
						}

						queue.add({
							autoContinue: false,
							fn: function () {
								A.Get.script(src, {
									onEnd: function (o) {
										o.purge(); //removes the script node immediately after executing it
										queue.run();
									}
								});
							},
							timeout: 0
						});
					}
					else {
						var dom = node._node;

						scriptContent.push(dom.text || dom.textContent || dom.innerHTML || '');
					}
				});

				if (scriptContent.length) {
					instance._addInlineScript(scriptContent.join(SEMICOLON));
				}

				queue.run();
			}
		}
	}
);

A.namespace('Plugin').ParseContent = ParseContent;<commit_msg>Review documentation for aui-parse-content<commit_after>/**
 * The ParseContent Utility - Parse the content of a Node so that all of the
 * javascript contained in that Node will be executed according to the order
 * that it appears.
 *
 * @module aui-parse-content
 */

/*
 * NOTE: The inspiration of ParseContent cames from the "Caridy Patino" Node Dispatcher Plugin
 * 		 http://github.com/caridy/yui3-gallery/blob/master/src/gallery-dispatcher/
 */

var L = A.Lang,
	isString = L.isString,

	DOC = A.config.doc,

	APPEND = 'append',
	DOCUMENT_ELEMENT = 'documentElement',
	FIRST_CHILD = 'firstChild',
	HEAD = 'head',
	HOST = 'host',
	INNER_HTML = 'innerHTML',
	PADDING_NODE = '
_
',
	PARSE_CONTENT = 'ParseContent',
	QUEUE = 'queue',
	SCRIPT = 'script',
	SEMICOLON = ';',
	SRC = 'src',

	SCRIPT_TYPES = {
		'': 1,
		'text/javascript': 1
	};

/**
 * A base class for ParseContent, providing:
 *

 *
After plug ParseContent on a A.Node instance the javascript chunks will be executed (remote and inline scripts)

 *
All the javascripts within a content will be executed according to the order of apparition

 *

 *
 *
NOTE: For performance reasons on DOM manipulation,
 * ParseContent only parses the content passed to the
 * setContent,
 * prepend and
 * append methods.

 *
 * Quick Example:

 *
 *
node.plug(A.Plugin.ParseContent);

 *
 * Check the list of Configuration Attributes available for
 * ParseContent.
 *
 * @class ParseContent
 * @extends Plugin.Base
 * @param config {Object} Object literal specifying widget configuration properties.
 * @constructor
 */
var ParseContent = A.Component.create(
	{
		/**
		 * Static property provides a string to identify the class.
		 *
		 * @property ParseContent.NAME
		 * @type String
		 * @static
		 */
		NAME: PARSE_CONTENT,

		/**
		 * Static property provides a string to identify the namespace.
		 *
		 * @property ParseContent.NS
		 * @type String
		 * @static
		 */
		NS: PARSE_CONTENT,

		/**
		 * Static property used to define the default attribute
		 * configuration for the ParseContent.
		 *
		 * @property ParseContent.ATTRS
		 * @type Object
		 * @static
		 */
		ATTRS: {

			/**
			 * A queue of elements to be parsed.
			 *
			 * @attribute queue
			 * @default null
			 */
			queue: {
				value: null
			}
		},

		/**
		 * Static property used to define which component it extends.
		 *
		 * @property ParseContent.EXTENDS
		 * @type Object
		 * @static
		 */
		EXTENDS: A.Plugin.Base,

		prototype: {

			/**
			 * Construction logic executed during ParseContent instantiation. Lifecycle.
			 *
			 * @method initializer
			 * @protected
			 */
			initializer: function() {
				var instance = this;

				ParseContent.superclass.initializer.apply(this, arguments);

				instance.set(
					QUEUE,
					new A.AsyncQueue()
				);

				instance._bindAOP();
			},

			/**
			 * Global eval the <data>data</data> passed.
			 *
			 * @method globalEval
			 * @param {String} data JavaScript String.
			 */
			globalEval: function(data) {
				var doc = A.getDoc();
				var head = doc.one(HEAD) || doc.get(DOCUMENT_ELEMENT);

				// NOTE: A.Node.create('') doesn't work correctly on Opera
				var newScript = DOC.createElement(SCRIPT);

				newScript.type = 'text/javascript';

				if (data) {
					// NOTE: newScript.set(TEXT, data) breaks on IE, YUI BUG.
					newScript.text = L.trim(data);
				}

				head.appendChild(newScript).remove(); //removes the script node immediately after executing it
			},

			/**
			 * Extract the script tags from the string content and
			 * evaluate the chunks.
			 *
			 * @method parseContent
			 * @param {String} content HTML string
			 * @return {String}
			 */
			parseContent: function(content) {
				var instance = this;

				var output = instance._clean(content);

				instance._dispatch(output);

				return output;
			},

			/**
			 * Add inline script data to the queue.
			 *
			 * @method _addInlineScript
			 * @param {String} data The script content which should be added to the queue
			 * @protected
			 */
			_addInlineScript: function(data) {
				var instance = this;

				instance.get(QUEUE).add(
					{
						args: data,
						context: instance,
						fn: instance.globalEval,
						timeout: 0
					}
				);
			},

			/**
			 * Bind listeners on the insert and setContent
			 * methods of the Node instance where you are plugging the ParseContent.
			 * These listeners are responsible for intercept the HTML passed and parse
			 * them.
			 *
			 * @method _bindAOP
			 * @protected
			 */
			_bindAOP: function() {
				var instance = this;

				var cleanFirstArg = function(content) {
					var args = Array.prototype.slice.call(arguments);
					var output = instance.parseContent(content);

					// replace the first argument with the clean fragment
					args.splice(0, 1, output.fragment);

					return new A.Do.AlterArgs(null, args);
				};

				this.doBefore('insert', cleanFirstArg);
				this.doBefore('replaceChild', cleanFirstArg);

				var cleanArgs = function(content) {
					var output = instance.parseContent(content);

					return new A.Do.AlterArgs(null, [output.fragment]);
				};

				this.doBefore('replace', cleanArgs);
				this.doBefore('setContent', cleanArgs);
			},

			/**
			 * Create an HTML fragment with the String passed, extract all the script
			 * tags and return an Object with a reference for the extracted scripts and
			 * the fragment.
			 *
			 * @method clean
			 * @param {String} content HTML content.
			 * @protected
			 * @return {Object}
			 */
			_clean: function(content) {
				var output = {};

				var fragment = A.Node.create('

');

				// For PADDING_NODE, instead of fixing all tags in the content to be "XHTML"-style,
				// we make the firstChild be a valid non-empty tag, then we remove it later

				if (isString(content)) {
					content = PADDING_NODE + content;

					// create fragment from {String}
					A.DOM.addHTML(fragment, content, APPEND);
				}
				else {
					fragment.append(PADDING_NODE);

					// create fragment from {Y.Node | HTMLElement}
					fragment.append(content);
				}

				output.js = fragment.all(SCRIPT).filter(function(script) {
					return SCRIPT_TYPES[script.getAttribute('type').toLowerCase()];
				});

				output.js.each(
					function(node, i) {
						node.remove();
					}
				);

				// remove PADDING_NODE
				fragment.get(FIRST_CHILD).remove();

				output.fragment = fragment.get('childNodes').toFrag();

				return output;
			},

			/**
			 * Loop trough all extracted script tags and evaluate them.
			 *
			 * @method _dispatch
			 * @param {Object} output Object containing the reference for the fragment and the extracted script tags.
			 * @protected
			 * @return {String}
			 */
			_dispatch: function(output) {
				var instance = this;

				var queue = instance.get(QUEUE);

				var scriptContent = [];

				output.js.each(function(node, i) {
					var src = node.get(SRC);

					if (src) {
						if (scriptContent.length) {
							instance._addInlineScript(scriptContent.join(SEMICOLON));

							scriptContent.length = 0;
						}

						queue.add({
							autoContinue: false,
							fn: function () {
								A.Get.script(src, {
									onEnd: function (o) {
										o.purge(); //removes the script node immediately after executing it
										queue.run();
									}
								});
							},
							timeout: 0
						});
					}
					else {
						var dom = node._node;

						scriptContent.push(dom.text || dom.textContent || dom.innerHTML || '');
					}
				});

				if (scriptContent.length) {
					instance._addInlineScript(scriptContent.join(SEMICOLON));
				}

				queue.run();
			}
		}
	}
);

A.namespace('Plugin').ParseContent = ParseContent;<|endoftext|>


<commit_before>({
    /**
     * @description: adds hidden and non-lightning:inputfield fields to the Data Import record before submitting.
     * @return: Object rowFields with hidden fields added
     */
    getRowWithHiddenFields: function (component, event) {
        var rowFields = event.getParam('fields');

        var recId = component.get('v.recordId');
        var batchField = component.get('v.labels.batchIdField');
        rowFields[batchField] = recId;

        // add donor type hidden fields
        var donorType = component.get('v.donorType');
        var donorField = component.get('v.labels.donationDonor');
        rowFields[donorField] = donorType;

        // add any picklist fields manually, because they use lightning:select
        var dynamicInputFields = component.find('dynamicInputFields');
        var dataImportFields = component.get('v.dataImportFields');

        //dataImportFields and dynamicInputFields have the same order, so can loop both to get the value
        for (var i=0; i<dataImportFields.length; i++) {
            if (dataImportFields[i].options && dataImportFields[i].options.length > 0) {
                var fieldValue = dynamicInputFields[i].get('v.value');
                var fieldName = dataImportFields[i].name;
                rowFields[fieldName] = fieldValue;
            }
        }

        return rowFields;
    },

    /**
     * @description: sends error toast to parent component notifying user of missing fields
     * @param missingFields: Array of missing fields
     */
    sendErrorToast: function(component, missingFields) {
        var channel = 'onError';
        var error = $A.get('$Label.c.exceptionRequiredField') + ' ' + missingFields.join(', ') + '.';
        var message = {title: $A.get('$Label.c.PageMessagesError'), errorMessage: error};
        this.sendMessage(channel, message);
    },

    /**
     * @description: generic component used to send a message to parent component.
     */
    sendMessage: function (channel, message) {
        var sendMessage = $A.get('e.ltng:sendMessage');
        sendMessage.setParams({
            'channel': channel,
            'message': message
        });
        sendMessage.fire();
    },

    /**
     * @description: checks for Donor and other required fields and gathers error messages before submitting
     * @return: validity Object with Boolean for validity and an array of any missing fields to display
     */
    validateFields: function(component, rowFields) {
        var validity = {isValid: true, missingFields: []};

        var hasDonor = this.verifyRowHasDonor(component, rowFields);
        if (!hasDonor) {
            var labels = component.get("v.labels");
            var missingDonor = (component.get("v.donorType") === 'Contact1') ? labels.contactObject : labels.accountObject;
            validity.missingFields.push(missingDonor);
        }

        var missingRequiredFields = this.verifyRequiredFields(component, rowFields);
        if (missingRequiredFields.length != 0) {
            validity.missingFields = validity.missingFields.concat(missingRequiredFields);
        }

        if (validity.missingFields.length !== 0) {
            validity.isValid = false;
        }

        return validity;
    },

    /**
     * @description: checks for presence of fields that user has marked as required
     * @param rowFields: Object rowFields with updated hidden values
     * @return missingFields: list of any fields by label that are missing
     */
    verifyRequiredFields: function(component, rowFields) {
        var missingFields = [];
        var dataImportFields = component.get("v.dataImportFields");
        var dynamicInputFields = component.find("dynamicInputFields");

        //dataImportFields and dynamicInputFields have the same order, so can loop both to check validity
        for (var i=0; i<dataImportFields.length; i++) {
            if (dataImportFields[i].required) {
                var fieldValue = dynamicInputFields[i].get("v.value");
                if (fieldValue === '' || fieldValue === null) {
                    missingFields.push(dataImportFields[i].label);
                }
            }
        }

        return missingFields;
    },

    /**
     * @description: checks for presence of a donor, which is always required
     * @param rowFields: Object rowFields with updated hidden values
     * @return hasDonor: Boolean to indicate if row has a donor
     */
    verifyRowHasDonor: function(component, rowFields) {
        var hasDonor = true;
        var lookupValue;

        if (component.get("v.donorType") === 'Contact1') {
            lookupValue = rowFields[component.get("v.labels.contactLookup")];
        } else if (component.get("v.donorType") === 'Account1') {
            lookupValue = rowFields[component.get("v.labels.accountLookup")];
        }

        if (!lookupValue || lookupValue.length !== 18) {
            hasDonor = false;
        }

        return hasDonor;
    }

})<commit_msg>bug fix to allow batch/template with one field (#3791)<commit_after>({
    /**
     * @description: adds hidden and non-lightning:inputfield fields to the Data Import record before submitting.
     * @return: Object rowFields with hidden fields added
     */
    getRowWithHiddenFields: function (component, event) {
        var rowFields = event.getParam('fields');

        var recId = component.get('v.recordId');
        var batchField = component.get('v.labels.batchIdField');
        rowFields[batchField] = recId;

        // add donor type hidden fields
        var donorType = component.get('v.donorType');
        var donorField = component.get('v.labels.donationDonor');
        rowFields[donorField] = donorType;

        // add any picklist fields manually, because they use lightning:select
        var dynamicInputFields = component.find('dynamicInputFields');
        var dataImportFields = component.get('v.dataImportFields');

        //dataImportFields and dynamicInputFields have the same order, so can loop both to get the value
        for (var i=0; i<dataImportFields.length; i++) {
            if (dataImportFields[i].options && dataImportFields[i].options.length > 0) {
                var fieldValue = dynamicInputFields[i].get('v.value');
                var fieldName = dataImportFields[i].name;
                rowFields[fieldName] = fieldValue;
            }
        }

        return rowFields;
    },

    /**
     * @description: sends error toast to parent component notifying user of missing fields
     * @param missingFields: Array of missing fields
     */
    sendErrorToast: function(component, missingFields) {
        var channel = 'onError';
        var error = $A.get('$Label.c.exceptionRequiredField') + ' ' + missingFields.join(', ') + '.';
        var message = {title: $A.get('$Label.c.PageMessagesError'), errorMessage: error};
        this.sendMessage(channel, message);
    },

    /**
     * @description: generic component used to send a message to parent component.
     */
    sendMessage: function (channel, message) {
        var sendMessage = $A.get('e.ltng:sendMessage');
        sendMessage.setParams({
            'channel': channel,
            'message': message
        });
        sendMessage.fire();
    },

    /**
     * @description: checks for Donor and other required fields and gathers error messages before submitting
     * @return: validity Object with Boolean for validity and an array of any missing fields to display
     */
    validateFields: function(component, rowFields) {
        var validity = {isValid: true, missingFields: []};

        var hasDonor = this.verifyRowHasDonor(component, rowFields);
        if (!hasDonor) {
            var labels = component.get("v.labels");
            var missingDonor = (component.get("v.donorType") === 'Contact1') ? labels.contactObject : labels.accountObject;
            validity.missingFields.push(missingDonor);
        }

        var missingRequiredFields = this.verifyRequiredFields(component, rowFields);
        if (missingRequiredFields.length != 0) {
            validity.missingFields = validity.missingFields.concat(missingRequiredFields);
        }

        if (validity.missingFields.length !== 0) {
            validity.isValid = false;
        }

        return validity;
    },

    /**
     * @description: checks for presence of fields that user has marked as required
     * @param rowFields: Object rowFields with updated hidden values
     * @return missingFields: list of any fields by label that are missing
     */
    verifyRequiredFields: function(component, rowFields) {
        var missingFields = [];
        var dataImportFields = component.get('v.dataImportFields');
        var dynamicInputFields = component.find('dynamicInputFields');

        if (! Array.isArray(dynamicInputFields)) {
            dynamicInputFields = [dynamicInputFields];
        }

        //dataImportFields and dynamicInputFields have the same order, so can loop both to check validity
        for (var i=0; i<dataImportFields.length; i++) {
            if (dataImportFields[i].required) {
                var fieldValue = dynamicInputFields[i].get('v.value');
                if (fieldValue === '' || fieldValue === null) {
                    missingFields.push(dataImportFields[i].label);
                }
            }
        }

        return missingFields;
    },

    /**
     * @description: checks for presence of a donor, which is always required
     * @param rowFields: Object rowFields with updated hidden values
     * @return hasDonor: Boolean to indicate if row has a donor
     */
    verifyRowHasDonor: function(component, rowFields) {
        var hasDonor = true;
        var lookupValue;

        if (component.get("v.donorType") === 'Contact1') {
            lookupValue = rowFields[component.get("v.labels.contactLookup")];
        } else if (component.get("v.donorType") === 'Account1') {
            lookupValue = rowFields[component.get("v.labels.accountLookup")];
        }

        if (!lookupValue || lookupValue.length !== 18) {
            hasDonor = false;
        }

        return hasDonor;
    }

})<|endoftext|>