<commit_before>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import { padding, pointSize, debounceDelay } from './utils';
import CSSClassnames from '../../utils/CSSClassnames';
import Intl from '../../utils/Intl';

const CLASS_ROOT = CSSClassnames.CHART_GRAPH;
const COLOR_INDEX = CSSClassnames.COLOR_INDEX;

export default class Graph extends Component {

  constructor(props, context) {
    super(props, context);
    this._onResize = this._onResize.bind(this);
    this._layout = this._layout.bind(this);
    this._renderA11YTitle = this._renderA11YTitle.bind(this);
    this.state = { height: props.height || 1, width: props.width || 1 };
  }

  componentDidMount () {
    window.addEventListener('resize', this._onResize);
    this._onResize();
  }

  componentWillUnmount () {
    clearTimeout(this._resizeTimer);
    window.removeEventListener('resize', this._onResize);
  }

  _onResize () {
    // debounce
    clearTimeout(this._resizeTimer);
    // delay should be greater than Chart's delay
    this._resizeTimer = setTimeout(this._layout, debounceDelay + 10);
  }

  _layout () {
    const { height, width } = this.props;
    const graph = this.graphRef;
    const rect = graph.parentNode.getBoundingClientRect();
    this.setState({
      height: height || Math.floor(rect.height),
      width: width || Math.floor(rect.width)
    });
  }

  // Determines what the appropriate control coordinates are on
  // either side of the coordinate at the specified index.
  // This calculation is a simplified smoothing function that
  // just looks at whether the line through this coordinate is
  // ascending, descending or not. Peaks, valleys, and flats are
  // treated the same.
  _controlCoordinates (coordinates, index) {
    let current = coordinates[index];
    // Use previous and next coordinates when available, otherwise use
    // the current coordinate for them.
    let previous = current;
    if (index > 0) {
      previous = coordinates[index - 1];
    }
    let next = current;
    if (index < coordinates.length - 1) {
      next = coordinates[index + 1];
    }

    // Put the control X coordinates midway between the coordinates.
    let deltaX = (current[0] - previous[0]) / 2.4;
    let deltaY;

    // Start with a flat slope. This works for peaks, valleys, and flats.
    let first = [current[0] - deltaX, current[1]];
    let second = [current[0] + deltaX, current[1]];

    if (previous[1] < current[1] && current[1] < next[1]) {
      // Ascending, use the minimum positive slope.
      deltaY = Math.min(((current[1] - previous[1]) / 2),
        ((next[1] - current[1]) / 2));
      first[1] = current[1] - deltaY;
      second[1] = current[1] + deltaY;
    } else if (previous[1] > current[1] && current[1] > next[1]) {
      // Descending, use the minimum negative slope.
      deltaY = Math.min(((previous[1] - current[1]) / 2),
        ((current[1] - next[1]) / 2));
      first[1] = current[1] + deltaY;
      second[1] = current[1] - deltaY;
    }
    return [first, second];
  }

  _renderA11YTitle () {
    const { a11yTitle, max, min, type, values } = this.props;
    const { intl } = this.context;

    if (a11yTitle) {
      return a11yTitle;
    }

    const typeLabel = Intl.getMessage(intl, type);

    let minLabel = `, ${Intl.getMessage(intl, 'Min')}: ${min}`;

    let maxLabel = `, ${Intl.getMessage(intl, 'Max')}: ${max}`;

    const definedValues = values.filter((value) => value);
    const valueLabel = Intl.getMessage(intl, 'GraphValues', {
      count: values.length,
      highest: Math.max(...definedValues).toString(),
      smallest: Math.min(...definedValues).toString()
    });

    return `${typeLabel} ${minLabel} ${maxLabel}. ${valueLabel}`;
  }

  render () {
    const { activeIndex, colorIndex, max, min, reverse, smooth, type,
      values, vertical } = this.props;
    const { height, width } = this.state;
    const pad = Math.min(width, height) < (padding * 8) ? 2 : padding;

    let classes = [CLASS_ROOT, `${CLASS_ROOT}--${type}`];
    if (vertical) {
      classes.push(`${CLASS_ROOT}--vertical`);
    }
    classes.push(`${COLOR_INDEX}-${colorIndex || 'graph-1'}`);

    let scale, step;
    if (vertical) {
      if (values.length <= 1) {
        scale = 1;
        step = height - (2 * pad);
      } else {
        scale = (width - (2 * pad)) / (max - min);
        step = (height - (2 * pad)) / (values.length - 1);
      }
    } else {
      if (values.length <= 1) {
        scale = 1;
        step = width - (2 * pad);
      } else {
        scale = (height - (2 * pad)) / (max - min);
        step = (width - (2 * pad)) / (values.length - 1);
      }
    }

    // Get all coordinates up front so they are available
    // if we are drawing a smooth chart.
    let points = [];
    const coordinates = values.map((value, index) => {
      let coordinate;
      if (undefined !== value) {
        if (vertical) {
          coordinate = [
            ((value - min) * scale) + pad,
            (reverse ? (index * step) :
              (height - (2 * pad)) - (index * step)) + pad
          ];
        } else {
          coordinate = [
            (reverse ? (width - (2 * pad)) - (index * step) :
              index * step) + pad,
            ((height - (2 * pad)) - ((value - min) * scale)) + pad
          ];
        }

        if ((this.props.points || index === activeIndex) &&
          ! this.props.sparkline) {
          const classes = [`${CLASS_ROOT}__point`,
            `${COLOR_INDEX}-${colorIndex || 'graph-1'}`];
          let radius = pointSize / 3;
          if (index === activeIndex) {
            classes.push(`${CLASS_ROOT}__point--active`);
            radius = pointSize / 2;
          }
          points.push(
            <circle key={index} className={classes.join(' ')}
              cx={coordinate[0]} cy={coordinate[1]} r={radius} />
          );
        }
      }

      return coordinate;
    })
    .filter(coordinate => coordinate);

    let path;
    if (coordinates.length > 1) {
      let pathProps = {};
      let commands;

      // Build the commands for this set of coordinates.

      if ('area' === type || 'line' === type) {

        if (smooth) {
          const controlCoordinates = coordinates.map((coord, index) => (
            this._controlCoordinates(coordinates, index)
          ));
          commands = '';
          coordinates.forEach((coord, index) => {
            if (0 === index) {
              commands += `M${coord.join(',')}`;
            } else {
              // Use the previous right control coordinate and the current
              // left control coordinate. We do this because we calculate
              // the left and right sides for a particular index together,
              // so the path is smooth but the SVG C command needs the
              // right one from the previous index and the left one from
              // the current index.
              commands += ` C${controlCoordinates[index-1][1].join(',')}
                ${controlCoordinates[index][0].join(',')} ${coord.join(',')}`;
            }
          });
        } else {
          commands = `M${coordinates.map(c => c.join(',')).join(' L')}`;
        }

        if ('area' === type) {
          if (vertical) {
            if (reverse) {
              // Close the path by drawing to the left
              // and across to the top of where we started.
              commands +=
                `L${pad},${coordinates[coordinates.length - 1][1]}
                L${pad},${coordinates[0][1]} Z`;
            } else {
              // Close the path by drawing to the left
              // and across to the bottom of where we started.
              commands +=
                `L${pad},${coordinates[coordinates.length - 1][1]}
                L${pad},${height - pad} Z`;
            }
          } else {
            // Close the path by drawing down to the bottom
            // and across to the left of where we started.
            commands +=
              `L${coordinates[coordinates.length - 1][0]},${height - pad}
              L${coordinates[0][0]},${height - pad} Z`;
          }
          pathProps.stroke = 'none';
        } else {
          pathProps.fill = 'none';
        }
      } else if ('bar' === type) {
        commands = coordinates.map(c => (
          `M${c.join(',')}L${vertical ? `${pad},${c[1]}` :
            `${c[0]},${height - pad}`}`
        )).join(' ');
        pathProps.fill = 'none';
      }

      path = <path {...pathProps} d={commands} />;
    }

    return (
      <svg ref={ref => this.graphRef = ref} className={classes.join(' ')}
        viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none"
        role="img" aria-label={this._renderA11YTitle()}>
        <g>
          {path}
        </g>
        {points}
      </svg>
    );
  }

};

Graph.contextTypes = {
  intl: PropTypes.object
};

Graph.defaultProps = {
  min: 0,
  max: 100
};

Graph.propTypes = {
  a11yTitle: PropTypes.string,
  activeIndex: PropTypes.number,
  colorIndex: PropTypes.string,
  height: PropTypes.number, // only from Chart
  max: PropTypes.number.isRequired,
  min: PropTypes.number.isRequired,
  points: PropTypes.bool,
  reverse: PropTypes.bool,
  smooth: PropTypes.bool,
  values: PropTypes.arrayOf(PropTypes.number).isRequired,
  // type comes from extending the component
  type: PropTypes.oneOf(['area', 'line', 'bar']).isRequired,
  vertical: PropTypes.bool,
  width: PropTypes.number // only from Chart
};
<commit_msg>Prevent chart from setting scale to infinity if all values in array are the same<commit_after>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import { padding, pointSize, debounceDelay } from './utils';
import CSSClassnames from '../../utils/CSSClassnames';
import Intl from '../../utils/Intl';

const CLASS_ROOT = CSSClassnames.CHART_GRAPH;
const COLOR_INDEX = CSSClassnames.COLOR_INDEX;

export default class Graph extends Component {

  constructor(props, context) {
    super(props, context);
    this._onResize = this._onResize.bind(this);
    this._layout = this._layout.bind(this);
    this._renderA11YTitle = this._renderA11YTitle.bind(this);
    this.state = { height: props.height || 1, width: props.width || 1 };
  }

