<commit_before>const React = require('react');

const Button = require('./Button');
const Icon = require('./Icon');

const StyleConstants = require('../constants/Style');

const Modal = React.createClass({
  propTypes: {
    buttons: React.PropTypes.arrayOf(React.PropTypes.shape({
      actionText: React.PropTypes.string,
      className: React.PropTypes.string,
      isActive: React.PropTypes.bool,
      icon: React.PropTypes.string,
      label: React.PropTypes.string,
      onClick: React.PropTypes.func,
      primaryColor: React.PropTypes.string,
      style: React.PropTypes.object,
      type: React.PropTypes.oneOf(['primary', 'secondary'])
    })),
    color: React.PropTypes.string,
    contentStyle: React.PropTypes.object,
    footerContent: React.PropTypes.node,
    footerStyle: React.PropTypes.oneOfType([
      React.PropTypes.array,
      React.PropTypes.object
    ]),
    isRelative: React.PropTypes.bool,
    onRequestClose: React.PropTypes.func,
    showFooter: React.PropTypes.bool,
    showTitleBar: React.PropTypes.bool,
    style: React.PropTypes.object,
    title: React.PropTypes.string,
    tooltip: React.PropTypes.string,
    tooltipLabel: React.PropTypes.string,
    tooltipTitle: React.PropTypes.string
  },

  getDefaultProps () {
    return {
      buttons: [],
      color: StyleConstants.Colors.PRIMARY,
      isRelative: false,
      showFooter: false,
      showTitleBar: false,
      title: '',
      tooltip: null,
      tooltipLabel: '',
      tooltipTitle: null
    };
  },

  getInitialState () {
    return {
      showTooltip: false
    };
  },

  componentDidMount () {
  /*eslint-disable */
    if (this.props.hasOwnProperty('isOpen')) {
      console.warn('WARNING: The prop "isOpen" is deprecated in this version of the component. Please handle Modal opening from its parent.');
    }
  /*eslint-enable */
  },

  _handleTooltipToggle (show) {
    this.setState({
      showTooltip: show
    });
  },

  _renderTitleBar () {
    if (this.props.showTitleBar) {
      const styles = this.styles();

      return (

          {this.props.title}

      );
    } else {
      return null;
    }
  },

  _renderFooter () {
    if (this.props.showFooter) {
      const styles = this.styles();

      return (

          {this._renderTooltipIconAndLabel()}
          {this._renderFooterContent()}

            {this.props.buttons.map((button, i) => {
              return (
                <Button
                  actionText={button.actionText}
                  className={'mx-modal-button ' + button.className}
                  icon={button.icon}
                  isActive={button.isActive}
                  key={button.type + i}
                  onClick={button.onClick}
                  primaryColor={button.primaryColor}
                  style={Object.assign({}, styles.button, button.style)}
                  type={button.type}
                >
                  {button.label}
                </Button>
              );
            })}

      );
    } else {
      return null;
    }
  },

  _renderFooterContent () {
    const styles = this.styles();

    return (

        {this.props.footerContent}

    );
  },

  _renderTooltip () {
    if (this.state.showTooltip) {
      const styles = this.styles();

      return (

            {this.props.tooltipTitle}

            {this.props.tooltip}

      );
    } else {
      return null;
    }
  },

  _renderTooltipIconAndLabel () {
    if (this.props.tooltip) {
      const styles = this.styles();

      return (

          <Icon
            className='mx-modal-tooltip-label-icon'
            onMouseOut={this._handleTooltipToggle.bind(null, false)}
            onMouseOver={this._handleTooltipToggle.bind(null, true)}
            size={18}
            style={{ color: this.props.color }}
            type='info'
          />

            {this.props.tooltipLabel}

      );
    } else {
      return null;
    }
  },

  render () {
    const styles = this.styles();

    return (

          <Icon
            className='mx-modal-close'
            onClick={this.props.onRequestClose}
            size={24}
            style={styles.close}
            type='close-solid'
          />
          {this._renderTitleBar()}

            {this.props.children}
            {this._renderTooltip()}

          {this._renderFooter()}

    );
  },

  styles () {
    return {
      scrim: {
        zIndex: 1000,
        position: 'fixed',
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        textAlign: 'center'
      },
      relative: {
        position: 'absolute'
      },
      overlay: {
        backgroundColor: this.props.showScrim ? StyleConstants.Colors.SCRIM : 'transparent'
      },
      close: {
        position: 'absolute',
        top: 0,
        right: 0,
        margin: '-12px -12px 0 0',
        cursor: 'pointer',
        color: StyleConstants.Colors.CHARCOAL
      },
      container: {
        fontFamily: StyleConstants.FontFamily,
        boxSizing: 'border-box',
        position: 'relative',
        zIndex: 1001,
        backgroundColor: StyleConstants.Colors.WHITE,
        boxShadow: StyleConstants.ShadowHigh,
        borderRadius: 2,
        top: 20,
        maxWidth: 'calc(100% - 40px)',
        display: 'inline-block',
        textAlign: 'left'
      },
      titleBar: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderTopLeftRadius: 2,
        borderTopRightRadius: 2,
        padding: '15px 20px',
        color: StyleConstants.Colors.ASH,
        fontSize: StyleConstants.FontSizes.SMALL,
        textTransform: 'uppercase'
      },
      content: {
        position: 'relative',
        maxHeight: 'calc(100% - 140px)',
        overflow: 'auto'
      },
      footer: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderBottomLeftRadius: 2,
        borderBottomRightRadius: 2,
        padding: '10px 20px',
        display: 'flex',
        justifyContent: 'space-between'
      },
      footerContent: {
        padding: '5px 0',
        textAlign: 'left'
      },
      tooltipLabel: {
        padding: '5px 0'
      },
      tooltipLabelText: {
        fontSize: StyleConstants.FontSizes.SMALL
      },
      tooltip: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderColor: StyleConstants.Colors.FOG,
        borderStyle: 'solid',
        borderWidth: 1,
        boxSizing: 'border-box',
        bottom: 10,
        left: 10,
        position: 'absolute',
        width: 250,
        maxWidth: '100%',
        padding: 10
      },
      tooltipTitle: {
        fontSize: StyleConstants.FontSizes.MEDIUM,
        marginBottom: 5
      },
      tooltipContent: {
        color: StyleConstants.Colors.ASH,
        fontSize: StyleConstants.FontSizes.SMALL,
        lineHeight: '1.5em',
        textAlign: 'left'
      },
      buttons: {
        textAlign: 'right'
      },
      button: {
        marginLeft: 5
      },
      small: {
        width: 400,
        textAlign: 'center'
      }
    };
  }
});

module.exports = Modal;<commit_msg>footerStyle prop validation correction<commit_after>const React = require('react');

const Button = require('./Button');
const Icon = require('./Icon');

const StyleConstants = require('../constants/Style');

const Modal = React.createClass({
  propTypes: {
    buttons: React.PropTypes.arrayOf(React.PropTypes.shape({
      actionText: React.PropTypes.string,
      className: React.PropTypes.string,
      isActive: React.PropTypes.bool,
      icon: React.PropTypes.string,
      label: React.PropTypes.string,
      onClick: React.PropTypes.func,
      primaryColor: React.PropTypes.string,
      style: React.PropTypes.object,
      type: React.PropTypes.oneOf(['primary', 'secondary'])
    })),
    color: React.PropTypes.string,
    contentStyle: React.PropTypes.object,
    footerContent: React.PropTypes.node,
    footerStyle: React.PropTypes.object,
    isRelative: React.PropTypes.bool,
    onRequestClose: React.PropTypes.func,
    showFooter: React.PropTypes.bool,
    showTitleBar: React.PropTypes.bool,
    style: React.PropTypes.object,
    title: React.PropTypes.string,
    tooltip: React.PropTypes.string,
    tooltipLabel: React.PropTypes.string,
    tooltipTitle: React.PropTypes.string
  },

  getDefaultProps () {
    return {
      buttons: [],
      color: StyleConstants.Colors.PRIMARY,
      isRelative: false,
      showFooter: false,
      showTitleBar: false,
      title: '',
      tooltip: null,
      tooltipLabel: '',
      tooltipTitle: null
    };
  },

  getInitialState () {
    return {
      showTooltip: false
    };
  },

  componentDidMount () {
  /*eslint-disable */
    if (this.props.hasOwnProperty('isOpen')) {
      console.warn('WARNING: The prop "isOpen" is deprecated in this version of the component. Please handle Modal opening from its parent.');
    }
  /*eslint-enable */
  },

  _handleTooltipToggle (show) {
    this.setState({
      showTooltip: show
    });
  },

  _renderTitleBar () {
    if (this.props.showTitleBar) {
      const styles = this.styles();

      return (

          {this.props.title}

      );
    } else {
      return null;
    }
  },

  _renderFooter () {
    if (this.props.showFooter) {
      const styles = this.styles();

      return (

          {this._renderTooltipIconAndLabel()}
          {this._renderFooterContent()}

            {this.props.buttons.map((button, i) => {
              return (
                <Button
                  actionText={button.actionText}
                  className={'mx-modal-button ' + button.className}
                  icon={button.icon}
                  isActive={button.isActive}
                  key={button.type + i}
                  onClick={button.onClick}
                  primaryColor={button.primaryColor}
                  style={Object.assign({}, styles.button, button.style)}
                  type={button.type}
                >
                  {button.label}
                </Button>
              );
            })}

      );
    } else {
      return null;
    }
  },

  _renderFooterContent () {
    const styles = this.styles();

    return (

        {this.props.footerContent}

    );
  },

  _renderTooltip () {
    if (this.state.showTooltip) {
      const styles = this.styles();

      return (

            {this.props.tooltipTitle}

            {this.props.tooltip}

      );
    } else {
      return null;
    }
  },

  _renderTooltipIconAndLabel () {
    if (this.props.tooltip) {
      const styles = this.styles();

      return (

          <Icon
            className='mx-modal-tooltip-label-icon'
            onMouseOut={this._handleTooltipToggle.bind(null, false)}
            onMouseOver={this._handleTooltipToggle.bind(null, true)}
            size={18}
            style={{ color: this.props.color }}
            type='info'
          />

            {this.props.tooltipLabel}

      );
    } else {
      return null;
    }
  },

  render () {
    const styles = this.styles();

    return (

          <Icon
            className='mx-modal-close'
            onClick={this.props.onRequestClose}
            size={24}
            style={styles.close}
            type='close-solid'
          />
          {this._renderTitleBar()}

            {this.props.children}
            {this._renderTooltip()}

          {this._renderFooter()}

    );
  },

  styles () {
    return {
      scrim: {
        zIndex: 1000,
        position: 'fixed',
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        textAlign: 'center'
      },
      relative: {
        position: 'absolute'
      },
      overlay: {
        backgroundColor: this.props.showScrim ? StyleConstants.Colors.SCRIM : 'transparent'
      },
      close: {
        position: 'absolute',
        top: 0,
        right: 0,
        margin: '-12px -12px 0 0',
        cursor: 'pointer',
        color: StyleConstants.Colors.CHARCOAL
      },
      container: {
        fontFamily: StyleConstants.FontFamily,
        boxSizing: 'border-box',
        position: 'relative',
        zIndex: 1001,
        backgroundColor: StyleConstants.Colors.WHITE,
        boxShadow: StyleConstants.ShadowHigh,
        borderRadius: 2,
        top: 20,
        maxWidth: 'calc(100% - 40px)',
        display: 'inline-block',
        textAlign: 'left'
      },
      titleBar: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderTopLeftRadius: 2,
        borderTopRightRadius: 2,
        padding: '15px 20px',
        color: StyleConstants.Colors.ASH,
        fontSize: StyleConstants.FontSizes.SMALL,
        textTransform: 'uppercase'
      },
      content: {
        position: 'relative',
        maxHeight: 'calc(100% - 140px)',
        overflow: 'auto'
      },
      footer: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderBottomLeftRadius: 2,
        borderBottomRightRadius: 2,
        padding: '10px 20px',
        display: 'flex',
        justifyContent: 'space-between'
      },
      footerContent: {
        padding: '5px 0',
        textAlign: 'left'
      },
      tooltipLabel: {
        padding: '5px 0'
      },
      tooltipLabelText: {
        fontSize: StyleConstants.FontSizes.SMALL
      },
      tooltip: {
        backgroundColor: StyleConstants.Colors.PORCELAIN,
        borderColor: StyleConstants.Colors.FOG,
        borderStyle: 'solid',
        borderWidth: 1,
        boxSizing: 'border-box',
        bottom: 10,
        left: 10,
        position: 'absolute',
        width: 250,
        maxWidth: '100%',
        padding: 10
      },
      tooltipTitle: {
        fontSize: StyleConstants.FontSizes.MEDIUM,
        marginBottom: 5
      },
      tooltipContent: {
        color: StyleConstants.Colors.ASH,
        fontSize: StyleConstants.FontSizes.SMALL,
        lineHeight: '1.5em',
        textAlign: 'left'
      },
      buttons: {
        textAlign: 'right'
      },
      button: {
        marginLeft: 5
      },
      small: {
        width: 400,
        textAlign: 'center'
      }
    };
  }
});