  componentDidMount () {
    window.addEventListener('resize', this._onResize);
    this._onResize();
  }

  componentWillUnmount () {
    clearTimeout(this._resizeTimer);
    window.removeEventListener('resize', this._onResize);
  }

  _onResize () {
    // debounce
    clearTimeout(this._resizeTimer);
    // delay should be greater than Chart's delay
    this._resizeTimer = setTimeout(this._layout, debounceDelay + 10);
  }

  _layout () {
    const { height, width } = this.props;
    const graph = this.graphRef;
    const rect = graph.parentNode.getBoundingClientRect();
    this.setState({
      height: height || Math.floor(rect.height),
      width: width || Math.floor(rect.width)
    });
  }

  // Determines what the appropriate control coordinates are on
  // either side of the coordinate at the specified index.
  // This calculation is a simplified smoothing function that
  // just looks at whether the line through this coordinate is
  // ascending, descending or not. Peaks, valleys, and flats are
  // treated the same.
  _controlCoordinates (coordinates, index) {
    let current = coordinates[index];
    // Use previous and next coordinates when available, otherwise use
    // the current coordinate for them.
    let previous = current;
    if (index > 0) {
      previous = coordinates[index - 1];
    }
    let next = current;
    if (index < coordinates.length - 1) {
      next = coordinates[index + 1];
    }

    // Put the control X coordinates midway between the coordinates.
    let deltaX = (current[0] - previous[0]) / 2.4;
    let deltaY;

    // Start with a flat slope. This works for peaks, valleys, and flats.
    let first = [current[0] - deltaX, current[1]];
    let second = [current[0] + deltaX, current[1]];

    if (previous[1] < current[1] && current[1] < next[1]) {
      // Ascending, use the minimum positive slope.
      deltaY = Math.min(((current[1] - previous[1]) / 2),
        ((next[1] - current[1]) / 2));
      first[1] = current[1] - deltaY;
      second[1] = current[1] + deltaY;
    } else if (previous[1] > current[1] && current[1] > next[1]) {
      // Descending, use the minimum negative slope.
      deltaY = Math.min(((previous[1] - current[1]) / 2),
        ((current[1] - next[1]) / 2));
      first[1] = current[1] + deltaY;
      second[1] = current[1] - deltaY;
    }
    return [first, second];
  }

  _renderA11YTitle () {
    const { a11yTitle, max, min, type, values } = this.props;
    const { intl } = this.context;

    if (a11yTitle) {
      return a11yTitle;
    }

    const typeLabel = Intl.getMessage(intl, type);

    let minLabel = `, ${Intl.getMessage(intl, 'Min')}: ${min}`;

    let maxLabel = `, ${Intl.getMessage(intl, 'Max')}: ${max}`;

    const definedValues = values.filter((value) => value);
    const valueLabel = Intl.getMessage(intl, 'GraphValues', {
      count: values.length,
      highest: Math.max(...definedValues).toString(),
      smallest: Math.min(...definedValues).toString()
    });

    return `${typeLabel} ${minLabel} ${maxLabel}. ${valueLabel}`;
  }

  render () {
    const { activeIndex, colorIndex, max, min, reverse, smooth, type,
      values, vertical } = this.props;
    const { height, width } = this.state;
    const pad = Math.min(width, height) < (padding * 8) ? 2 : padding;

    let classes = [CLASS_ROOT, `${CLASS_ROOT}--${type}`];
    if (vertical) {
      classes.push(`${CLASS_ROOT}--vertical`);
    }
    classes.push(`${COLOR_INDEX}-${colorIndex || 'graph-1'}`);

    let scale, step;
    if (max - min === 0) {
      min = 0;
    }
    if (vertical) {
      if (values.length <= 1) {
        scale = 1;
        step = height - (2 * pad);
      } else {
        if (max - min === 0) {
          scale = 1;
        } else {
          scale = (width - (2 * pad)) / (max - min);
        }
        step = (height - (2 * pad)) / (values.length - 1);
      }
    } else {
      if (values.length <= 1) {
        scale = 1;
        step = width - (2 * pad);
      } else {
        if (max - min === 0) {
          scale = 1;
        } else {
          scale = (height - (2 * pad)) / (max - min);
        }
        step = (width - (2 * pad)) / (values.length - 1);
      }
    }

    // Get all coordinates up front so they are available
    // if we are drawing a smooth chart.
    let points = [];
    const coordinates = values.map((value, index) => {
      let coordinate;
      if (undefined !== value) {
        if (vertical) {
          coordinate = [
            ((value - min) * scale) + pad,
            (reverse ? (index * step) :
              (height - (2 * pad)) - (index * step)) + pad
          ];
        } else {
          coordinate = [
            (reverse ? (width - (2 * pad)) - (index * step) :
              index * step) + pad,
            ((height - (2 * pad)) - ((value - min) * scale)) + pad
          ];
        }

        if ((this.props.points || index === activeIndex) &&
          ! this.props.sparkline) {
          const classes = [`${CLASS_ROOT}__point`,
            `${COLOR_INDEX}-${colorIndex || 'graph-1'}`];
          let radius = pointSize / 3;
          if (index === activeIndex) {
            classes.push(`${CLASS_ROOT}__point--active`);
            radius = pointSize / 2;
          }
          points.push(
            <circle key={index} className={classes.join(' ')}
              cx={coordinate[0]} cy={coordinate[1]} r={radius} />
          );
        }
      }

      return coordinate;
    })
    .filter(coordinate => coordinate);

    let path;
    if (coordinates.length > 1) {
      let pathProps = {};
      let commands;

      // Build the commands for this set of coordinates.

      if ('area' === type || 'line' === type) {

        if (smooth) {
          const controlCoordinates = coordinates.map((coord, index) => (
            this._controlCoordinates(coordinates, index)
          ));
          commands = '';
          coordinates.forEach((coord, index) => {
            if (0 === index) {
              commands += `M${coord.join(',')}`;
            } else {
              // Use the previous right control coordinate and the current
              // left control coordinate. We do this because we calculate
              // the left and right sides for a particular index together,
              // so the path is smooth but the SVG C command needs the
              // right one from the previous index and the left one from
              // the current index.
              commands += ` C${controlCoordinates[index-1][1].join(',')}
                ${controlCoordinates[index][0].join(',')} ${coord.join(',')}`;
            }
          });
        } else {
          commands = `M${coordinates.map(c => c.join(',')).join(' L')}`;
        }

        if ('area' === type) {
          if (vertical) {
            if (reverse) {
              // Close the path by drawing to the left
              // and across to the top of where we started.
              commands +=
                `L${pad},${coordinates[coordinates.length - 1][1]}
                L${pad},${coordinates[0][1]} Z`;
            } else {
              // Close the path by drawing to the left
              // and across to the bottom of where we started.
              commands +=
                `L${pad},${coordinates[coordinates.length - 1][1]}
                L${pad},${height - pad} Z`;
            }
          } else {
            // Close the path by drawing down to the bottom
            // and across to the left of where we started.
            commands +=
              `L${coordinates[coordinates.length - 1][0]},${height - pad}
              L${coordinates[0][0]},${height - pad} Z`;
          }
          pathProps.stroke = 'none';
        } else {
          pathProps.fill = 'none';
        }
      } else if ('bar' === type) {
        commands = coordinates.map(c => (
          `M${c.join(',')}L${vertical ? `${pad},${c[1]}` :
            `${c[0]},${height - pad}`}`
        )).join(' ');
        pathProps.fill = 'none';
      }

      path = <path {...pathProps} d={commands} />;
    }

    return (
      <svg ref={ref => this.graphRef = ref} className={classes.join(' ')}
        viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none"
        role="img" aria-label={this._renderA11YTitle()}>
        <g>
          {path}
        </g>
        {points}
      </svg>
    );
  }

};

Graph.contextTypes = {
  intl: PropTypes.object
};

Graph.defaultProps = {
  min: 0,
  max: 100
};

Graph.propTypes = {
  a11yTitle: PropTypes.string,
  activeIndex: PropTypes.number,
  colorIndex: PropTypes.string,
  height: PropTypes.number, // only from Chart
  max: PropTypes.number.isRequired,
  min: PropTypes.number.isRequired,
  points: PropTypes.bool,
  reverse: PropTypes.bool,
  smooth: PropTypes.bool,
  values: PropTypes.arrayOf(PropTypes.number).isRequired,
  // type comes from extending the component
  type: PropTypes.oneOf(['area', 'line', 'bar']).isRequired,
  vertical: PropTypes.bool,
  width: PropTypes.number // only from Chart
};
<|endoftext|>


<commit_before>(function($) {

    /**
     * jQuery tabs with bootstrap styles
     */
    $.widget("vis-ui-js.tabNavigator", $.ui.tabs, {
        options: {
        },
        _create: function() {
            var widget = this;
            var options = widget.options;
            var el = widget.element;
            var ul = $('
');

            el.append(ul);

            //var wrapper = navigation.closest('.ui-tabs');
            el.addClass('mapbender-element-tab-navigator');

            if(options.hasOwnProperty('children')){
                $.each(options.children,function(){
                    widget._add(this);
                });
            }

            el.on('tabnavigatoractivate',function(e,ui){
                var item = $(ui.newTab).data('item');
                if(item.hasOwnProperty('active')){
                    item.active(e,ui);
                }
            });
            return this._super();
        },

        _add: function (item){
            var $panel = $("
")
                .uniqueId()
                .addClass('tab-content')
                .append(item.html)
            ;
            var $anchor = $('')
                .attr('href', '#' + $panel.attr('id'))
                .html(item.title)
            ;
            var $tab = $('
')
                .append($anchor)
            ;

            $tab.data('item', item); // ...only for tabnavigatoractive event?

            this._getList().append($tab);
            this.element.append($panel);
            return $panel;
        },

        add: function(title, htmlElement, activate) {
            var content = this._add({
                html:  htmlElement,
                title: title
            });
            if(activate) {
                this.option('active', this.size() - 1);
            }
            this.refresh();
            return content;
        },

        size: function() {
            return this.tabs.length;
        }
    });
})(jQuery);
<commit_msg>Fix tabNavigator title encoding<commit_after>(function($) {

    /**
     * jQuery tabs with bootstrap styles
     */
    $.widget("vis-ui-js.tabNavigator", $.ui.tabs, {
        options: {
        },
        _create: function() {
            var widget = this;
            var options = widget.options;
            var el = widget.element;
            var ul = $('
');

            el.append(ul);

            //var wrapper = navigation.closest('.ui-tabs');
            el.addClass('mapbender-element-tab-navigator');

            if(options.hasOwnProperty('children')){
                $.each(options.children,function(){
                    widget._add(this);
                });
            }

            el.on('tabnavigatoractivate',function(e,ui){
                var item = $(ui.newTab).data('item');
                if(item.hasOwnProperty('active')){
                    item.active(e,ui);
                }
            });
            return this._super();
        },

        _add: function (item){
            var $panel = $("
")
                .uniqueId()
                .addClass('tab-content')
                .append(item.html)
            ;
            var $anchor = $('')
                .attr('href', '#' + $panel.attr('id'))
                .text(item.title)
            ;
            var $tab = $('
')
                .append($anchor)
            ;

            $tab.data('item', item); // ...only for tabnavigatoractive event?

            this._getList().append($tab);
            this.element.append($panel);
            return $panel;
        },

        add: function(title, htmlElement, activate) {
            var content = this._add({
                html:  htmlElement,
                title: title
            });
            if(activate) {
                this.option('active', this.size() - 1);
            }
            this.refresh();
            return content;
        },

        size: function() {
            return this.tabs.length;
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>(function($) {

	$.extend(mejs.MepDefaults, {
		forcePluginFullScreen: false,
		newWindowCallback: function() { return '';},
		fullscreenText: 'Fullscreen'
	});

	$.extend(MediaElementPlayer.prototype, {

		isFullScreen: false,

		isNativeFullScreen: false,

		docStyleOverflow: null,

		isInIframe: false,

		buildfullscreen: function(player, controls, layers, media) {

			if (!player.isVideo)
				return;

			player.isInIframe = (window.location != window.parent.location);

			// native events
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				player.container.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
				//player.container.bind('webkitfullscreenchange', function(e) {

					if (mejs.MediaFeatures.isFullScreen()) {
						player.isNativeFullScreen = true;
						// reset the controls once we are fully in full screen
						player.setControlsSize();
					} else {
						player.isNativeFullScreen = false;
						// when a user presses ESC
						// make sure to put the player back into place
						player.exitFullScreen();
					}
				});
			}

			var t = this,
				normalHeight = 0,
				normalWidth = 0,
				container = player.container,
				fullscreenBtn =
					$('
' +
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
					'
')
					.appendTo(controls);

				if (t.media.pluginType === 'native') {

					fullscreenBtn.click(function() {
						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;

						if (isFullScreen) {
							player.exitFullScreen();
						} else {
							player.enterFullScreen();
						}
					});

				} else {

					var hideTimeout = null;

					fullscreenBtn
						.mouseover(function() {
							console.log('trying to position');

							if (hideTimeout !== null) {
								clearTimeout(hideTimeout);
								delete hideTimeout;
							}

							var buttonPos = fullscreenBtn.offset(),
								containerPos = player.container.offset();

							media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top);

						})
						.mouseout(function() {

							console.log('mouseout fullscreen buton');

							if (hideTimeout !== null) {
								clearTimeout(hideTimeout);
								delete hideTimeout;
							}

							hideTimeout = setTimeout(function() {
								media.hideFullscreenButton();
							}, 1500);

						})
				}

			player.fullscreenBtn = fullscreenBtn;

			$(document).bind('keydown',function (e) {
				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
					player.exitFullScreen();
				}
			});

		},
		enterFullScreen: function() {

			var t = this;

			// firefox+flash can't adjust plugin sizes without resetting :(
			if (/* t.container.find('object,embed,iframe').length > 0 */
			    t.media.pluginType !== 'native'
			    && (mejs.MediaFeatures.isGecko || t.options.forcePluginFullScreen)) {
				t.media.setFullscreen(true);
				//player.isFullScreen = true;
				return;
			}

			// store overflow
			docStyleOverflow = document.documentElement.style.overflow;
			// set it to not show scroll bars so 100% will work
			document.documentElement.style.overflow = 'hidden';

			// store sizing
			normalHeight = t.container.height();
			normalWidth = t.container.width();

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				mejs.MediaFeatures.requestFullScreen(t.container[0]);
				//return;

			} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
				t.media.webkitEnterFullscreen();
				return;
			}

			// check for iframe launch
			if (t.isInIframe) {
				var url = t.options.newWindowCallback(this);

				if (url !== '') {

					// launch immediately
					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
						t.pause();
						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
						return;
					} else {
						setTimeout(function() {
							if (!t.isNativeFullScreen) {
								t.pause();
								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
							}
						}, 250);
					}
				}

			}

			// full window code

			// make full size
			t.container
				.addClass('mejs-container-fullscreen')
				.width('100%')
				.height('100%');
				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});

			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
				setTimeout(function() {
					t.container.css({width: '100%', height: '100%'});
				}, 500);
			}

			if (t.pluginType === 'native') {
				t.$media
					.width('100%')
					.height('100%');
			} else {
				t.container.find('object, embed, iframe')
					.width('100%')
					.height('100%');

				if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
					t.media.setVideoSize($(window).width(),$(window).height());
				}
			}

			t.layers.children('div')
				.width('100%')
				.height('100%');

			if (t.fullscreenBtn) {
				t.fullscreenBtn
					.removeClass('mejs-fullscreen')
					.addClass('mejs-unfullscreen');
			}

			t.setControlsSize();
			t.isFullScreen = true;
		},

		exitFullScreen: function() {

			var t = this;

			// firefox can't adjust plugins
			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
				t.media.setFullscreen(false);
				//player.isFullScreen = false;
				return;
			}

			// come outo of native fullscreen
			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
				mejs.MediaFeatures.cancelFullScreen();
			}

			// restore scroll bars to document
			document.documentElement.style.overflow = docStyleOverflow;

			t.container
				.removeClass('mejs-container-fullscreen')
				.width(normalWidth)
				.height(normalHeight);
				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			if (t.pluginType === 'native') {
				t.$media
					.width(normalWidth)
					.height(normalHeight);
			} else {
				t.container.find('object embed')
					.width(normalWidth)
					.height(normalHeight);

				t.media.setVideoSize(normalWidth, normalHeight);
			}

			t.layers.children('div')
				.width(normalWidth)
				.height(normalHeight);

			t.fullscreenBtn
				.removeClass('mejs-unfullscreen')
				.addClass('mejs-fullscreen');

			t.setControlsSize();
			t.isFullScreen = false;
		}
	});

})(mejs.$);
<commit_msg>adjusted fullscreen functionality for Flash/Firefox<commit_after>(function($) {

	$.extend(mejs.MepDefaults, {
		usePluginFullScreen: false,
		newWindowCallback: function() { return '';},
		fullscreenText: 'Fullscreen'
	});

	$.extend(MediaElementPlayer.prototype, {

		isFullScreen: false,

		isNativeFullScreen: false,

		docStyleOverflow: null,

		isInIframe: false,

		buildfullscreen: function(player, controls, layers, media) {

			if (!player.isVideo)
				return;

			player.isInIframe = (window.location != window.parent.location);

			// native events
			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				player.container.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
				//player.container.bind('webkitfullscreenchange', function(e) {

					if (mejs.MediaFeatures.isFullScreen()) {
						player.isNativeFullScreen = true;
						// reset the controls once we are fully in full screen
						player.setControlsSize();
					} else {
						player.isNativeFullScreen = false;
						// when a user presses ESC
						// make sure to put the player back into place
						player.exitFullScreen();
					}
				});
			}

			var t = this,
				normalHeight = 0,
				normalWidth = 0,
				container = player.container,
				fullscreenBtn =
					$('
' +
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
					'
')
					.appendTo(controls);

				if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {

					fullscreenBtn.click(function() {
						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;

						if (isFullScreen) {
							player.exitFullScreen();
						} else {
							player.enterFullScreen();
						}
					});

				} else {

					var hideTimeout = null;

					fullscreenBtn
						.mouseover(function() {

							if (hideTimeout !== null) {
								clearTimeout(hideTimeout);
								delete hideTimeout;
							}

							var buttonPos = fullscreenBtn.offset(),
								containerPos = player.container.offset();

							media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top);

						})
						.mouseout(function() {

							if (hideTimeout !== null) {
								clearTimeout(hideTimeout);
								delete hideTimeout;
							}

							hideTimeout = setTimeout(function() {
								media.hideFullscreenButton();
							}, 1500);

						})
				}

			player.fullscreenBtn = fullscreenBtn;

			$(document).bind('keydown',function (e) {
				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
					player.exitFullScreen();
				}
			});

		},
		enterFullScreen: function() {

			var t = this;

			// firefox+flash can't adjust plugin sizes without resetting :(
			if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
				//t.media.setFullscreen(true);
				//player.isFullScreen = true;
				return;
			}

			// store overflow
			docStyleOverflow = document.documentElement.style.overflow;
			// set it to not show scroll bars so 100% will work
			document.documentElement.style.overflow = 'hidden';

			// store sizing
			normalHeight = t.container.height();
			normalWidth = t.container.width();

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
			if (t.media.pluginType === 'native') {
				if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

					mejs.MediaFeatures.requestFullScreen(t.container[0]);
					//return;

				} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
					t.media.webkitEnterFullscreen();
					return;
				}
			}

			// check for iframe launch
			if (t.isInIframe) {
				var url = t.options.newWindowCallback(this);

				if (url !== '') {

					// launch immediately
					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
						t.pause();
						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
						return;
					} else {
						setTimeout(function() {
							if (!t.isNativeFullScreen) {
								t.pause();
								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
							}
						}, 250);
					}
				}

			}

			// full window code

			// make full size
			t.container
				.addClass('mejs-container-fullscreen')
				.width('100%')
				.height('100%');
				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});

			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
			// Actually, it seems to be needed for IE8, too
			//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
				setTimeout(function() {
					t.container.css({width: '100%', height: '100%'});
					t.setControlsSize();
				}, 500);
			//}

			if (t.pluginType === 'native') {
				t.$media
					.width('100%')
					.height('100%');
			} else {
				t.container.find('object, embed, iframe')
					.width('100%')
					.height('100%');

				//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
					t.media.setVideoSize($(window).width(),$(window).height());
				//}
			}

			t.layers.children('div')
				.width('100%')
				.height('100%');

			if (t.fullscreenBtn) {
				t.fullscreenBtn
					.removeClass('mejs-fullscreen')
					.addClass('mejs-unfullscreen');
			}

			t.setControlsSize();
			t.isFullScreen = true;
		},

		exitFullScreen: function() {

			var t = this;

			// firefox can't adjust plugins
			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
				t.media.setFullscreen(false);
				//player.isFullScreen = false;
				return;
			}

			// come outo of native fullscreen
			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
				mejs.MediaFeatures.cancelFullScreen();
			}

			// restore scroll bars to document
			document.documentElement.style.overflow = docStyleOverflow;

			t.container
				.removeClass('mejs-container-fullscreen')
				.width(normalWidth)
				.height(normalHeight);
				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			if (t.pluginType === 'native') {
				t.$media
					.width(normalWidth)
					.height(normalHeight);
			} else {
				t.container.find('object embed')
					.width(normalWidth)
					.height(normalHeight);

				t.media.setVideoSize(normalWidth, normalHeight);
			}

			t.layers.children('div')
				.width(normalWidth)
				.height(normalHeight);

			t.fullscreenBtn
				.removeClass('mejs-unfullscreen')
				.addClass('mejs-fullscreen');

			t.setControlsSize();
			t.isFullScreen = false;
		}
	});

})(mejs.$);
<|endoftext|>