module.exports = Modal;<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * The global object.
 * @type {!Object}
 * @const
 */
var global = this;

/** Platform, package, object property, and Event support. **/
this.cr = (function() {
  'use strict';

  /**
   * Builds an object structure for the provided namespace path,
   * ensuring that names that already exist are not overwritten. For
   * example:
   * "a.b.c" -> a = {};a.b={};a.b.c={};
   * @param {string} name Name of the object that this file defines.
   * @param {*=} opt_object The object to expose at the end of the path.
   * @param {Object=} opt_objectToExportTo The object to add the path to;
   *     default is {@code global}.
   * @private
   */
  function exportPath(name, opt_object, opt_objectToExportTo) {
    var parts = name.split('.');
    var cur = opt_objectToExportTo || global;

    for (var part; parts.length && (part = parts.shift());) {
      if (!parts.length && opt_object !== undefined) {
        // last part and we have an object; use it
        cur[part] = opt_object;
      } else if (part in cur) {
        cur = cur[part];
      } else {
        cur = cur[part] = {};
      }
    }
    return cur;
  };

  /**
   * Fires a property change event on the target.
   * @param {EventTarget} target The target to dispatch the event on.
   * @param {string} propertyName The name of the property that changed.
   * @param {*} newValue The new value for the property.
   * @param {*} oldValue The old value for the property.
   */
  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
    var e = new Event(propertyName + 'Change');
    e.propertyName = propertyName;
    e.newValue = newValue;
    e.oldValue = oldValue;
    target.dispatchEvent(e);
  }

  /**
   * Converts a camelCase javascript property name to a hyphenated-lower-case
   * attribute name.
   * @param {string} jsName The javascript camelCase property name.
   * @return {string} The equivalent hyphenated-lower-case attribute name.
   */
  function getAttributeName(jsName) {
    return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
  }

  /**
   * The kind of property to define in {@code defineProperty}.
   * @enum {number}
   * @const
   */
  var PropertyKind = {
    /**
     * Plain old JS property where the backing data is stored as a "private"
     * field on the object.
     */
    JS: 'js',

    /**
     * The property backing data is stored as an attribute on an element.
     */
    ATTR: 'attr',

    /**
     * The property backing data is stored as an attribute on an element. If the
     * element has the attribute then the value is true.
     */
    BOOL_ATTR: 'boolAttr'
  };

  /**
   * Helper function for defineProperty that returns the getter to use for the
   * property.
   * @param {string} name The name of the property.
   * @param {cr.PropertyKind} kind The kind of the property.
   * @return {function():*} The getter for the property.
   */
  function getGetter(name, kind) {
    switch (kind) {
      case PropertyKind.JS:
        var privateName = name + '_';
        return function() {
          return this[privateName];
        };
      case PropertyKind.ATTR:
        var attributeName = getAttributeName(name);
        return function() {
          return this.getAttribute(attributeName);
        };
      case PropertyKind.BOOL_ATTR:
        var attributeName = getAttributeName(name);
        return function() {
          return this.hasAttribute(attributeName);
        };
    }
  }

  /**
   * Helper function for defineProperty that returns the setter of the right
   * kind.
   * @param {string} name The name of the property we are defining the setter
   *     for.
   * @param {cr.PropertyKind} kind The kind of property we are getting the
   *     setter for.
   * @param {function(*):void} opt_setHook A function to run after the property
   *     is set, but before the propertyChange event is fired.
   * @return {function(*):void} The function to use as a setter.
   */
  function getSetter(name, kind, opt_setHook) {
    switch (kind) {
      case PropertyKind.JS:
        var privateName = name + '_';
        return function(value) {
          var oldValue = this[name];
          if (value !== oldValue) {
            this[privateName] = value;
            if (opt_setHook)
              opt_setHook.call(this, value, oldValue);
            dispatchPropertyChange(this, name, value, oldValue);
          }
        };

      case PropertyKind.ATTR:
        var attributeName = getAttributeName(name);
        return function(value) {
          var oldValue = this[name];
          if (value !== oldValue) {
            if (value == undefined)
              this.removeAttribute(attributeName);
            else
              this.setAttribute(attributeName, value);
            if (opt_setHook)
              opt_setHook.call(this, value, oldValue);
            dispatchPropertyChange(this, name, value, oldValue);
          }
        };

      case PropertyKind.BOOL_ATTR:
        var attributeName = getAttributeName(name);
        return function(value) {
          var oldValue = this[name];
          if (value !== oldValue) {
            if (value)
              this.setAttribute(attributeName, name);
            else
              this.removeAttribute(attributeName);
            if (opt_setHook)
              opt_setHook.call(this, value, oldValue);
            dispatchPropertyChange(this, name, value, oldValue);
          }
        };
    }
  }

  /**
   * Defines a property on an object. When the setter changes the value a
   * property change event with the type {@code name + 'Change'} is fired.
   * @param {!Object} obj The object to define the property for.
   * @param {string} name The name of the property.
   * @param {cr.PropertyKind=} opt_kind What kind of underlying storage to use.
   * @param {function(*):void} opt_setHook A function to run after the
   *     property is set, but before the propertyChange event is fired.
   */
  function defineProperty(obj, name, opt_kind, opt_setHook) {
    if (typeof obj == 'function')
      obj = obj.prototype;

    var kind = opt_kind || PropertyKind.JS;

    if (!obj.__lookupGetter__(name))
      obj.__defineGetter__(name, getGetter(name, kind));

    if (!obj.__lookupSetter__(name))
      obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
  }

  /**
   * Counter for use with createUid
   */
  var uidCounter = 1;

  /**
   * @return {number} A new unique ID.
   */
  function createUid() {
    return uidCounter++;
  }

  /**
   * Returns a unique ID for the item. This mutates the item so it needs to be
   * an object
   * @param {!Object} item The item to get the unique ID for.
   * @return {number} The unique ID for the item.
   */
  function getUid(item) {
    if (item.hasOwnProperty('uid'))
      return item.uid;
    return item.uid = createUid();
  }

  /**
   * Dispatches a simple event on an event target.
   * @param {!EventTarget} target The event target to dispatch the event on.
   * @param {string} type The type of the event.
   * @param {boolean=} opt_bubbles Whether the event bubbles or not.
   * @param {boolean=} opt_cancelable Whether the default action of the event
   *     can be prevented. Default is true.
   * @return {boolean} If any of the listeners called {@code preventDefault}
   *     during the dispatch this will return false.
   */
  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
    var e = new Event(type, {
      bubbles: opt_bubbles,
      cancelable: opt_cancelable === undefined || opt_cancelable
    });
    return target.dispatchEvent(e);
  }

  /**
   * Calls |fun| and adds all the fields of the returned object to the object
   * named by |name|. For example, cr.define('cr.ui', function() {
   *   function List() {
   *     ...
   *   }
   *   function ListItem() {
   *     ...
   *   }
   *   return {
   *     List: List,
   *     ListItem: ListItem,
   *   };
   * });
   * defines the functions cr.ui.List and cr.ui.ListItem.
   * @param {string} name The name of the object that we are adding fields to.
   * @param {!Function} fun The function that will return an object containing
   *     the names and values of the new fields.
   */
  function define(name, fun) {
    var obj = exportPath(name);
    var exports = fun();
    for (var propertyName in exports) {
      // Maybe we should check the prototype chain here? The current usage
      // pattern is always using an object literal so we only care about own
      // properties.
      var propertyDescriptor = Object.getOwnPropertyDescriptor(exports,
                                                               propertyName);
      if (propertyDescriptor)
        Object.defineProperty(obj, propertyName, propertyDescriptor);
    }
  }

  /**
   * Adds a {@code getInstance} static method that always return the same
   * instance object.
   * @param {!Function} ctor The constructor for the class to add the static
   *     method to.
   */
  function addSingletonGetter(ctor) {
    ctor.getInstance = function() {
      return ctor.instance_ || (ctor.instance_ = new ctor());
    };
  }

  /**
   * Initialization which must be deferred until run-time.
   */
  function initialize() {
    // If 'document' isn't defined, then we must be being pre-compiled,
    // so set a trap so that we're initialized on first access at run-time.
    if (!global.document) {
      var originalCr = cr;

      Object.defineProperty(global, 'cr', {
        get: function() {
          Object.defineProperty(global, 'cr', {value: originalCr});
          originalCr.initialize();
          return originalCr;
        },
        configurable: true
      });

      return;
    }

    cr.doc = document;

    /**
     * Whether we are using a Mac or not.
     */
    cr.isMac = /Mac/.test(navigator.platform);

    /**
     * Whether this is on the Windows platform or not.
     */
    cr.isWindows = /Win/.test(navigator.platform);

    /**
     * Whether this is on chromeOS or not.
     */
    cr.isChromeOS = /CrOS/.test(navigator.userAgent);

    /**
     * Whether this is on vanilla Linux (not chromeOS).
     */
    cr.isLinux = /Linux/.test(navigator.userAgent);

    /**
     * Whether this uses GTK or not.
     */
    cr.isGTK = typeof chrome.getVariableValue == 'function' &&
        /GTK/.test(chrome.getVariableValue('toolkit'));

    /**
     * Whether this uses the views toolkit or not.
     */
    cr.isViews = typeof chrome.getVariableValue == 'function' &&
        /views/.test(chrome.getVariableValue('toolkit'));
  }

  return {
    addSingletonGetter: addSingletonGetter,
    createUid: createUid,
    define: define,
    defineProperty: defineProperty,
    dispatchPropertyChange: dispatchPropertyChange,
    dispatchSimpleEvent: dispatchSimpleEvent,
    getUid: getUid,
    initialize: initialize,
    PropertyKind: PropertyKind
  };
})();