<commit_before>// This file containts opportunities bussines logic
// function definitions section
lx.upload.getFileButton = function(element) {
    console.log('Rendering button from %s', element.field_name);
    if ($('#' + element.field_name).length == 0) {
        console.log('Field %s not present in EditView', element.field_name);
    } else {
        data = $('#' + element.field_name).val();
        if (data == '') {
            data = {
                "note_link": '',
                "note_name": ''
            };
        } else {
            data = JSON.parse(data);
        }
        $('#' + element.field_name).parent().append('
' + data.note_name + '

');
        $('#' + element.field_name).parent().append('<button id="show_' + element.field_name + '_loader" type="button" class="btn btn-primary btn-sm">+ ' + element.button_label + '</button>');
        $('#' + element.field_name).parent().append('
');
        $('#' + element.field_name).prop('readonly', 'readonly');
        $('#' + element.field_name).hide();
        $('#show_' + element.field_name + '_loader').click(function() {
            lx.upload.getFileTemplate(element);
            $('#show_' + element.field_name + '_loader').prop('disabled', true);
            $('#' + element.field_name).prop('disabled', true);
            // $('#' + element.field_name).toggle(); // to view field
        });
        console.log('Field ' + element.field_name + ' rendered.')
    }
}

lx.upload.getFileTemplate = function(element) {
    var method = "uploadFileTemplate";
    data = {
        "method": method,
        "field_name": element.field_name,
        "label": element.button_label,
        "ok_message": element.ok_message,
        "module_name": element.module_name,
        "record_id": element.record_id
    }
    $.ajax({
        // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
        beforeSend: function(jqXHR, settings) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax beforeSend');
            console.log("*** start ***");
            console.log("beforeSend callback:", settings.url);
            console.log("beforeSend callback:", settings.data);
        }, //end beforeSend
        url: "lxajax.php",
        type: 'POST',
        data: data,
        // success is a function to be called if the request succeeds.
        success: function(data, status, jqXHR) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax success');
            console.log("success callback:", status);
            console.log("data:", data);
            $('#floating-div-for-upload-' + element.field_name + '-file').remove();
            $('#' + element.field_name + '_loader_hook').html('
');
            $replaceMe = $('
');
            $('#floating-div-for-upload-' + element.field_name + '-file').html($replaceMe).addClass("lx-floating-div").draggable({
                cursor: "crosshair",
                cursorAt: {
                    top: 56,
                    left: 56
                }
            })
            // populate dropdown with QRN
            $('#lx-replace-me').replaceWith(data);
            $('#floating-div-for-upload-' + element.field_name + '-file').show("slow");
            // buttons functionality
            $('#exit-' + element.field_name + '-btn').click(function() {
                $('#floating-div-for-upload-' + element.field_name + '-file').hide("slow");
                $('#show_' + element.field_name + '_loader').prop('disabled', false);
                $('#' + element.field_name).prop('disabled', false);
                // $('#' + element.field_name).toggle(); // to view field
            });
            $('#upload-' + element.field_name + '-btn').click(function() {
                $('#' + element.field_name + '-file').hide();
                $('#upload-' + element.field_name + '-btn').hide();
                $('#exit-' + element.field_name + '-btn').hide();
                $('#preview_' + element.field_name).html('');
                $('#preview_' + element.field_name).html('');
                $('

0%

').prependTo('#preview_' + element.field_name);
                $('#' + element.field_name + '-form').ajaxForm({
                    beforeSend: function(jqXHR, settings) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm beforeSend');
                        console.log("*** start ***");
                        console.log("beforeSend callback:", settings.url);
                        // file to be modified
                        settings.url += "&opportunity_id=" + element.opportunity_id;
                        console.log("url modified:", settings.url);
                    }, //end beforeSend
                    // target: '#preview_fieldname', //It's not required 'cause #preview_fieldname is been handled on success
                    // Progress bar while uploading file...
                    uploadProgress: function(event, position, total, percentComplete) {
                        $('#floating-div-for-upload-' + element.field_name + '-file').css({"height": "260px"});
                        var percentVal = percentComplete + '%';
                        $('.lx-bar').width(percentVal)
                        $('.lx-percent').html(percentVal);
                    },
                    // success is a function to be called if the request succeeds.
                    success: function(data, status, jqXHR) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm success');
                        console.log("success callback:", status);
                        console.log("data:", data);
                        data = JSON.parse(data);
                        $('#preview_' + element.field_name).text(data.message);
                        $('#floating-div-for-upload-' + element.field_name + '-file').css({"height": "300px"});
                        if (data.ok) {
                            jsonToStore = {
                                "note_name": data.document_name,
                                "note_id": data.document_id,
                                "note_link": data.document_file
                            }
                            $('#' + element.field_name).val(JSON.stringify(jsonToStore));
                            $('#' + element.field_name + '-file-name').html('' + data.document_name + '');
                            $('#floating-div-for-upload-' + element.field_name + '-file').css({"width": "235px", "height": "200px"});
                            $('#' + element.field_name + '-title').hide();
                            $('#' + element.field_name + '-form').hide();
                            var percentVal = '100%';
                            $('.lx-bar').width(percentVal);
                            $('.lx-percent').html(percentVal);
                            $('#exit-' + element.field_name + '-btn').show();
                        } else {
                            $('.lx-progress').hide();
                            $('#' + element.field_name + '-file').show();
                            $('#upload-' + element.field_name + '-btn').show();
                            $('#exit-' + element.field_name + '-btn').show();
                        }

                    }, // success
                    // error is a function to be called if the request fails.
                    error: function(jqXHR, status, error) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm error');
                        console.log("error callback:", status);
                        console.log("Function lx.upload.getFileTemplate error:", error);
                    }, // end error
                    // complete is a function to be called when the request finishes (after success and error callbacks are executed).
                    complete: function(jqXHR, status) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm complete');
                        console.log("complete callback:", status);
                        console.log("*** finish ***");
                    }, // end complete
                    datatype: "text"
                }).submit();
            });

        }, // end success
        // error is a function to be called if the request fails.
        error: function(jqXHR, status, error) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax error');
            console.log("error callback:", status);
            console.log("Function lx.upload.getFileTemplate error:", error);
        }, // end error
        // complete is a function to be called when the request finishes (after success and error callbacks are executed).
        complete: function(jqXHR, status) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax complete');
            console.log("complete callback:", status);
            console.log("*** finish ***");
        }, // end complete
        datatype: "text"
    })/*Fin del Ajax*/
} //lx.upload.getFileTemplate()