/**
 * TODO(kgr): Move this to another file which is to be loaded last.
 * This will be done as part of future work to make this code pre-compilable.
 */
cr.initialize();
<commit_msg>Remove cr.isGTK; it's not used any more.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * The global object.
 * @type {!Object}
 * @const
 */
var global = this;

/** Platform, package, object property, and Event support. **/
this.cr = (function() {
  'use strict';

  /**
   * Builds an object structure for the provided namespace path,
   * ensuring that names that already exist are not overwritten. For
   * example:
   * "a.b.c" -> a = {};a.b={};a.b.c={};
   * @param {string} name Name of the object that this file defines.
   * @param {*=} opt_object The object to expose at the end of the path.
   * @param {Object=} opt_objectToExportTo The object to add the path to;
   *     default is {@code global}.
   * @private
   */
  function exportPath(name, opt_object, opt_objectToExportTo) {
    var parts = name.split('.');
    var cur = opt_objectToExportTo || global;

    for (var part; parts.length && (part = parts.shift());) {
      if (!parts.length && opt_object !== undefined) {
        // last part and we have an object; use it
        cur[part] = opt_object;
      } else if (part in cur) {
        cur = cur[part];
      } else {
        cur = cur[part] = {};
      }
    }
    return cur;
  };

  /**
   * Fires a property change event on the target.
   * @param {EventTarget} target The target to dispatch the event on.
   * @param {string} propertyName The name of the property that changed.
   * @param {*} newValue The new value for the property.
   * @param {*} oldValue The old value for the property.
   */
  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
    var e = new Event(propertyName + 'Change');
    e.propertyName = propertyName;
    e.newValue = newValue;
    e.oldValue = oldValue;
    target.dispatchEvent(e);
  }

  /**
   * Converts a camelCase javascript property name to a hyphenated-lower-case
   * attribute name.
   * @param {string} jsName The javascript camelCase property name.
   * @return {string} The equivalent hyphenated-lower-case attribute name.
   */
  function getAttributeName(jsName) {
    return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
  }

  /**
   * The kind of property to define in {@code defineProperty}.
   * @enum {number}
   * @const
   */
  var PropertyKind = {
    /**
     * Plain old JS property where the backing data is stored as a "private"
     * field on the object.
     */
    JS: 'js',

    /**
     * The property backing data is stored as an attribute on an element.
     */
    ATTR: 'attr',

    /**
     * The property backing data is stored as an attribute on an element. If the
     * element has the attribute then the value is true.
     */
    BOOL_ATTR: 'boolAttr'
  };

  /**
   * Helper function for defineProperty that returns the getter to use for the
   * property.
   * @param {string} name The name of the property.
   * @param {cr.PropertyKind} kind The kind of the property.
   * @return {function():*} The getter for the property.
   */
  function getGetter(name, kind) {
    switch (kind) {
      case PropertyKind.JS:
        var privateName = name + '_';
        return function() {
          return this[privateName];
        };
      case PropertyKind.ATTR:
        var attributeName = getAttributeName(name);
        return function() {
          return this.getAttribute(attributeName);
        };
      case PropertyKind.BOOL_ATTR:
        var attributeName = getAttributeName(name);
        return function() {
          return this.hasAttribute(attributeName);
        };
    }
  }

  /**
   * Helper function for defineProperty that returns the setter of the right
   * kind.
   * @param {string} name The name of the property we are defining the setter
   *     for.
   * @param {cr.PropertyKind} kind The kind of property we are getting the
   *     setter for.
   * @param {function(*):void} opt_setHook A function to run after the property
   *     is set, but before the propertyChange event is fired.
   * @return {function(*):void} The function to use as a setter.
   */
  function getSetter(name, kind, opt_setHook) {
    switch (kind) {
      case PropertyKind.JS:
        var privateName = name + '_';
        return function(value) {
          var oldValue = this[name];
          if (value !== oldValue) {
            this[privateName] = value;
            if (opt_setHook)
              opt_setHook.call(this, value, oldValue);
            dispatchPropertyChange(this, name, value, oldValue);
          }
        };

      case PropertyKind.ATTR:
        var attributeName = getAttributeName(name);
        return function(value) {
          var oldValue = this[name];
          if (value !== oldValue) {
            if (value == undefined)
              this.removeAttribute(attributeName);
            else
              this.setAttribute(attributeName, value);
            if (opt_setHook)
              opt_setHook.call(this, value, oldValue);
            dispatchPropertyChange(this, name, value, oldValue);
          }
        };

      case PropertyKind.BOOL_ATTR:
        var attributeName = getAttributeName(name);
        return function(value) {
          var oldValue = this[name];
          if (value !== oldValue) {
            if (value)
              this.setAttribute(attributeName, name);
            else
              this.removeAttribute(attributeName);
            if (opt_setHook)
              opt_setHook.call(this, value, oldValue);
            dispatchPropertyChange(this, name, value, oldValue);
          }
        };
    }
  }

  /**
   * Defines a property on an object. When the setter changes the value a
   * property change event with the type {@code name + 'Change'} is fired.
   * @param {!Object} obj The object to define the property for.
   * @param {string} name The name of the property.
   * @param {cr.PropertyKind=} opt_kind What kind of underlying storage to use.
   * @param {function(*):void} opt_setHook A function to run after the
   *     property is set, but before the propertyChange event is fired.
   */
  function defineProperty(obj, name, opt_kind, opt_setHook) {
    if (typeof obj == 'function')
      obj = obj.prototype;

    var kind = opt_kind || PropertyKind.JS;

    if (!obj.__lookupGetter__(name))
      obj.__defineGetter__(name, getGetter(name, kind));

    if (!obj.__lookupSetter__(name))
      obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
  }

  /**
   * Counter for use with createUid
   */
  var uidCounter = 1;

  /**
   * @return {number} A new unique ID.
   */
  function createUid() {
    return uidCounter++;
  }

  /**
   * Returns a unique ID for the item. This mutates the item so it needs to be
   * an object
   * @param {!Object} item The item to get the unique ID for.
   * @return {number} The unique ID for the item.
   */
  function getUid(item) {
    if (item.hasOwnProperty('uid'))
      return item.uid;
    return item.uid = createUid();
  }

  /**
   * Dispatches a simple event on an event target.
   * @param {!EventTarget} target The event target to dispatch the event on.
   * @param {string} type The type of the event.
   * @param {boolean=} opt_bubbles Whether the event bubbles or not.
   * @param {boolean=} opt_cancelable Whether the default action of the event
   *     can be prevented. Default is true.
   * @return {boolean} If any of the listeners called {@code preventDefault}
   *     during the dispatch this will return false.
   */
  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
    var e = new Event(type, {
      bubbles: opt_bubbles,
      cancelable: opt_cancelable === undefined || opt_cancelable
    });
    return target.dispatchEvent(e);
  }

  /**
   * Calls |fun| and adds all the fields of the returned object to the object
   * named by |name|. For example, cr.define('cr.ui', function() {
   *   function List() {
   *     ...
   *   }
   *   function ListItem() {
   *     ...
   *   }
   *   return {
   *     List: List,
   *     ListItem: ListItem,
   *   };
   * });
   * defines the functions cr.ui.List and cr.ui.ListItem.
   * @param {string} name The name of the object that we are adding fields to.
   * @param {!Function} fun The function that will return an object containing
   *     the names and values of the new fields.
   */
  function define(name, fun) {
    var obj = exportPath(name);
    var exports = fun();
    for (var propertyName in exports) {
      // Maybe we should check the prototype chain here? The current usage
      // pattern is always using an object literal so we only care about own
      // properties.
      var propertyDescriptor = Object.getOwnPropertyDescriptor(exports,
                                                               propertyName);
      if (propertyDescriptor)
        Object.defineProperty(obj, propertyName, propertyDescriptor);
    }
  }

  /**
   * Adds a {@code getInstance} static method that always return the same
   * instance object.
   * @param {!Function} ctor The constructor for the class to add the static
   *     method to.
   */
  function addSingletonGetter(ctor) {
    ctor.getInstance = function() {
      return ctor.instance_ || (ctor.instance_ = new ctor());
    };
  }

  /**
   * Initialization which must be deferred until run-time.
   */
  function initialize() {
    // If 'document' isn't defined, then we must be being pre-compiled,
    // so set a trap so that we're initialized on first access at run-time.
    if (!global.document) {
      var originalCr = cr;

      Object.defineProperty(global, 'cr', {
        get: function() {
          Object.defineProperty(global, 'cr', {value: originalCr});
          originalCr.initialize();
          return originalCr;
        },
        configurable: true
      });

      return;
    }

    cr.doc = document;

    /**
     * Whether we are using a Mac or not.
     */
    cr.isMac = /Mac/.test(navigator.platform);

    /**
     * Whether this is on the Windows platform or not.
     */
    cr.isWindows = /Win/.test(navigator.platform);

    /**
     * Whether this is on chromeOS or not.
     */
    cr.isChromeOS = /CrOS/.test(navigator.userAgent);

    /**
     * Whether this is on vanilla Linux (not chromeOS).
     */
    cr.isLinux = /Linux/.test(navigator.userAgent);

    /**
     * Whether this uses the views toolkit or not.
     */
    cr.isViews = typeof chrome.getVariableValue == 'function' &&
        /views/.test(chrome.getVariableValue('toolkit'));
  }

  return {
    addSingletonGetter: addSingletonGetter,
    createUid: createUid,
    define: define,
    defineProperty: defineProperty,
    dispatchPropertyChange: dispatchPropertyChange,
    dispatchSimpleEvent: dispatchSimpleEvent,
    getUid: getUid,
    initialize: initialize,
    PropertyKind: PropertyKind
  };
})();