lx.upload.getFileFields = function() {
    var execute = false;
    var crmEditView = document.forms['EditView'];
    if (crmEditView) {
        module_name = crmEditView.module.value.toLowerCase();
        switch (module_name) {
            case 'accounts':
            case 'contacts':
            case 'opportunities':
                if (lx.lionixCRM.config.modules[module_name].upload_files_fields != undefined) {
                    text_fields_to_upload_fields_list = lx.lionixCRM.config.modules[module_name].upload_files_fields;
                    execute = true;
                }
                break;
        }
        if (execute) {
            console.log('Rendering upload files fields for ' + crmEditView.module.value + ' module...')
            text_fields_to_upload_fields_list.forEach(function(element) {
                element.module_name = crmEditView.module.value;
                element.record_id = crmEditView.record.value;
            });
            text_fields_to_upload_fields_list.forEach(function(element) {
                if ($('#show_' + element.field_name + '_loader').length == 0) {
                    lx.upload.getFileButton(element);
                }
            });
        }
    }
} // end function

//Self-Invoking Anonymous Function Notation
// !function(){}(); // easy to read, the result is unimportant.
// (function(){})(); // like above but more parens.
// (function(){}()); // Douglas Crockford's style when you need function results.
// Further reading: http://javascript.crockford.com/code.html then search for invoked immediately
!function() {
    // On other modules
    // create an observer instance
    // https://developer.mozilla.org/en/docs/Web/API/MutationObserver
    var observer = new MutationObserver(function(mutations) {
        if (mutations) {
            console.log("Upload files in EditView '%s' '%s' '%s' '%s'", 'all modules', 'lx-upload-files-in-editview.js', '!function()', 'observer');
            console.log('Running lx.upload.getFileFields() function');
            lx.lionixCRM.getConfigOption('modules').then(function() {
                lx.upload.getFileFields();
            });
            // if needed only once, you can stop observing with observer.disconnect();
            // observer.disconnect();
        }
    });
    // Observer target
    var target = document.querySelector('#content');
    // configuration of the observer:
    // NOTE: At the very least, childList, attributes, or characterData must be set to true. Otherwise, "An invalid or illegal string was specified" error is thrown.
    var config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
    };
    // pass in the target node, as well as the observer options
    observer.observe(target, config);
    // end observer
}();
//eof
<commit_msg>fix: file fields check on any view<commit_after>// This file containts opportunities bussines logic
// function definitions section
lx.upload.getFileButton = function(element) {
    console.log('Rendering button from %s', element.field_name);
    if ($('#' + element.field_name).length == 0) {
        console.log('Field %s not present in EditView', element.field_name);
    } else {
        data = $('#' + element.field_name).val();
        if (data == '') {
            data = {
                "note_link": '',
                "note_name": ''
            };
        } else {
            data = JSON.parse(data);
        }
        $('#' + element.field_name).parent().append('
' + data.note_name + '

');
        $('#' + element.field_name).parent().append('<button id="show_' + element.field_name + '_loader" type="button" class="btn btn-primary btn-sm">+ ' + element.button_label + '</button>');
        $('#' + element.field_name).parent().append('
');
        $('#' + element.field_name).prop('readonly', 'readonly');
        $('#' + element.field_name).hide();
        $('#show_' + element.field_name + '_loader').click(function() {
            lx.upload.getFileTemplate(element);
            $('#show_' + element.field_name + '_loader').prop('disabled', true);
            $('#' + element.field_name).prop('disabled', true);
            // $('#' + element.field_name).toggle(); // to view field
        });
        console.log('Field ' + element.field_name + ' rendered.')
    }
}

lx.upload.getFileTemplate = function(element) {
    var method = "uploadFileTemplate";
    data = {
        "method": method,
        "field_name": element.field_name,
        "label": element.button_label,
        "ok_message": element.ok_message,
        "module_name": element.module_name,
        "record_id": element.record_id
    }
    $.ajax({
        // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
        beforeSend: function(jqXHR, settings) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax beforeSend');
            console.log("*** start ***");
            console.log("beforeSend callback:", settings.url);
            console.log("beforeSend callback:", settings.data);
        }, //end beforeSend
        url: "lxajax.php",
        type: 'POST',
        data: data,
        // success is a function to be called if the request succeeds.
        success: function(data, status, jqXHR) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax success');
            console.log("success callback:", status);
            console.log("data:", data);
            $('#floating-div-for-upload-' + element.field_name + '-file').remove();
            $('#' + element.field_name + '_loader_hook').html('
');
            $replaceMe = $('
');
            $('#floating-div-for-upload-' + element.field_name + '-file').html($replaceMe).addClass("lx-floating-div").draggable({
                cursor: "crosshair",
                cursorAt: {
                    top: 56,
                    left: 56
                }
            })
            // populate dropdown with QRN
            $('#lx-replace-me').replaceWith(data);
            $('#floating-div-for-upload-' + element.field_name + '-file').show("slow");
            // buttons functionality
            $('#exit-' + element.field_name + '-btn').click(function() {
                $('#floating-div-for-upload-' + element.field_name + '-file').hide("slow");
                $('#show_' + element.field_name + '_loader').prop('disabled', false);
                $('#' + element.field_name).prop('disabled', false);
                // $('#' + element.field_name).toggle(); // to view field
            });
            $('#upload-' + element.field_name + '-btn').click(function() {
                $('#' + element.field_name + '-file').hide();
                $('#upload-' + element.field_name + '-btn').hide();
                $('#exit-' + element.field_name + '-btn').hide();
                $('#preview_' + element.field_name).html('');
                $('#preview_' + element.field_name).html('');
                $('

0%

').prependTo('#preview_' + element.field_name);
                $('#' + element.field_name + '-form').ajaxForm({
                    beforeSend: function(jqXHR, settings) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm beforeSend');
                        console.log("*** start ***");
                        console.log("beforeSend callback:", settings.url);
                        // file to be modified
                        settings.url += "&opportunity_id=" + element.opportunity_id;
                        console.log("url modified:", settings.url);
                    }, //end beforeSend
                    // target: '#preview_fieldname', //It's not required 'cause #preview_fieldname is been handled on success
                    // Progress bar while uploading file...
                    uploadProgress: function(event, position, total, percentComplete) {
                        $('#floating-div-for-upload-' + element.field_name + '-file').css({"height": "260px"});
                        var percentVal = percentComplete + '%';
                        $('.lx-bar').width(percentVal)
                        $('.lx-percent').html(percentVal);
                    },
                    // success is a function to be called if the request succeeds.
                    success: function(data, status, jqXHR) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm success');
                        console.log("success callback:", status);
                        console.log("data:", data);
                        data = JSON.parse(data);
                        $('#preview_' + element.field_name).text(data.message);
                        $('#floating-div-for-upload-' + element.field_name + '-file').css({"height": "300px"});
                        if (data.ok) {
                            jsonToStore = {
                                "note_name": data.document_name,
                                "note_id": data.document_id,
                                "note_link": data.document_file
                            }
                            $('#' + element.field_name).val(JSON.stringify(jsonToStore));
                            $('#' + element.field_name + '-file-name').html('' + data.document_name + '');
                            $('#floating-div-for-upload-' + element.field_name + '-file').css({"width": "235px", "height": "200px"});
                            $('#' + element.field_name + '-title').hide();
                            $('#' + element.field_name + '-form').hide();
                            var percentVal = '100%';
                            $('.lx-bar').width(percentVal);
                            $('.lx-percent').html(percentVal);
                            $('#exit-' + element.field_name + '-btn').show();
                        } else {
                            $('.lx-progress').hide();
                            $('#' + element.field_name + '-file').show();
                            $('#upload-' + element.field_name + '-btn').show();
                            $('#exit-' + element.field_name + '-btn').show();
                        }

                    }, // success
                    // error is a function to be called if the request fails.
                    error: function(jqXHR, status, error) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm error');
                        console.log("error callback:", status);
                        console.log("Function lx.upload.getFileTemplate error:", error);
                    }, // end error
                    // complete is a function to be called when the request finishes (after success and error callbacks are executed).
                    complete: function(jqXHR, status) {
                        console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajaxForm complete');
                        console.log("complete callback:", status);
                        console.log("*** finish ***");
                    }, // end complete
                    datatype: "text"
                }).submit();
            });

        }, // end success
        // error is a function to be called if the request fails.
        error: function(jqXHR, status, error) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax error');
            console.log("error callback:", status);
            console.log("Function lx.upload.getFileTemplate error:", error);
        }, // end error
        // complete is a function to be called when the request finishes (after success and error callbacks are executed).
        complete: function(jqXHR, status) {
            console.log("Bussines logic '%s' '%s' '%s' '%s'", 'opportunities', 'lx-upload-files-in-detailview.js', 'lx.upload.getFileTemplate()', 'ajax complete');
            console.log("complete callback:", status);
            console.log("*** finish ***");
        }, // end complete
        datatype: "text"
    })/*Fin del Ajax*/
} //lx.upload.getFileTemplate()

lx.upload.getFileFields = function() {
    var execute = false;
    var crmEditView = document.forms['EditView'];
    if (crmEditView) {
        module_name = crmEditView.module.value.toLowerCase();
        switch (module_name) {
            case 'accounts':
            case 'contacts':
            case 'opportunities':
                if (lx.lionixCRM.config.modules[module_name].upload_files_fields != undefined) {
                    text_fields_to_upload_fields_list = lx.lionixCRM.config.modules[module_name].upload_files_fields;
                    execute = true;
                }
                break;
        }
        if (execute) {
            console.log('Rendering upload files fields for ' + crmEditView.module.value + ' module...')
            text_fields_to_upload_fields_list.forEach(function(element) {
                element.module_name = crmEditView.module.value;
                element.record_id = crmEditView.record.value;
            });
            text_fields_to_upload_fields_list.forEach(function(element) {
                if ($('#show_' + element.field_name + '_loader').length == 0) {
                    lx.upload.getFileButton(element);
                }
            });
            lx.upload.processed = true;
        }
    } else {
        lx.upload.processed = true;
    }
} // end function

//Self-Invoking Anonymous Function Notation
// !function(){}(); // easy to read, the result is unimportant.
// (function(){})(); // like above but more parens.
// (function(){}()); // Douglas Crockford's style when you need function results.
// Further reading: http://javascript.crockford.com/code.html then search for invoked immediately
!function() {
    // On other modules
    // create an observer instance
    // https://developer.mozilla.org/en/docs/Web/API/MutationObserver
    var observer = new MutationObserver(function(mutations) {
        if (mutations) {
            // if needed only once, you can stop observing with observer.disconnect();
            if (lx.upload.processed) {
                observer.disconnect();
                console.log('Upload file fields already processed, observer stopped');
            } else {
                console.log("Upload files in EditView '%s' '%s' '%s' '%s'", 'all modules', 'lx-upload-files-in-editview.js', '!function()', 'observer');
                console.log('Running lx.upload.getFileFields() function');
                lx.lionixCRM.getConfigOption('modules').then(function() {
                    lx.upload.getFileFields();
                });
            }
        }
    });
    // Observer target
    var target = document.querySelector('#content');
    // configuration of the observer:
    // NOTE: At the very least, childList, attributes, or characterData must be set to true. Otherwise, "An invalid or illegal string was specified" error is thrown.
    var config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
    };
    // pass in the target node, as well as the observer options
    observer.observe(target, config);
    // end observer
}();
//eof
<|endoftext|>


<commit_before>import _ from "underscore";
import Backbone from "backbone";

// InstanceState manages the status/activity of an instance. An instance would
// have an status/activity of active/rebooting for example.

var InstanceState = Backbone.Model.extend({

  isInFinalState: function () {
    var validStates = [
      "active",
      "error",
      "active - deploy_error",
      "suspended",
      "shutoff"
    ];

    if (this.get('status') === "build")
        return false;

    return _.contains(validStates, this.get('status_raw'));
  },

  isDeployError: function () {
    var status = this.get('status');
    var activity = this.get('activity');

    if (status === "active" && activity === "deploy_error") {
      return true;
    } else {
      return false;
    }
  },

  getPercentComplete: function () {
    var status = this.get('status');
    var activity = this.get('activity');
    var percentComplete = 100;
    if (status && activity) {
      percentComplete = get_percent_complete(status, activity);
    }
    return percentComplete;
  },

  initialize: function (attributes, options) {

    var tokens = attributes.status_raw.split('-').map(s => s.trim());
    var state = tokens[0];
    var activity = tokens[1];

    if (tokens.length == 3) {
      // Deal with Openstack Grizzly's hyphenated states "powering-on" and "powering-off"
      activity = tokens[1] + '-' + tokens[2];
    }

    this.set('status', state);
    this.set('activity', activity);
  }

});

var get_percent_complete = function (state, activiy) {

  // Number represents percent task *completed* when in this state
  var states = {
    'build': {
      'block_device_mapping': 10,
      'scheduling': 20,
      'networking': 30,
      'spawning': 40,
      'deleting': 50,
    },
    'active': {
      'powering-off': 50,
      'image_uploading': 50,
      'deleting': 50,
      'suspending': 50,
      'initializing': 50,
      'networking': 60,
      'deploying': 70
    },
    'hard_reboot': {
      'rebooting-hard': 50
    },
    'reboot': {
      'rebooting': 50
    },
    'shutoff': {
      'powering-on': 50
    },
    'suspended': {
      'resuming': 50
    }
  };

  // Note: 100 is graphically similar to 0
  return states[state][activiy] || 100;
};

var get_final_state = function (activity) {
  // Check for the final state to prevent reverting if a queued task hasn't begun yet
  if (activity === 'powering-off') {
    return 'shutoff';
  }
  else if (activity === 'deleting') {
    return 'deleted';
  }
  else if (activity === 'suspending') {
    return 'suspended';
  }
  else if (activity === 'deploy_error') {
    return 'deploy_error';
  }
  else {
    // Applies for: build, shutoff, and suspended
    return 'active';
  }
};

export default InstanceState;
<commit_msg>Refactor, document strange code<commit_after>import _ from "underscore";
import Backbone from "backbone";

// InstanceState manages the status/activity of an instance. An instance would
// have an status/activity of active/rebooting for example.

var InstanceState = Backbone.Model.extend({

  isInFinalState: function () {
    var validStates = [
      "active",
      "error",
      "active - deploy_error",
      "suspended",
      "shutoff"
    ];

    if (this.get('status') === "build")
        return false;

    return _.contains(validStates, this.get('status_raw'));
  },

  // This method is a slight hack, there is a larger problem with how we keep
  // track of state. It is documented in ATMO-1120.
  isDeployError: function () {
    var status = this.get('status');
    var activity = this.get('activity');

    return status === "active" && activity === "deploy_error";
  },

  getPercentComplete: function () {
    var status = this.get('status');
    var activity = this.get('activity');
    var percentComplete = 100;
    if (status && activity) {
      percentComplete = get_percent_complete(status, activity);
    }
    return percentComplete;
  },

  initialize: function (attributes, options) {

    var tokens = attributes.status_raw.split('-').map(s => s.trim());
    var state = tokens[0];
    var activity = tokens[1];

    if (tokens.length == 3) {
      // Deal with Openstack Grizzly's hyphenated states "powering-on" and "powering-off"
      activity = tokens[1] + '-' + tokens[2];
    }

    this.set('status', state);
    this.set('activity', activity);
  }

});

var get_percent_complete = function (state, activiy) {

  // Number represents percent task *completed* when in this state
  var states = {
    'build': {
      'block_device_mapping': 10,
      'scheduling': 20,
      'networking': 30,
      'spawning': 40,
      'deleting': 50,
    },
    'active': {
      'powering-off': 50,
      'image_uploading': 50,
      'deleting': 50,
      'suspending': 50,
      'initializing': 50,
      'networking': 60,
      'deploying': 70
    },
    'hard_reboot': {
      'rebooting-hard': 50
    },
    'reboot': {
      'rebooting': 50
    },
    'shutoff': {
      'powering-on': 50
    },
    'suspended': {
      'resuming': 50
    }
  };

  // Note: 100 is graphically similar to 0
  return states[state][activiy] || 100;
};

var get_final_state = function (activity) {
  // Check for the final state to prevent reverting if a queued task hasn't begun yet
  if (activity === 'powering-off') {
    return 'shutoff';
  }
  else if (activity === 'deleting') {
    return 'deleted';
  }
  else if (activity === 'suspending') {
    return 'suspended';
  }
  else if (activity === 'deploy_error') {
    return 'deploy_error';
  }
  else {
    // Applies for: build, shutoff, and suspended
    return 'active';
  }
};

export default InstanceState;
<|endoftext|>