/**
 * TODO(kgr): Move this to another file which is to be loaded last.
 * This will be done as part of future work to make this code pre-compilable.
 */
cr.initialize();
<|endoftext|>


<commit_before>/* global NexT: true */

NexT.utils = NexT.$u = {
  /**
   * Wrap images with fancybox support.
   */
  wrapImageWithFancyBox: function () {
    $('.content img')
      .not('[hidden]')
      .not('.group-picture img, .post-gallery img')
      .each(function () {
        var $image = $(this);
        var imageTitle = $image.attr('title');
        var $imageWrapLink = $image.parent('a');

        if ($imageWrapLink.size() < 1) {
	        var imageLink = ($image.attr('data-original')) ? this.getAttribute('data-original') : this.getAttribute('src');
          $imageWrapLink = $image.wrap('').parent('a');
        }

        $imageWrapLink.addClass('fancybox fancybox.image');
        $imageWrapLink.attr('rel', 'group');

        if (imageTitle) {
          $imageWrapLink.append('
' + imageTitle + '
');

          //make sure img title tag will show correctly in fancybox
          $imageWrapLink.attr('title', imageTitle);
        }
      });

    $('.fancybox').fancybox({
      helpers: {
        overlay: {
          locked: false
        }
      }
    });
  },

  lazyLoadPostsImages: function () {
    $('#posts').find('img').lazyload({
      //placeholder: '/images/loading.gif',
      effect: 'fadeIn',
      threshold : 0
    });
  },

  /**
   * Tabs tag listener (without twitter bootstrap).
   */
  registerTabsTag: function () {
    var tNav = '.tabs ul.nav-tabs ';

    // Binding `nav-tabs` & `tab-content` by real time permalink changing.
    $(function() {
      $(window).bind('hashchange', function() {
        var tHash = location.hash;
        if (tHash !== '') {
          $(tNav + 'li:has(a[href="' + tHash + '"])').addClass('active').siblings().removeClass('active');
          $(tHash).addClass('active').siblings().removeClass('active');
        }
      }).trigger('hashchange');
    });

    $(tNav + '.tab').on('click', function (href) {
      href.preventDefault();
      // Prevent selected tab to select again.
      if(!$(this).hasClass('active')){

        // Add & Remove active class on `nav-tabs` & `tab-content`.
        $(this).addClass('active').siblings().removeClass('active');
        var tActive = $(this).find('a').attr('href');
        $(tActive).addClass('active').siblings().removeClass('active');

        // Clear location hash in browser if #permalink exists.
        if (location.hash !== '') {
          history.pushState('', document.title, window.location.pathname + window.location.search);
        }
      }
    });

  },

  registerESCKeyEvent: function () {
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        $('.search-popup').hide();
        $('.search-popup-overlay').remove();
        $('body').css('overflow', '');
      }
    });
  },

  registerBackToTop: function () {
    var THRESHOLD = 50;
    var $top = $('.back-to-top');

    $(window).on('scroll', function () {
      $top.toggleClass('back-to-top-on', window.pageYOffset > THRESHOLD);

      var scrollTop = $(window).scrollTop();
      var contentVisibilityHeight = NexT.utils.getContentVisibilityHeight();
      var scrollPercent = (scrollTop) / (contentVisibilityHeight);
      var scrollPercentRounded = Math.round(scrollPercent*100);
      var scrollPercentMaxed = (scrollPercentRounded > 100) ? 100 : scrollPercentRounded;
      $('#scrollpercent>span').html(scrollPercentMaxed);
    });

    $top.on('click', function () {
      $('body').velocity('scroll');
    });
  },

  /**
   * Transform embedded video to support responsive layout.
   * @see http://toddmotto.com/fluid-and-responsive-youtube-and-vimeo-videos-with-fluidvids-js/
   */
  embeddedVideoTransformer: function () {
    var $iframes = $('iframe');

    // Supported Players. Extend this if you need more players.
    var SUPPORTED_PLAYERS = [
      'www.youtube.com',
      'player.vimeo.com',
      'player.youku.com',
      'music.163.com',
      'www.tudou.com'
    ];
    var pattern = new RegExp( SUPPORTED_PLAYERS.join('|') );

    $iframes.each(function () {
      var iframe = this;
      var $iframe = $(this);
      var oldDimension = getDimension($iframe);
      var newDimension;

      if (this.src.search(pattern) > 0) {

        // Calculate the video ratio based on the iframe's w/h dimensions
        var videoRatio = getAspectRadio(oldDimension.width, oldDimension.height);

        // Replace the iframe's dimensions and position the iframe absolute
        // This is the trick to emulate the video ratio
        $iframe.width('100%').height('100%')
          .css({
            position: 'absolute',
            top: '0',
            left: '0'
          });

        // Wrap the iframe in a new
 which uses a dynamically fetched padding-top property
        // based on the video's w/h dimensions
        var wrap = document.createElement('div');
        wrap.className = 'fluid-vids';
        wrap.style.position = 'relative';
        wrap.style.marginBottom = '20px';
        wrap.style.width = '100%';
        wrap.style.paddingTop = videoRatio + '%';
        // Fix for appear inside tabs tag.
        (wrap.style.paddingTop === '') && (wrap.style.paddingTop = '50%');

        // Add the iframe inside our newly created

        var iframeParent = iframe.parentNode;
        iframeParent.insertBefore(wrap, iframe);
        wrap.appendChild(iframe);

        // Additional adjustments for 163 Music
        if (this.src.search('music.163.com') > 0) {
          newDimension = getDimension($iframe);
          var shouldRecalculateAspect = newDimension.width > oldDimension.width ||
                                        newDimension.height < oldDimension.height;

          // 163 Music Player has a fixed height, so we need to reset the aspect radio
          if (shouldRecalculateAspect) {
            wrap.style.paddingTop = getAspectRadio(newDimension.width, oldDimension.height) + '%';
          }
        }
      }
    });

    function getDimension($element) {
      return {
        width: $element.width(),
        height: $element.height()
      };
    }

    function getAspectRadio(width, height) {
      return height / width * 100;
    }
  },

  /**
   * Add `menu-item-active` class name to menu item
   * via comparing location.path with menu item's href.
   */
  addActiveClassToMenuItem: function () {
    var path = window.location.pathname;
    path = path === '/' ? path : path.substring(0, path.length - 1);
    $('.menu-item a[href^="' + path + '"]:first').parent().addClass('menu-item-active');
  },

  hasMobileUA: function () {
    var nav = window.navigator;
    var ua = nav.userAgent;
    var pa = /iPad|iPhone|Android|Opera Mini|BlackBerry|webOS|UCWEB|Blazer|PSP|IEMobile|Symbian/g;

    return pa.test(ua);
  },

  isTablet: function () {
    return window.screen.width < 992 && window.screen.width > 767 && this.hasMobileUA();
  },

  isMobile: function () {
    return window.screen.width < 767 && this.hasMobileUA();
  },

  isDesktop: function () {
    return !this.isTablet() && !this.isMobile();
  },

  /**
   * Escape meta symbols in jQuery selectors.
   *
   * @param selector
   * @returns {string|void|XML|*}
   */
  escapeSelector: function (selector) {
    return selector.replace(/[!"$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, '\\$&');
  },

  displaySidebar: function () {
    if (!this.isDesktop() || this.isPisces() || this.isGemini()) {
      return;
    }
    $('.sidebar-toggle').trigger('click');
  },

  isMist: function () {
    return CONFIG.scheme === 'Mist';
  },

  isPisces: function () {
    return CONFIG.scheme === 'Pisces';
  },

  isGemini: function () {
    return CONFIG.scheme === 'Gemini';
  },

  getScrollbarWidth: function () {
    var $div = $('
').addClass('scrollbar-measure').prependTo('body');
    var div = $div[0];
    var scrollbarWidth = div.offsetWidth - div.clientWidth;

    $div.remove();

    return scrollbarWidth;
  },

  getContentVisibilityHeight: function () {
    var docHeight = $('#content').height(),
        winHeight = $(window).height(),
        contentVisibilityHeight = (docHeight > winHeight) ? (docHeight - winHeight) : ($(document).height() - winHeight);

    return contentVisibilityHeight;
  },

  /**
   * Affix behaviour for Sidebar.
   *
   * @returns {Boolean}
   */
  needAffix: function () {
    return this.isPisces() || this.isGemini();
  }
};
<commit_msg>ADD: sidebar scrollable in all schemes [1].<commit_after>/* global NexT: true */

NexT.utils = NexT.$u = {
  /**
   * Wrap images with fancybox support.
   */
  wrapImageWithFancyBox: function () {
    $('.content img')
      .not('[hidden]')
      .not('.group-picture img, .post-gallery img')
      .each(function () {
        var $image = $(this);
        var imageTitle = $image.attr('title');
        var $imageWrapLink = $image.parent('a');

        if ($imageWrapLink.size() < 1) {
	        var imageLink = ($image.attr('data-original')) ? this.getAttribute('data-original') : this.getAttribute('src');
          $imageWrapLink = $image.wrap('').parent('a');
        }

        $imageWrapLink.addClass('fancybox fancybox.image');
        $imageWrapLink.attr('rel', 'group');

        if (imageTitle) {
          $imageWrapLink.append('
' + imageTitle + '
');

          //make sure img title tag will show correctly in fancybox
          $imageWrapLink.attr('title', imageTitle);
        }
      });

    $('.fancybox').fancybox({
      helpers: {
        overlay: {
          locked: false
        }
      }
    });
  },

  lazyLoadPostsImages: function () {
    $('#posts').find('img').lazyload({
      //placeholder: '/images/loading.gif',
      effect: 'fadeIn',
      threshold : 0
    });
  },

  /**
   * Tabs tag listener (without twitter bootstrap).
   */
  registerTabsTag: function () {
    var tNav = '.tabs ul.nav-tabs ';

    // Binding `nav-tabs` & `tab-content` by real time permalink changing.
    $(function() {
      $(window).bind('hashchange', function() {
        var tHash = location.hash;
        if (tHash !== '') {
          $(tNav + 'li:has(a[href="' + tHash + '"])').addClass('active').siblings().removeClass('active');
          $(tHash).addClass('active').siblings().removeClass('active');
        }
      }).trigger('hashchange');
    });

    $(tNav + '.tab').on('click', function (href) {
      href.preventDefault();
      // Prevent selected tab to select again.
      if(!$(this).hasClass('active')){

        // Add & Remove active class on `nav-tabs` & `tab-content`.
        $(this).addClass('active').siblings().removeClass('active');
        var tActive = $(this).find('a').attr('href');
        $(tActive).addClass('active').siblings().removeClass('active');

        // Clear location hash in browser if #permalink exists.
        if (location.hash !== '') {
          history.pushState('', document.title, window.location.pathname + window.location.search);
        }
      }
    });

  },

  registerESCKeyEvent: function () {
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        $('.search-popup').hide();
        $('.search-popup-overlay').remove();
        $('body').css('overflow', '');
      }
    });
  },

  registerBackToTop: function () {
    var THRESHOLD = 50;
    var $top = $('.back-to-top');

    $(window).on('scroll', function () {
      $top.toggleClass('back-to-top-on', window.pageYOffset > THRESHOLD);

      var scrollTop = $(window).scrollTop();
      var contentVisibilityHeight = NexT.utils.getContentVisibilityHeight();
      var scrollPercent = (scrollTop) / (contentVisibilityHeight);
      var scrollPercentRounded = Math.round(scrollPercent*100);
      var scrollPercentMaxed = (scrollPercentRounded > 100) ? 100 : scrollPercentRounded;
      $('#scrollpercent>span').html(scrollPercentMaxed);
    });

    $top.on('click', function () {
      $('body').velocity('scroll');
    });
  },

  /**
   * Transform embedded video to support responsive layout.
   * @see http://toddmotto.com/fluid-and-responsive-youtube-and-vimeo-videos-with-fluidvids-js/
   */
  embeddedVideoTransformer: function () {
    var $iframes = $('iframe');

    // Supported Players. Extend this if you need more players.
    var SUPPORTED_PLAYERS = [
      'www.youtube.com',
      'player.vimeo.com',
      'player.youku.com',
      'music.163.com',
      'www.tudou.com'
    ];
    var pattern = new RegExp( SUPPORTED_PLAYERS.join('|') );

    $iframes.each(function () {
      var iframe = this;
      var $iframe = $(this);
      var oldDimension = getDimension($iframe);
      var newDimension;

      if (this.src.search(pattern) > 0) {

        // Calculate the video ratio based on the iframe's w/h dimensions
        var videoRatio = getAspectRadio(oldDimension.width, oldDimension.height);

        // Replace the iframe's dimensions and position the iframe absolute
        // This is the trick to emulate the video ratio
        $iframe.width('100%').height('100%')
          .css({
            position: 'absolute',
            top: '0',
            left: '0'
          });

        // Wrap the iframe in a new
 which uses a dynamically fetched padding-top property
        // based on the video's w/h dimensions
        var wrap = document.createElement('div');
        wrap.className = 'fluid-vids';
        wrap.style.position = 'relative';
        wrap.style.marginBottom = '20px';
        wrap.style.width = '100%';
        wrap.style.paddingTop = videoRatio + '%';
        // Fix for appear inside tabs tag.
        (wrap.style.paddingTop === '') && (wrap.style.paddingTop = '50%');

        // Add the iframe inside our newly created

        var iframeParent = iframe.parentNode;
        iframeParent.insertBefore(wrap, iframe);
        wrap.appendChild(iframe);

        // Additional adjustments for 163 Music
        if (this.src.search('music.163.com') > 0) {
          newDimension = getDimension($iframe);
          var shouldRecalculateAspect = newDimension.width > oldDimension.width ||
                                        newDimension.height < oldDimension.height;

          // 163 Music Player has a fixed height, so we need to reset the aspect radio
          if (shouldRecalculateAspect) {
            wrap.style.paddingTop = getAspectRadio(newDimension.width, oldDimension.height) + '%';
          }
        }
      }
    });

    function getDimension($element) {
      return {
        width: $element.width(),
        height: $element.height()
      };
    }

    function getAspectRadio(width, height) {
      return height / width * 100;
    }
  },

  /**
   * Add `menu-item-active` class name to menu item
   * via comparing location.path with menu item's href.
   */
  addActiveClassToMenuItem: function () {
    var path = window.location.pathname;
    path = path === '/' ? path : path.substring(0, path.length - 1);
    $('.menu-item a[href^="' + path + '"]:first').parent().addClass('menu-item-active');
  },

  hasMobileUA: function () {
    var nav = window.navigator;
    var ua = nav.userAgent;
    var pa = /iPad|iPhone|Android|Opera Mini|BlackBerry|webOS|UCWEB|Blazer|PSP|IEMobile|Symbian/g;

    return pa.test(ua);
  },

  isTablet: function () {
    return window.screen.width < 992 && window.screen.width > 767 && this.hasMobileUA();
  },

  isMobile: function () {
    return window.screen.width < 767 && this.hasMobileUA();
  },

  isDesktop: function () {
    return !this.isTablet() && !this.isMobile();
  },

  /**
   * Escape meta symbols in jQuery selectors.
   *
   * @param selector
   * @returns {string|void|XML|*}
   */
  escapeSelector: function (selector) {
    return selector.replace(/[!"$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, '\\$&');
  },

  displaySidebar: function () {
    if (!this.isDesktop() || this.isPisces() || this.isGemini()) {
      return;
    }
    $('.sidebar-toggle').trigger('click');
  },

  isMist: function () {
    return CONFIG.scheme === 'Mist';
  },

  isPisces: function () {
    return CONFIG.scheme === 'Pisces';
  },

  isGemini: function () {
    return CONFIG.scheme === 'Gemini';
  },

  getScrollbarWidth: function () {
    var $div = $('
').addClass('scrollbar-measure').prependTo('body');
    var div = $div[0];
    var scrollbarWidth = div.offsetWidth - div.clientWidth;

    $div.remove();

    return scrollbarWidth;
  },

  getContentVisibilityHeight: function () {
    var docHeight = $('#content').height(),
        winHeight = $(window).height(),
        contentVisibilityHeight = (docHeight > winHeight) ? (docHeight - winHeight) : ($(document).height() - winHeight);
    return contentVisibilityHeight;
  },

  getSidebarSchemePadding: function () {
    var sidebarb2tHeight = ($('.back-to-top').css('display') == 'block') ? 0 : $('.back-to-top').height(),
        sidebarNavHeight = ($('.sidebar-nav').css('display') == 'block') ? $('.sidebar-nav').outerHeight(true) : 0,
        sidebarInner = $('.sidebar-inner'),
        sidebarPadding = sidebarInner.innerWidth() - sidebarInner.width(),
        sidebarSchemePadding = this.isPisces() || this.isGemini() ?
          ((sidebarPadding * 2) + sidebarNavHeight + (CONFIG.sidebar.offset * 2) + sidebarb2tHeight) :
          ((sidebarPadding * 2) + (sidebarNavHeight / 2));
    return sidebarSchemePadding;
  },

  /**
   * Affix behaviour for Sidebar.
   *
   * @returns {Boolean}
   */
//  needAffix: function () {
//    return this.isPisces() || this.isGemini();
//  }
};
<|endoftext|>


<commit_before>steal.plugins('jquery/event').then(function( $ ) {
	/**
	 * @add jQuery.event.special
	 */
	var resizers = $(),
		resizeCount = 0,
		// bind on the window window resizes to happen
		win = $(window),
		windowWidth = 0,
		windowHeight = 0,
		timer;

	$(function() {
		windowWidth = win.width();
		windowHeight = win.height();
	})

	/**
	 * @attribute resize
	 * @parent specialevents
	 *
	 * The resize event is useful for updating elements dimensions when a parent element
	 * has been resized.  It allows you to only resize elements that need to be resized
	 * in the 'right order'.
	 *
	 * By listening to a resize event, you will be alerted whenever a parent
	 * element has a resize event triggered on it.  For example:
	 *
	 *     $('#foo').bind('resize', function(){
	 *        // adjust #foo's dimensions
	 *     })
	 *
	 *     $(document.body).trigger("resize");
	 *
	 * ## The 'Right Order'
	 *
	 * When a control changes size, typically, you want only internal controls to have to adjust their
	 * dimensions.  Furthermore, you want to adjust controls from the 'outside-in', meaning
	 * that the outermost control adjusts its dimensions before child controls adjust theirs.
	 *
	 * Resize calls resize events in exactly this manner.
	 *
	 * When you trigger a resize event, it will propagate up the DOM until it reaches
	 * an element with the first resize event
	 * handler.  There it will move the event in the opposite direction, calling the element's
	 * children's resize event handlers.
	 *
	 * If your intent is to call resize without bubbling and only trigger child element's handlers,
	 * use the following:
	 *
	 *     $("#foo").trigger("resize", false);
	 *
	 * ## Stopping Children Updates
	 *
	 * If your element doesn't need to change it's dimensions as a result of the parent element, it should
	 * call ev.stopPropagation().  This will only stop resize from being sent to child elements of the current element.
	 *
	 *
	 */
	$.event.special.resize = {
		setup: function( handleObj ) {
			// add and sort the resizers array
			// don't add window because it can't be compared easily
			if ( this !== window ) {
				resizers.push(this);
				$.unique(resizers);
			}
			// returns false if the window
			return this !== window;
		},
		teardown: function() {
			// we shouldn't have to sort
			resizers = resizers.not(this);

			// returns false if the window
			return this !== window;
		},
		add: function( handleObj ) {
			// increment the number of resizer elements
			//$.data(this, "jquery.dom.resizers", ++$.data(this, "jquery.dom.resizers") );
			var origHandler = handleObj.handler;
			handleObj.origHandler = origHandler;

			handleObj.handler = function( ev, data ) {
				var isWindow = this === window;

				// if we are the window and a real resize has happened
				// then we check if the dimensions actually changed
				// if they did, we will wait a brief timeout and
				// trigger resize on the window
				// this is for IE, to prevent window resize 'infinate' loop issues
				if ( isWindow && ev.originalEvent ) {
					var width = win.width(),
						height = win.height();

					if ((width != windowWidth || height != windowHeight)) {
						//update the new dimensions
						windowWidth = width;
						windowHeight = height;
						clearTimeout(timer)
						timer = setTimeout(function() {
							win.trigger("resize");
						}, 1);

					}
					return;
				}

				// if this is the first handler for this event ...
				if ( resizeCount === 0 ) {
					// prevent others from doing what we are about to do
					resizeCount++;
					var where = data === false ? ev.target : this
					console.log(where, data);
					//trigger all this element's handlers
					$.event.handle.call(where, ev);
					if ( ev.isPropagationStopped() ) {
						resizeCount--;
						return;
					}

					// get all other elements within this element that listen to resize
					// and trigger their resize events
					var index = resizers.index(this),
						length = resizers.length,
						child, sub;

					// if index == -1 it's the window
					while (++index < length && (child = resizers[index]) && (isWindow || $.contains(where, child)) ) {

						// call the event
						$.event.handle.call(child, ev);

						if ( ev.isPropagationStopped() ) {
							// move index until the item is not in the current child
							while (++index < length && (sub = resizers[index]) ) {
								if (!$.contains(child, sub) ) {
									// set index back one
									index--;
									break
								}
							}
						}
					}

					// prevent others from responding
					ev.stopImmediatePropagation();
					resizeCount--;
				} else {
					handleObj.origHandler.call(this, ev, data);
				}
			}
		}
	};

	// automatically bind on these
	$([document, window]).bind('resize', function() {})
})<commit_msg>remove console log<commit_after>steal.plugins('jquery/event').then(function( $ ) {
	/**
	 * @add jQuery.event.special
	 */
	var resizers = $(),
		resizeCount = 0,
		// bind on the window window resizes to happen
		win = $(window),
		windowWidth = 0,
		windowHeight = 0,
		timer;

	$(function() {
		windowWidth = win.width();
		windowHeight = win.height();
	})

	/**
	 * @attribute resize
	 * @parent specialevents
	 *
	 * The resize event is useful for updating elements dimensions when a parent element
	 * has been resized.  It allows you to only resize elements that need to be resized
	 * in the 'right order'.
	 *
	 * By listening to a resize event, you will be alerted whenever a parent
	 * element has a resize event triggered on it.  For example:
	 *
	 *     $('#foo').bind('resize', function(){
	 *        // adjust #foo's dimensions
	 *     })
	 *
	 *     $(document.body).trigger("resize");
	 *
	 * ## The 'Right Order'
	 *
	 * When a control changes size, typically, you want only internal controls to have to adjust their
	 * dimensions.  Furthermore, you want to adjust controls from the 'outside-in', meaning
	 * that the outermost control adjusts its dimensions before child controls adjust theirs.
	 *
	 * Resize calls resize events in exactly this manner.
	 *
	 * When you trigger a resize event, it will propagate up the DOM until it reaches
	 * an element with the first resize event
	 * handler.  There it will move the event in the opposite direction, calling the element's
	 * children's resize event handlers.
	 *
	 * If your intent is to call resize without bubbling and only trigger child element's handlers,
	 * use the following:
	 *
	 *     $("#foo").trigger("resize", false);
	 *
	 * ## Stopping Children Updates
	 *
	 * If your element doesn't need to change it's dimensions as a result of the parent element, it should
	 * call ev.stopPropagation().  This will only stop resize from being sent to child elements of the current element.
	 *
	 *
	 */
	$.event.special.resize = {
		setup: function( handleObj ) {
			// add and sort the resizers array
			// don't add window because it can't be compared easily
			if ( this !== window ) {
				resizers.push(this);
				$.unique(resizers);
			}
			// returns false if the window
			return this !== window;
		},
		teardown: function() {
			// we shouldn't have to sort
			resizers = resizers.not(this);

			// returns false if the window
			return this !== window;
		},
		add: function( handleObj ) {
			// increment the number of resizer elements
			//$.data(this, "jquery.dom.resizers", ++$.data(this, "jquery.dom.resizers") );
			var origHandler = handleObj.handler;
			handleObj.origHandler = origHandler;

			handleObj.handler = function( ev, data ) {
				var isWindow = this === window;

				// if we are the window and a real resize has happened
				// then we check if the dimensions actually changed
				// if they did, we will wait a brief timeout and
				// trigger resize on the window
				// this is for IE, to prevent window resize 'infinate' loop issues
				if ( isWindow && ev.originalEvent ) {
					var width = win.width(),
						height = win.height();

					if ((width != windowWidth || height != windowHeight)) {
						//update the new dimensions
						windowWidth = width;
						windowHeight = height;
						clearTimeout(timer)
						timer = setTimeout(function() {
							win.trigger("resize");
						}, 1);

					}
					return;
				}

				// if this is the first handler for this event ...
				if ( resizeCount === 0 ) {
					// prevent others from doing what we are about to do
					resizeCount++;
					var where = data === false ? ev.target : this

					//trigger all this element's handlers
					$.event.handle.call(where, ev);
					if ( ev.isPropagationStopped() ) {
						resizeCount--;
						return;
					}

					// get all other elements within this element that listen to resize
					// and trigger their resize events
					var index = resizers.index(this),
						length = resizers.length,
						child, sub;

					// if index == -1 it's the window
					while (++index < length && (child = resizers[index]) && (isWindow || $.contains(where, child)) ) {

						// call the event
						$.event.handle.call(child, ev);

						if ( ev.isPropagationStopped() ) {
							// move index until the item is not in the current child
							while (++index < length && (sub = resizers[index]) ) {
								if (!$.contains(child, sub) ) {
									// set index back one
									index--;
									break
								}
							}
						}
					}

					// prevent others from responding
					ev.stopImmediatePropagation();
					resizeCount--;
				} else {
					handleObj.origHandler.call(this, ev, data);
				}
			}
		}
	};

	// automatically bind on these
	$([document, window]).bind('resize', function() {})
})<|endoftext|>


<commit_before>'use-strict';

angular.module('ActivityLogger').factory('DataService',
    function ($firebase, FIREBASE_URL, $timeout, $q, $ionicPopup, $state,User,Activity) {

        var rootRef = new Firebase(FIREBASE_URL);
        var usersRef = rootRef.child('users');
        var all_Users_activitiesRef = rootRef.child('all_Users_activities');
        var competitionsRef = rootRef.child('competitions');

        // AngularFire wrapper
        var usersRefAngular = $firebase(usersRef);
        var all_Users_activitiesRefAngular = $firebase(all_Users_activitiesRef);
        var competitionsRefAngular = $firebase(competitionsRef);

//Private method
        /**
         * get usersdata stored in local
         * @return {Object of usersdata|empty array if user has no profil*}
         */
        function getUserLocal() {
            var leer= new User("","","","","","","");
            var user = localStorage.getItem('user');
            return user?JSON.parse(user):leer;
        }

        /**
         * get all activities of a user saved in local
         * @return {Object of activities saved local|empty array if no activty *}
         */
        function getAllActivitiesLocal() {
            var leer = new Activity("","","","","",[],"","","");
            var activities = localStorage.getItem('activities');
            return activities?JSON.parse(activities):leer;
        }

        function getAllCompetitions_firebase() {
            return competitionsRefAngular.$asArray();
        }

        function getAllActivities_firebase() {
            return all_Users_activitiesRefAngular.$asArray();

        }

        function saveUserId_Local(user) {
            var timer = $timeout(function () {
                var users = getAllUsers();
                var f_user;
                for (var i = 0; i < users.length; i++) {
                    f_user = users[i];
                    if (equal(f_user, user)) {
                        localStorage.setItem('userId', f_user.$id);//Store usersid that was generated by firebase
                        break;
                    }
                }
            }, 4 * 60); //wait 4 seconds
        }

        function equal(user1,user2) {
            return user1.usersName == user2.usersName;
        }

        function getFirebaseId(userId, id) {
            var allfirebaseActty = getAllActivities_firebase();
            for (var i = 0; i < allfirebaseActty.length; i++) {
                var f_activty = allfirebaseActty[i];
                if ((f_activty.userId == userId) && (f_activty.id == id)) {
                    return f_activty.$id;
                }
            }
            return id;
        }

        function showErrorMess(mess) {
            $ionicPopup.alert({
                title: 'Fehler',
                template: mess,
                buttons: [{
                    text: 'Schließen',
                    type: 'button-positive'
                }]
            });
        }

//Public method
        /*************************Users*******************************************/
        /**
         * get all Users stored in firebase
         * @return {*}
         */
        function getAllUsers() {
            return usersRefAngular.$asArray();
        }

        /**
         *  add and store user only local or local and in firebase
         * @param user
         * show exception message if Usersname already exist
         */
        function addUser(user) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId = localStorage.getItem('userId');
            var fconnect=false;
            if ((firebaseConnected) && (!userId)) {  //Add User on firebase if not have been.
                var users = getAllUsers();
                var timer = $timeout(function () {
                    alert(users.length);
                    var hasUser = false;
                    for (var i = 0; i < users.length; i++) {
                        var userf = users[i];
                        if (userf.usersName == user.usersName) {
                            hasUser = true;
                            break;
                        }
                    }
                    if (hasUser) {
                       // throw "BenutzerName schon Vegeben";
                        showErrorMess("BenutzerName schon Vegeben");
                    } else {
                        fconnect = true;

                        getAllUsers().$add(user);
                        localStorage.setItem('user', JSON.stringify(user));
                        localStorage.setItem('infirebaseSaved', 'true');
                        saveUserId_Local(user);
                        var users_ref2 = getAllUsers();
                        timer=$timeout(function(user){
                            var userId=getCurrentUserId();
                            var user=getUserByID(userId);
                            user.id=userId;
                            users_ref2.$save(user);
                            localStorage.setItem('user', JSON.stringify(user));
                        },4*60)

                    }
                }, 8* 60)

            }else{
                localStorage.setItem('user', JSON.stringify(user));
            }
        }

        /**
         * update user only local or local and in firebase
         * @param user
         * show exception message if a firebase registered users want to update his profil but now he is not connecting.
         */
        function updateUser(user) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId = localStorage.getItem('userId');

            if (firebaseConnected && userId) {
                getAllUsers().$save(user);
                localStorage.setItem('user', JSON.stringify(user));
            } else {
                if (!userId) {//Profil local update if have not been added in firebase
                    localStorage.setItem('user', JSON.stringify(user));
                } else {//firebaseConnected==false
                    showErrorMess("Um Ihre Profil zu ändern müssen Sie sich mit Firebase verbinden ");
                }
                if (firebaseConnected && !userId) {
                    addUser(user);  //kann happen when usersname already used and user decide to change it.
                }
            }
        }

        /**
         *  get user by id stored local or in firebase
         * @param id: usersid
         * @return {user| null if the key is not found }
         */
        function getUserByID(id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            if ((id && id != null) && firebaseConnected) {
                return getAllUsers().$getRecord(id);
            } else {
                return getUserLocal();
            }

        }

        /**
         * get id of the current user
         * @return {user id| null if id not exist}
         */
        function getCurrentUserId() {
            var userId = localStorage.getItem('userId');
            return userId?userId:null;
        }

        /**
         * remove user from firebase
         * @param id
         */
        function removeUser(id) {
            getAllUsers().$remove(getUserByID(id));
        }

        /************************************Activities*******************************************/
        /**
         * Add and store activity Activity only local or local and in firebase.
         * @param activity
         * @throws exception if a user is connect to firebase and wants to store activities  without registration
         */
        function addActivity(activity) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId = localStorage.getItem('userId');
            var activities = getAllActivitiesLocal();
            var nexid = localStorage.getItem('nextActivityId');

            if (!nexid) {
                nexid = 1;
            } else {
                nexid = parseInt(nexid);
            }
            if (activities != null) {
                activity.id = nexid;
                activities.push(activity);
            } else {
                activities = [];
                activity.id = nexid;
                activities.push(activity);
            }
            localStorage.setItem('activities', JSON.stringify(activities));
            localStorage.setItem('nextActivityId', parseInt(nexid) + 1);

            if (firebaseConnected) { //Add activity in firebase, and to to a list on Activities saved on firebase(activities_firebase)
                alert(" persit on firebase ...");
                if (userId != null) {
                    var activities_firebase = localStorage.getItem('activities_firebase'); // Activities saved on firebase.
                    var next_af_id = localStorage.getItem('next_af_id');//next Activity id saved on firebase

                    if (!next_af_id) {
                        next_af_id = 1;
                    } else {
                        next_af_id = parseInt(next_af_id);
                    }
                    if (activities_firebase) {
                        activity.id = next_af_id;
                        activities_firebase = JSON.parse(activities_firebase);
                        activities_firebase.push(activity);
                    } else {
                        activities_firebase = [];
                        activity.id = next_af_id;
                        activities_firebase.push(activity);
                    }
                    activity.userId = userId;
                    getAllActivities_firebase().$add(activity);
                    localStorage.setItem('activities_firebase', JSON.stringify(activities_firebase));
                    localStorage.setItem('next_af_id', parseInt(next_af_id) + 1);
                } else {
                    // to firebase connectect and don't have a Profil-> can´t add Activities
                    showErrorMess("Sie müssen ein Profil in Firebase  anlegen um Ihre Aktivität speichert zu können !");

                }
            }
        }

        /**
         * get all activities of a user
         * @param user_id: usersid
         * @return { Array of all usersactivties|empty array}
         */
        function getAllActivities(user_id) {
            var all_activitiesByUserID = [];
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            if (user_id && firebaseConnected) {
                var all_user_activities = getAllActivities_firebase();
                for (var i = 0; i < all_user_activities.length; i++) {
                    var activity = all_user_activities[i];
                    if (activity.userId) {
                        if ((activity.userId) == (user_id)) {

                            all_activitiesByUserID.push(activity);
                        }
                    }
                }
                return all_activitiesByUserID;
            } else {
                return getAllActivitiesLocal();

            }
        }

        /**
         * update activity only local or local and in firebase
         * @param activity
         */
        function updateActivity(activity) {
            var activities = getAllActivitiesLocal();
            for (var i = 0; i < activities.length; i++) {
                var _activity = activities[i];
                if ((_activity.id == activity.id)) {
                    activities.splice(i, 1);
                    activities.push(activity);
                    localStorage.setItem('activities', JSON.stringify(activities));
                    break;
                }
            }
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            if (firebaseConnected) {

                getAllActivities_firebase().$save(activity);
                //update local List of activties saved on firebase (activities_firebase)
                var activities_firebase = localStorage.getItem('activities_firebase'); // Activities saved on firebase.
                if (activities_firebase) {
                    activities_firebase = JSON.parse(activities_firebase);
                    for (var i = 0; i < activities_firebase.length; i++) {
                        var _activity = activities[i];
                        if ((_activity.id == activity.id)) {
                            activities_firebase.splice(i, 1);
                            activities_firebase.push(activity);
                            localStorage.setItem('activities_firebase', JSON.stringify(activities_firebase));
                            break;
                        }
                    }
                }

            }
        }

        /**
         * get activity by id
         * @param id: id of activity local. If firebase connected, it will be converted to activtysid in firebase
         * @return {activty by id|null if the key is not found*}
         */
        function getActivityByID(id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var cur_userId = getCurrentUserId();
            if (firebaseConnected && cur_userId) {
                id =getFirebaseId(cur_userId, id);  //converted to activtysid in firebase
                return getAllActivities_firebase().$getRecord(id);
            } else {
                var activities = getAllActivitiesLocal();
                for (var i = 0; i < activities.length; i++) {
                    var activity = activities[i];
                    if (activity.id == id) {
                        return activity;
                    }
                }
                return null;
            }
        }

        /**
         * remove a activty by id only local or local and from firebase.
         * @param id
         */
        function removeActivity(id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var activities = getAllActivitiesLocal();
            for (var i = 0; i <activities.length; i++) {
                var activity = activities[i];
                if (activity.id == id) {
                    activities.splice(i,1);
                    localStorage.setItem('activities', JSON.stringify(activities));
                    break;
                }
            }
            if (firebaseConnected) {
                var userId = localStorage.getItem('userId');

                getAllActivities_firebase().$remove(getActivityByID(getFirebaseId(userId, id)));
                var activities_firebase = localStorage.getItem('activities_firebase'); // Activities saved on firebase.
                if (activities_firebase) {
                    activities_firebase = JSON.parse(activities_firebase);
                    for (var i = 0; i < activities_firebase.length; i++) {
                        var activity_f = activities_firebase[i];
                        if ((activity_f.id == id)) {
                            activities_firebase.splice(i, 1);
                            localStorage.setItem('activities_firebase', JSON.stringify(activities_firebase));
                            break;
                        }
                    }
                }
            }

        }

        /**
         * remove all activties by usersid
         * @param user_Id: usersid
         */
        function removeAllActivities(user_Id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            localStorage.removeItem('activities');
            if (firebaseConnected) {
                getAllActivities_firebase(user_Id).$remove();
            }
        }

        /*******************************competition********************************************/
        /**
         * Add a competition
         * @param competition
         * @throws exception if user is not registered
         */
        function addCompetition(competition) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId =getCurrentUserId();
             if(firebaseConnected&userId){
                 getAllCompetitions_firebase().$add(competition);
             }else {
                 throw 'Um eine Competition anzulegen müssen Sie :
'+'
in Settings Die Firebase Verbindung akzeptieren falls noch nicht
'+'
sich registrieren oder anmelden
';
             }
        }

        /**
         * remove competition by id
         * @param id: competitions id
         */
        function removeCompetition(id) {
            getAllCompetitions_firebase().$remove(getCompetitionByID(id));
        }

        /**
         * get competition by id
         * @param id competitions id
         * @return {Object|null if the key is not found*}
         */
        function getCompetitionByID(id) {
            return getAllCompetitions_firebase().$getRecord(id);
        }

        /**
         * get all competions of user by user_id
         * @param user_id. usersid
         * @return {Object|null if the key is not found*}
         */
        function getAllCompetitions(user_id) {
            return getAllCompetitions_firebase().$getRecord(user_id);
        }

        var service = {
            //User
            getAllUsers: getAllUsers,
            addUser: addUser,
            updateUser: updateUser,
            getUserByID: getUserByID,
            removeUser: removeUser,
            getCurrentUserId: getCurrentUserId,
            //Activities
            getAllActivities: getAllActivities,
            getActivityByID: getActivityByID,
            addActivity: addActivity,
            updateActivity: updateActivity,
            removeActivity: removeActivity,
            //competition
            getAllCompetitions: getAllCompetitions,
            getCompetitionByID: getCompetitionByID,
            addCompetition: addCompetition,
            removeCompetition: removeCompetition

        };
        return service;

    }
)
;<commit_msg>use Model<commit_after>'use-strict';

angular.module('ActivityLogger').factory('DataService',
    function ($firebase, FIREBASE_URL, $timeout, $ionicPopup, $state,User,Activity,Competition) {

        var rootRef = new Firebase(FIREBASE_URL);
        var usersRef = rootRef.child('users');
        var all_Users_activitiesRef = rootRef.child('all_Users_activities');
        var competitionsRef = rootRef.child('competitions');

        // AngularFire wrapper
        var usersRefAngular = $firebase(usersRef);
        var all_Users_activitiesRefAngular = $firebase(all_Users_activitiesRef);
        var competitionsRefAngular = $firebase(competitionsRef);

//Private method
        /**
         * get usersdata stored in local
         * @return {Object of usersdata|empty array if user has no profil*}
         */
        function getUserLocal() {
            var leer= new User("","","","","","","");
            var user = localStorage.getItem('user');
            return user?JSON.parse(user):leer;
        }

        /**
         * get all activities of a user saved in local
         * @return {Object of activities saved local|empty array if no activty *}
         */
        function getAllActivitiesLocal() {
            var leer=[];
            var activities = localStorage.getItem('activities');
            return activities?JSON.parse(activities):leer;
        }

        function getAllCompetitions_firebase() {
            return competitionsRefAngular.$asArray();
        }

        function getAllActivities_firebase() {
            return all_Users_activitiesRefAngular.$asArray();

        }

        function saveUserId_Local(user) {
            var timer = $timeout(function () {
                var users = getAllUsers();
                var f_user;
                for (var i = 0; i < users.length; i++) {
                    f_user = users[i];
                    if (equal(f_user, user)) {
                        localStorage.setItem('userId', f_user.$id);//Store usersid that was generated by firebase
                        break;
                    }
                }
            }, 4 * 60); //wait 4 seconds
        }

        function equal(user1,user2) {
            return user1.id == user2.id;
        }

        function getFirebaseId(userId, id) {
            var allfirebaseActty = getAllActivities_firebase();
            for (var i = 0; i < allfirebaseActty.length; i++) {
                var f_activty = allfirebaseActty[i];
                if ((f_activty.userId == userId) && (f_activty.id == id)) {
                    return f_activty.$id;
                }
            }
            return id;
        }

        function showErrorMess(mess) {
            $ionicPopup.alert({
                title: 'Fehler',
                template: mess,
                buttons: [{
                    text: 'Schließen',
                    type: 'button-positive'
                }]
            });

        }

//Public method
        /*************************Users*******************************************/
        /**
         * get all Users stored in firebase
         * @return {*}
         */
        function getAllUsers() {
            return usersRefAngular.$asArray();
        }

        /**
         *  add and store user only local or local and in firebase
         * @param user
         * show exception message if Usersname already exist
         */
        function addUser(user) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId = localStorage.getItem('userId');
            var user= new User(user.id,user.firstname,user.surname,user.gender,user.birthday,user.weight,user.size);
            if ((firebaseConnected) && (!userId)) {  //Add User on firebase if not have been.
                var users = getAllUsers();
                var timer = $timeout(function () {
                    var hasUser = false;
                    for (var i = 0; i < users.length; i++) {
                        var userf = users[i];
                        if (userf.id == user.id) {
                            hasUser = true;
                            break;
                        }
                    }
                    if (hasUser) {
                       // throw "BenutzerName schon Vegeben";
                        showErrorMess("BenutzerName schon Vegeben");
                    } else {
                        getAllUsers().$add(user);
                        localStorage.setItem('user', JSON.stringify(user));
                        localStorage.setItem('infirebaseSaved', 'true');
                        saveUserId_Local(user);
                        showMessage(" Ihre Daten  wurden erfolgreich in firebase gespeichert")
                    }
                }, 8* 60)

            }else{
                localStorage.setItem('user', JSON.stringify(user));
                showMessage(" Ihre Daten  wurden erfolgreich local  gespeichert")
            }
        }

        /**
         * update user only local or local and in firebase
         * @param user
         * show exception message if a firebase registered users want to update his profil but now he is not connecting.
         */
        function updateUser(user) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId = localStorage.getItem('userId');

            if (firebaseConnected && userId) {
                getAllUsers().$save(user);
                localStorage.setItem('user', JSON.stringify(user));
            } else {
                if (!userId) {//Profil local update if have not been added in firebase
                    localStorage.setItem('user', JSON.stringify(user));
                } else {//firebaseConnected==false
                    showErrorMess("Um Ihre Profil zu ändern müssen Sie sich mit Firebase verbinden ");
                }
                if (firebaseConnected && !userId) {
                    addUser(user);  //kann happen when usersname already used and user decide to change it.
                }
            }
        }

        /**
         *  get user by id stored local or in firebase
         * @param id: usersid
         * @return {user| null if the key is not found }
         */
        function getUserByID(id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            if ((id && id != null) && firebaseConnected) {
                return getAllUsers().$getRecord(id);
            } else {
                return getUserLocal();
            }

        }

        /**
         * get id of the current user
         * @return {user id| null if id not exist}
         */
        function getCurrentUserId() {
            var userId = localStorage.getItem('userId');
            return userId?userId:null;
        }

        /**
         * remove user from firebase
         * @param id
         */
        function removeUser(id) {
            getAllUsers().$remove(getUserByID(id));
        }

        /************************************Activities*******************************************/
        /**
         * Add and store activity Activity only local or local and in firebase.
         * @param activity
         * @throws exception if a user is connect to firebase and wants to store activities  without registration
         */
        function addActivity(activity) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var activities = getAllActivitiesLocal();
            var nexid = localStorage.getItem('nextActivityId');

            if (!nexid) {
                nexid = 1;
            } else {
                nexid = parseInt(nexid);
            }
            if (firebaseConnected) {
                var userId = localStorage.getItem('userId');
                if (userId) {
                    _activity= new Activity(nexid,activity.type,activity.start_time,activity.end_time,activity.track_data,activity.comment,activity.distance,userId);
                    getAllActivities_firebase().$add(_activity);
                    activities.push(_activity);
                    localStorage.setItem('activities',JSON.stringify(activities));
                    localStorage.setItem('nextActivityId', parseInt(nexid) + 1);
                    showMessage(" Activity erfolgreich local und in firebase  gespeichert")
                } else {
                    // to firebase connectect and don't have a Profil-> can´t add Activities
                    showErrorMess("Sie müssen ein Profil in Firebase  anlegen um Ihre Aktivität speichert zu können !");
                }
            }else{
                var _activity= new Activity(nexid,activity.type,activity.start_time,activity.end_time,activity.track_data,activity.comment,activity.distance,"");
                activities.push(_activity);

                localStorage.setItem('activities',JSON.stringify(activities));
                localStorage.setItem('nextActivityId', parseInt(nexid) + 1);
                showMessage("Activity erfolgreich local gespeichert")
            }
        }

        function showMessage(mess){
            var myPopup= $ionicPopup.show({
                title: mess
            })
            $timeout(function() {
                myPopup.close(); //close the popup after 3 seconds for some reason
            }, 2000);
        }

        /**
         * get all activities of a user
         * @param user_id: usersid
         * @return { Array of all usersactivties|empty array}
         */
        function getAllActivities(user_id) {
            var all_activitiesByUserID = [];
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            if (user_id && firebaseConnected) {
                var all_user_activities = getAllActivities_firebase();
                for (var i = 0; i < all_user_activities.length; i++) {
                    var activity = all_user_activities[i];
                    if (activity.userId) {
                        if ((activity.userId) == (user_id)) {

                            all_activitiesByUserID.push(activity);
                        }
                    }
                }
                return all_activitiesByUserID;
            } else {
                return getAllActivitiesLocal();

            }
        }

        /**
         * update activity only local or local and in firebase
         * @param activity
         */
        function updateActivity(activity) {
            var activities = getAllActivitiesLocal();
            for (var i = 0; i < activities.length; i++) {
                var _activity = activities[i];
                if ((_activity.id == activity.id)) {
                    activities.splice(i, 1);
                    activities.push(activity);
                    localStorage.setItem('activities', JSON.stringify(activities));
                    break;
                }
            }
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            if (firebaseConnected) {

                getAllActivities_firebase().$save(activity);
                //update local List of activties saved on firebase (activities_firebase)
                var activities_firebase = localStorage.getItem('activities_firebase'); // Activities saved on firebase.
                if (activities_firebase) {
                    activities_firebase = JSON.parse(activities_firebase);
                    for (var i = 0; i < activities_firebase.length; i++) {
                        var _activity = activities[i];
                        if ((_activity.id == activity.id)) {
                            activities_firebase.splice(i, 1);
                            activities_firebase.push(activity);
                            localStorage.setItem('activities_firebase', JSON.stringify(activities_firebase));
                            break;
                        }
                    }
                }

            }
        }

        /**
         * get activity by id
         * @param id: id of activity local. If firebase connected, it will be converted to activtysid in firebase
         * @return {activty by id|null if the key is not found*}
         */
        function getActivityByID(id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var cur_userId = getCurrentUserId();
            if (firebaseConnected && cur_userId) {
               // id =getFirebaseId(cur_userId, id);  //converted to activtysid in firebase
                return getAllActivities_firebase().$getRecord(id);
            } else {
                var activities = getAllActivitiesLocal();
                for (var i = 0; i < activities.length; i++) {
                    var activity = activities[i];
                    if (activity.id == id) {
                        return activity;
                    }
                }
                return null;
            }
        }

        /**
         * remove a activty by id only local or local and from firebase.
         * @param id
         */
        function removeActivity(id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var activities = getAllActivitiesLocal();
            for (var i = 0; i <activities.length; i++) {
                var activity = activities[i];
                if (activity.id == id) {
                    activities.splice(i,1);
                    localStorage.setItem('activities', JSON.stringify(activities));
                    break;
                }
            }
            if (firebaseConnected) {
                var userId = localStorage.getItem('userId');

                getAllActivities_firebase().$remove(getActivityByID(getFirebaseId(userId, id)));
                var activities_firebase = localStorage.getItem('activities_firebase'); // Activities saved on firebase.
                if (activities_firebase) {
                    activities_firebase = JSON.parse(activities_firebase);
                    for (var i = 0; i < activities_firebase.length; i++) {
                        var activity_f = activities_firebase[i];
                        if ((activity_f.id == id)) {
                            activities_firebase.splice(i, 1);
                            localStorage.setItem('activities_firebase', JSON.stringify(activities_firebase));
                            break;
                        }
                    }
                }
            }

        }

        /**
         * remove all activties by usersid
         * @param user_Id: usersid
         */
        function removeAllActivities(user_Id) {
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            localStorage.removeItem('activities');
            if (firebaseConnected) {
                getAllActivities_firebase(user_Id).$remove();
            }
        }

        /*******************************competition********************************************/
        /**
         * Add a competition
         * @param competition
         * @throws exception if user is not registered
         */
        function addCompetition(competition) {
            var nexCompetitionId = localStorage.getItem('nexCompetitionId');

            if (!nexCompetitionId) {
                nexCompetitionId= 1;
            } else {
                nexCompetitionId= parseInt(nexCompetitionId);
            }
            var firebaseConnected = localStorage.getItem('firebaseConection') == 'true';
            var userId =getCurrentUserId();
             if(firebaseConnected&&userId){
                 var competition=new Competition(nexCompetitionId,competition.user_id1,competition.user_id2,competition.activity_id1,competition.activity_id2,competition.distance);
                 getAllCompetitions_firebase().$add(competition);
                 localStorage.setItem('nexCompetitionId', parseInt('nexCompetitionId') + 1);

             }else {
                 showErrorMess("Um eine Competition anzulegen müssen Sie in Settings Die Firebase Verbindung akzeptieren falls noch nicht sich registrieren oder anmelden");

             }
        }

        /**
         * remove competition by id
         * @param id: competitions id
         */
        function removeCompetition(id) {
            getAllCompetitions_firebase().$remove(getCompetitionByID(id));
        }

        /**
         * get competition by id
         * @param id competitions id
         * @return {Object|null if the key is not found*}
         */
        function getCompetitionByID(id) {
            return getAllCompetitions_firebase().$getRecord(id);
        }

        /**
         * get all competions of user by user_id
         * @param user_id. usersid
         * @return {Object|null if the key is not found*}
         */
        function getAllCompetitions(user_id) {
            return getAllCompetitions_firebase().$getRecord(user_id);
        }

        var service = {
            //User
            getAllUsers: getAllUsers,
            addUser: addUser,
            updateUser: updateUser,
            getUserByID: getUserByID,
            removeUser: removeUser,
            getCurrentUserId: getCurrentUserId,
            //Activities
            getAllActivities: getAllActivities,
            getActivityByID: getActivityByID,
            addActivity: addActivity,
            updateActivity: updateActivity,
            removeActivity: removeActivity,
            //competition
            getAllCompetitions: getAllCompetitions,
            getCompetitionByID: getCompetitionByID,
            addCompetition: addCompetition,
            removeCompetition: removeCompetition

        };
        return service;

    }
)
;<|endoftext|>