<commit_before>describe('Channel:', function () {
  beforeEach(function () {
    this.channel = Backbone.Radio.channel('myChannel');
  });

  describe('when calling Radio.channel with no name', function() {
    it('should throw an error', function() {
      expect(Backbone.Radio.channel).to.throw(Error, 'You must provide a name for the channel.');
    });
  });

  describe('upon creation', function() {
    it('should create a new instance of the Channel', function() {
      expect(this.channel).to.be.instanceOf(Backbone.Radio.Channel);
    });

    it('should have its name set', function() {
      expect(this.channel).to.have.property('channelName', 'myChannel');
    });

    it('should have all of the Backbone.Events methods', function() {
      expect(this.channel).to.contain(Backbone.Events);
    });

    it('should have all of the Radio.Commands methods', function() {
      expect(this.channel).to.contain(Backbone.Radio.Commands);
    });

    it('should have all of the Radio.Requests methods', function() {
      expect(this.channel).to.contain(Backbone.Radio.Requests);
    });
  });

  describe('calling channel twice with the same name', function() {
    beforeEach(function() {
      this.channelCopy = Backbone.Radio.channel('myChannel');
    });

    it('should return the same channel', function() {
      expect(this.channelCopy).to.deep.equal(this.channel);
    });
  });

  describe('executing the `reset` method of a Channel', function() {
    beforeEach(function() {
      stub(this.channel, 'off');
      stub(this.channel, 'stopListening');
      stub(this.channel, 'stopComplying');
      stub(this.channel, 'stopReplying');
      spy(this.channel, 'reset');

      this.channel.reset();
    });

    it('should call the reset functions of Backbone.Events', function() {
      expect(this.channel.off).to.have.been.calledOnce;
      expect(this.channel.stopListening).to.have.been.calledOnce;
    });

    it('should call the reset functions of Backbone.Radio.Commands', function() {
      expect(this.channel.stopComplying).to.have.been.calledOnce;
    });

    it('should call the reset functions of Backbone.Radio.Requests', function() {
      expect(this.channel.stopReplying).to.have.been.calledOnce;
    });

    it('should return the Channel', function() {
      expect(this.channel.reset).to.have.always.returned(this.channel);
    });
  });
});
<commit_msg>Adds test to ensure that Channels don't conflict.<commit_after>describe('Channel:', function () {
  beforeEach(function () {
    this.channel = Backbone.Radio.channel('myChannel');
    this.channelTwo = Backbone.Radio.channel('myOtherChannel');
  });

  describe('when calling Radio.channel with no name', function() {
    it('should throw an error', function() {
      expect(Backbone.Radio.channel).to.throw(Error, 'You must provide a name for the channel.');
    });
  });

  describe('upon creation', function() {
    it('should create a new instance of the Channel', function() {
      expect(this.channel).to.be.instanceOf(Backbone.Radio.Channel);
    });

    it('should have its name set', function() {
      expect(this.channel).to.have.property('channelName', 'myChannel');
    });

    it('should have all of the Backbone.Events methods', function() {
      expect(this.channel).to.contain(Backbone.Events);
    });

    it('should have all of the Radio.Commands methods', function() {
      expect(this.channel).to.contain(Backbone.Radio.Commands);
    });

    it('should have all of the Radio.Requests methods', function() {
      expect(this.channel).to.contain(Backbone.Radio.Requests);
    });
  });

  describe('calling channel twice with the same name', function() {
    beforeEach(function() {
      this.channelCopy = Backbone.Radio.channel('myChannel');
    });

    it('should return the same channel', function() {
      expect(this.channelCopy).to.deep.equal(this.channel);
    });
  });

  describe('executing the `reset` method of a Channel', function() {
    beforeEach(function() {
      stub(this.channel, 'off');
      stub(this.channel, 'stopListening');
      stub(this.channel, 'stopComplying');
      stub(this.channel, 'stopReplying');
      spy(this.channel, 'reset');

      this.channel.reset();
    });

    it('should call the reset functions of Backbone.Events', function() {
      expect(this.channel.off).to.have.been.calledOnce;
      expect(this.channel.stopListening).to.have.been.calledOnce;
    });

    it('should call the reset functions of Backbone.Radio.Commands', function() {
      expect(this.channel.stopComplying).to.have.been.calledOnce;
    });

    it('should call the reset functions of Backbone.Radio.Requests', function() {
      expect(this.channel.stopReplying).to.have.been.calledOnce;
    });

    it('should return the Channel', function() {
      expect(this.channel.reset).to.have.always.returned(this.channel);
    });
  });

  describe('when executing an event that exists on two channels', function() {
    beforeEach(function() {
      this.callbackOne = stub();
      this.callbackTwo = stub();
    });

    describe('on Events', function() {
      beforeEach(function() {
        this.channel.on('some:event', this.callbackOne);
        this.channelTwo.on('some:event', this.callbackOne);

        this.channel.trigger('some:event');
      });

      it('should only trigger the callback on the channel specified', function() {
        expect(this.callbackOne).to.have.been.calledOnce;
        expect(this.callbackTwo).to.not.have.been.called;
      });
    });

    describe('on Commands', function() {
      beforeEach(function() {
        this.channel.comply('some:command', this.callbackOne);
        this.channelTwo.comply('some:command', this.callbackOne);

        this.channel.command('some:command');
      });

      it('should only trigger the callback on the channel specified', function() {
        expect(this.callbackOne).to.have.been.calledOnce;
        expect(this.callbackTwo).to.not.have.been.called;
      });
    });

    describe('on Requests', function() {
      beforeEach(function() {
        this.channel.reply('some:request', this.callbackOne);
        this.channelTwo.reply('some:request', this.callbackOne);

        this.channel.request('some:request');
      });

      it('should only trigger the callback on the channel specified', function() {
        expect(this.callbackOne).to.have.been.calledOnce;
        expect(this.callbackTwo).to.not.have.been.called;
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var utils = require('./utils'),
	request = require('supertest'),
	express = require('express'),
	Tag = require('../../../models/Tag'),
	tagDao = require('../../../api/dao/tag'),
	app = express();

var tag1 = {
	_id: '52e2551694d6f1312355ba9e',
	libelle: 'Exercie'
};

describe('Dao:Tag', function() {

	it('Dao:Tag:Create', function(done) {
		app.post('/addTag', function(req, res) {
			req.body = tag1;
			tagDao.create(req, res);
		});
		request(app).post('/addTag').expect(200, done);
	});

	it('Dao:Tag:Update', function(done) {
		app.post('/updateTag', function(req, res) {
			req.body = {
				_id: tag1._id,
				libelle: 'Cours'
			};
			tagDao.update(req, res);
		});
		request(app).post('/updateTag').expect(200, done);
	});

	it('Dao:Tag:All', function(done) {
		app.post('/readTags', function(req, res) {
			tagDao.all(req, res);
		});
		request(app).post('/readTags').expect(200, done);
	});

	it('Dao:Tag:Remove', function(done) {
		app.post('/deleteTag', function(req, res) {
			req.body = {
				_id: tag1._id
			};
			tagDao.remove(req, res);
		});
		request(app).post('/deleteTag').expect(200, done);
	});
});<commit_msg><commit_after><|endoftext|>


<commit_before>import _ from 'lodash';
// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { PropTypes } from 'react';

import { Row, Col } from 'react-bootstrap';
import Button from '@folio/stripes-components/lib/Button';
import Icon from '@folio/stripes-components/lib/Icon';
import TextField from '@folio/stripes-components/lib/TextField';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';

class UserLoans extends React.Component {

  static propTypes = {
    data: PropTypes.shape({
      userLoans: PropTypes.arrayOf(PropTypes.object),
      loansHistory: PropTypes.arrayOf(PropTypes.object),
    }),
    onClickViewLoansHistory: PropTypes.func.isRequired,
  };

  static manifest = Object.freeze({
    usersLoans: {
      type: 'okapi',
      records: 'loans',
      GET: {
        path: 'circulation/loans?query=(userId=:{userid} AND status="Open")',
      },
    },
    userid: {},
  });

  render() {
    const { data: { usersLoans } } = this.props;

    const loansFormatter = {
      title: loan => `${_.get(loan, ['item', 'title'], '')}`,
      barcode: loan => `${_.get(loan, ['item', 'barcode'], '')}`,
      status: loan => `${_.get(loan, ['status', 'name'], '')}`,
      loanDate: loan => loan.loanDate.substr(0, 10),
    };

    if (!usersLoans) return
;

    return (

        <Row>
          <Col xs={3}>

Current loans

          </Col>
          <Col xs={4} sm={3}>
            <TextField
              rounded
              endControl={<Button buttonStyle="fieldControl"><Icon icon="clearX" /></Button>}
              startControl={<Icon icon="search" />}
              placeholder="Search"
              fullWidth
            />
          </Col>
          <Col xs={5} sm={6}>
            <Button align="end" bottomMargin0 onClick={this.props.onClickViewLoansHistory}>View Full History</Button>
          </Col>
        </Row>
        <MultiColumnList
          fullWidth
          formatter={loansFormatter}
          visibleColumns={['title', 'barcode', 'loanDate', 'status']}
          contentData={usersLoans}
        />

);
  }
}

export default UserLoans;
<commit_msg>Render loan dates in locale-specific format. Fixes LIBAPP-179.<commit_after>import _ from 'lodash';
// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { PropTypes } from 'react';

import { Row, Col } from 'react-bootstrap';
import Button from '@folio/stripes-components/lib/Button';
import Icon from '@folio/stripes-components/lib/Icon';
import TextField from '@folio/stripes-components/lib/TextField';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';

class UserLoans extends React.Component {

  static propTypes = {
    data: PropTypes.shape({
      userLoans: PropTypes.arrayOf(PropTypes.object),
      loansHistory: PropTypes.arrayOf(PropTypes.object),
    }),
    stripes: PropTypes.shape({
      locale: PropTypes.string.isRequired,
    }).isRequired,
    onClickViewLoansHistory: PropTypes.func.isRequired,
  };

  static manifest = Object.freeze({
    usersLoans: {
      type: 'okapi',
      records: 'loans',
      GET: {
        path: 'circulation/loans?query=(userId=:{userid} AND status="Open")',
      },
    },
    userid: {},
  });

  render() {
    const { data: { usersLoans } } = this.props;

    const loansFormatter = {
      title: loan => `${_.get(loan, ['item', 'title'], '')}`,
      barcode: loan => `${_.get(loan, ['item', 'barcode'], '')}`,
      status: loan => `${_.get(loan, ['status', 'name'], '')}`,
      loanDate: loan => new Date(Date.parse(loan.loanDate)).toLocaleDateString(this.props.stripes.locale),
    };

    if (!usersLoans) return
;

    return (

        <Row>
          <Col xs={3}>

Current loans

          </Col>
          <Col xs={4} sm={3}>
            <TextField
              rounded
              endControl={<Button buttonStyle="fieldControl"><Icon icon="clearX" /></Button>}
              startControl={<Icon icon="search" />}
              placeholder="Search"
              fullWidth
            />
          </Col>
          <Col xs={5} sm={6}>
            <Button align="end" bottomMargin0 onClick={this.props.onClickViewLoansHistory}>View Full History</Button>
          </Col>
        </Row>
        <MultiColumnList
          fullWidth
          formatter={loansFormatter}
          visibleColumns={['title', 'barcode', 'loanDate', 'status']}
          contentData={usersLoans}
        />

);
  }
}

export default UserLoans;
<|endoftext|>


<commit_before>/*
 * Copyright 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. 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
 * OWNER 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.
 */

/**
 * @fileoverview This file contains a loader class for helping to load
 *     muliple assets in an asynchronous manner.
 */

o3djs.provide('o3djs.loader');

o3djs.require('o3djs.io');
o3djs.require('o3djs.scene');

/**
 * A Module with a loader class for helping to load muliple assets in an
 * asynchronous manner.
 * @namespace
 */
o3djs.loader = o3djs.loader || {};

/**
 * A simple Loader class to call some callback when everything has loaded.
 * @constructor
 * @param {!function(): void} onFinished Function to call when final item has
 *        loaded.
 */
o3djs.loader.Loader = function(onFinished)  {
  this.count_ = 1;
  this.onFinished_ = onFinished;

  /**
   * The LoadInfo for this loader you can use to track progress.
   * @type {!o3djs.io.LoadInfo}
   */
  this.loadInfo = o3djs.io.createLoadInfo();
};

/**
 * Creates a Loader for helping to load a bunch of items asychronously.
 *
 * The way you use this is as follows.
 *
 *

 * var loader = o3djs.loader.createLoader(myFinishedCallback);
 * loader.loadTexture(pack, texture1Url, callbackForTexture);
 * loader.loadTexture(pack, texture2Url, callbackForTexture);
 * loader.loadTexture(pack, texture3Url, callbackForTexture);
 * loader.finish();
 *

 *
 * The loader guarantees that myFinishedCallback will be called after
 * all the items have been loaded.
 *
* @param {!function(): void} onFinished Function to call when final item has
*        loaded.
* @return {!o3djs.loader.Loader} A Loader Object.
 */
o3djs.loader.createLoader = function(onFinished) {
  return new o3djs.loader.Loader(onFinished);
};

/**
 * Loads a texture.
 * @param {!o3d.Pack} pack Pack to load texture into.
 * @param {string} url URL of texture to load.
 * @param {!function(o3d.Texture, *): void} opt_onTextureLoaded
 *     optional callback when texture is loaded. It will be passed the texture
 *     and an exception which is null on success.
 */
o3djs.loader.Loader.prototype.loadTexture = function(pack,
                                                     url,
                                                     opt_onTextureLoaded) {
  var that = this;  // so the function below can see "this".
  ++this.count_;
  var loadInfo = o3djs.io.loadTexture(pack, url, function(texture, exception) {
    if (opt_onTextureLoaded) {
      opt_onTextureLoaded(texture, exception);
    }
    that.countDown_();
  });
  this.loadInfo.addChild(loadInfo);
};

/**
 * Loads a 3d scene.
 * @param {!o3d.Client} client An O3D client object.
 * @param {!o3d.Pack} pack Pack to load texture into.
 * @param {!o3d.Transform} parent Transform to parent scene under.
 * @param {string} url URL of scene to load.
 * @param {!function(!o3d.Pack, !o3d.Transform, *): void}
 *     opt_onSceneLoaded optional callback when scene is loaded. It will be
 *     passed the pack and parent and an exception which is null on success.
 */
o3djs.loader.Loader.prototype.loadScene = function(client,
                                                   pack,
                                                   parent,
                                                   url,
                                                   opt_onSceneLoaded) {
  var that = this;  // so the function below can see "this".
  ++this.count_;
  var loadInfo = o3djs.scene.loadScene(
      client, pack, parent, url, function(pack, parent, exception) {
    if (opt_onSceneLoaded) {
      opt_onSceneLoaded(pack, parent, exception);
    }
    that.countDown_();
  });
  this.loadInfo.addChild(loadInfo);
};

/**
 * Loads a text file.
 * @param {string} url URL of scene to load.
 * @param {!function(string, *): void} onTextLoaded Function to call when
 *     the file is loaded. It will be passed the contents of the file as a
 *     string and an exception which is null on success.
 */
o3djs.loader.Loader.prototype.loadTextFile = function(url, onTextLoaded) {
  var that = this;  // so the function below can see "this".
  ++this.count_;
  var loadInfo = o3djs.io.loadTextFile(url, function(string, exception) {
    onTextLoaded(string, exception);
    that.countDown_();
  });
  this.loadInfo.addChild(loadInfo);
};

/**
 * Creates a loader that is tracked by this loader so that when the new loader
 * is finished it will be reported to this loader.
 * @param {!function(): void} onFinished Function to be called when everything
 *      loaded with this loader has finished.
 * @return {!o3djs.loader.Loader} The new Loader.
 */
o3djs.loader.Loader.prototype.createLoader = function(onFinished) {
  var that = this;
  ++this.count_;
  var loader = o3djs.loader.createLoader(function() {
      onFinished();
      that.countDown_();
  });
  this.loadInfo.addChild(loader.loadInfo);
  return loader;
};

/**
 * Counts down the internal count and if it gets to zero calls the callback.
 * @private
 */
o3djs.loader.Loader.prototype.countDown_ = function() {
  --this.count_;
  if (this.count_ === 0) {
    this.onFinished_();
  }
};

/**
 * Finishes the loading process.
 * Actually this just calls countDown_ to account for the count starting at 1.
 */
o3djs.loader.Loader.prototype.finish = function() {
  this.countDown_();
};

<commit_msg>Fix o3djs.loader.loadScene so it has opt_options argument.<commit_after>/*
 * Copyright 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. 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
 * OWNER 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.
 */

/**
 * @fileoverview This file contains a loader class for helping to load
 *     muliple assets in an asynchronous manner.
 */

o3djs.provide('o3djs.loader');

o3djs.require('o3djs.io');
o3djs.require('o3djs.scene');

/**
 * A Module with a loader class for helping to load muliple assets in an
 * asynchronous manner.
 * @namespace
 */
o3djs.loader = o3djs.loader || {};

/**
 * A simple Loader class to call some callback when everything has loaded.
 * @constructor
 * @param {!function(): void} onFinished Function to call when final item has
 *        loaded.
 */
o3djs.loader.Loader = function(onFinished)  {
  this.count_ = 1;
  this.onFinished_ = onFinished;

  /**
   * The LoadInfo for this loader you can use to track progress.
   * @type {!o3djs.io.LoadInfo}
   */
  this.loadInfo = o3djs.io.createLoadInfo();
};

/**
 * Creates a Loader for helping to load a bunch of items asychronously.
 *
 * The way you use this is as follows.
 *
 *

 * var loader = o3djs.loader.createLoader(myFinishedCallback);
 * loader.loadTexture(pack, texture1Url, callbackForTexture);
 * loader.loadTexture(pack, texture2Url, callbackForTexture);
 * loader.loadTexture(pack, texture3Url, callbackForTexture);
 * loader.finish();
 *

 *
 * The loader guarantees that myFinishedCallback will be called after
 * all the items have been loaded.
 *
* @param {!function(): void} onFinished Function to call when final item has
*        loaded.
* @return {!o3djs.loader.Loader} A Loader Object.
 */
o3djs.loader.createLoader = function(onFinished) {
  return new o3djs.loader.Loader(onFinished);
};

/**
 * Loads a texture.
 * @param {!o3d.Pack} pack Pack to load texture into.
 * @param {string} url URL of texture to load.
 * @param {!function(o3d.Texture, *): void} opt_onTextureLoaded
 *     optional callback when texture is loaded. It will be passed the texture
 *     and an exception which is null on success.
 */
o3djs.loader.Loader.prototype.loadTexture = function(pack,
                                                     url,
                                                     opt_onTextureLoaded) {
  var that = this;  // so the function below can see "this".
  ++this.count_;
  var loadInfo = o3djs.io.loadTexture(pack, url, function(texture, exception) {
    if (opt_onTextureLoaded) {
      opt_onTextureLoaded(texture, exception);
    }
    that.countDown_();
  });
  this.loadInfo.addChild(loadInfo);
};

/**
 * Loads a 3d scene.
 * @param {!o3d.Client} client An O3D client object.
 * @param {!o3d.Pack} pack Pack to load texture into.
 * @param {!o3d.Transform} parent Transform to parent scene under.
 * @param {string} url URL of scene to load.
 * @param {!o3djs.serialization.Options} opt_options Options passed into the
 *     loader.
 * @param {!function(!o3d.Pack, !o3d.Transform, *): void}
 *     opt_onSceneLoaded optional callback when scene is loaded. It will be
 *     passed the pack and parent and an exception which is null on success.
 */
o3djs.loader.Loader.prototype.loadScene = function(client,
                                                   pack,
                                                   parent,
                                                   url,
                                                   opt_onSceneLoaded,
                                                   opt_options) {
  var that = this;  // so the function below can see "this".
  ++this.count_;
  var loadInfo = o3djs.scene.loadScene(
      client, pack, parent, url, function(pack, parent, exception) {
        if (opt_onSceneLoaded) {
          opt_onSceneLoaded(pack, parent, exception);
        }
        that.countDown_();
      },
      opt_options);
  this.loadInfo.addChild(loadInfo);
};

/**
 * Loads a text file.
 * @param {string} url URL of scene to load.
 * @param {!function(string, *): void} onTextLoaded Function to call when
 *     the file is loaded. It will be passed the contents of the file as a
 *     string and an exception which is null on success.
 */
o3djs.loader.Loader.prototype.loadTextFile = function(url, onTextLoaded) {
  var that = this;  // so the function below can see "this".
  ++this.count_;
  var loadInfo = o3djs.io.loadTextFile(url, function(string, exception) {
    onTextLoaded(string, exception);
    that.countDown_();
  });
  this.loadInfo.addChild(loadInfo);
};

/**
 * Creates a loader that is tracked by this loader so that when the new loader
 * is finished it will be reported to this loader.
 * @param {!function(): void} onFinished Function to be called when everything
 *      loaded with this loader has finished.
 * @return {!o3djs.loader.Loader} The new Loader.
 */
o3djs.loader.Loader.prototype.createLoader = function(onFinished) {
  var that = this;
  ++this.count_;
  var loader = o3djs.loader.createLoader(function() {
      onFinished();
      that.countDown_();
  });
  this.loadInfo.addChild(loader.loadInfo);
  return loader;
};

/**
 * Counts down the internal count and if it gets to zero calls the callback.
 * @private
 */
o3djs.loader.Loader.prototype.countDown_ = function() {
  --this.count_;
  if (this.count_ === 0) {
    this.onFinished_();
  }
};

/**
 * Finishes the loading process.
 * Actually this just calls countDown_ to account for the count starting at 1.
 */
o3djs.loader.Loader.prototype.finish = function() {
  this.countDown_();
};

<|endoftext|>