<commit_before>// @flow
import { helpers } from 'utils';
import BaseEditorView from './base/BaseEditorView';
import template from './templates/avatarEditor.hbs';
import formRepository from '../formRepository';

const defaultOptions = {
    removable: true,
    autoUpload: false,
    refreshPreviewAfterUpload: false,
    controller: undefined
};

/**
 * @name AvatarEditorView
 * @memberof module:core.form.editors
 * @class Editor used to set (or unset) an image to be used mainly as user avatar and process it any way (e.g. upload to server).
 * @extends module:core.form.editors.base.BaseEditorView
 * @param {string} options.fullName - Full name used to fill editor with initials when no value is provided.
 * @param {boolean} options.removable - Flags whether an image may be removed (editor's value is set to null).
 * @param {boolean} options.autoUpload - Flags whether to upload (or process any other way) an image after it has been selected via file explorer.
 * Instead, method upload can be called on editor to do it manually.
 * @param {boolean} options.refreshPreviewAfterUpload - Flags whether to refresh editor with value returned by upload method.
 * This only makes sense when upload method returns value coresponding to image other than image used as argument to upload method.
 * @param {BaseAvatarEditorController} options.controller - Data provider controller in the form of subclass of
 * {@link module:core.form.editors.avatar.controllers.BaseAvatarEditorController BaseAvatarEditorController}.
 */

export default (formRepository.editors.Avatar = BaseEditorView.extend({
    className: 'user-avatar-wrp',

    attributes: {
        tabindex: 0
    },

    template: Handlebars.compile(template),

    ui: {
        image: '.js-image',
        remove: '.js-remove',
        initials: '.js-initials',
        tooltip: '.js-tooltip'
    },

    events: {
        click: '__attach',
        'click @ui.remove': '__remove'
    },

    initialize(options = {}) {
        _.defaults(this.options, options.schema, defaultOptions);

        helpers.ensureOption(this.options, 'controller');
        this.controller = this.getOption('controller');
        this.__removed = false;
        this.__previewURL = null;
        this.__initFileInput();
    },

    onRender() {
        this.ui.initials.append(this.__getInitialsOrDefaultImage(this.getOption('fullName') || ''));

        if (this.getValue()) {
            this.__preview(this.controller.getImage(this.getValue()));
        } else if (this.controller.getImage()) {
            this.__preview(this.controller.getImage());
        } else {
            this.ui.initials.show();
        }

        this.ui.tooltip.hide();
        this.ui.remove.hide();

        this.$el.hover(
            () => {
                if (this.getEnabled() && !this.getReadonly()) {
                    this.ui.tooltip.show();
                }

                if (this.getEnabled() && !this.getReadonly() && this.getOption('removable') && this.ui.image.css('background-image') !== 'none') {
                    this.ui.remove.show();
                }
            },
            () => {
                this.ui.tooltip.hide();
                this.ui.remove.hide();
            }
        );
    },

    onBeforeDestroy() {
        URL.revokeObjectURL(this.__previewURL);
    },

    upload() {
        const file = this.fileInput.files[0];
        this.__initFileInput();

        if (file) {
            return this.controller.upload(file).then(data => {
                if (!this.__removed) {
                    this.setValue(data.value);
                    this.__triggerChange();

                    if (this.getOption('refreshPreviewAfterUpload')) {
                        this.__preview(this.controller.getImage(this.getValue()));
                    }
                }
            });
        }
        return Promise.resolve();
    },

    __initFileInput() {
        this.fileInput = document.createElement('input');
        this.fileInput.type = 'file';
        this.fileInput.accept = 'image/*';
        this.fileInput.style.display = 'none';

        this.fileInput.oninput = this.fileInput.onchange = () => {
            if (!(this.fileInput.files && this.fileInput.files.length)) {
                return;
            }

            this.__removed = false;
            this.__preview(this.fileInput.files[0]);

            if (this.getOption('autoUpload')) {
                this.upload();
            }
        };
    },

    __getInitialsOrDefaultImage(fullName) {
        const words = fullName.split(' ');
        let userInitials;

        switch (words.length) {
            case 0:
                userInitials = null;
                break;
            case 1:
                if (words[0] === '') {
                    userInitials = null;
                }
                userInitials = fullName.substr(0, 2).toUpperCase();
                break;
            default:
                userInitials = (words[0].charAt(0) + words[1].charAt(0)).toUpperCase();
                break;
        }
        this.el.querySelector('.user-avatar-default-icon').style.visibility = userInitials ? 'hidden' : 'visible';
        return userInitials;
    },

    __attach() {
        if (this.getEnabled() && !this.getReadonly() && document.body) {
            document.body.appendChild(this.fileInput);
            this.fileInput.click();
            if (document.body) {
                document.body.removeChild(this.fileInput);
            }
        }
    },

    __remove() {
        if (this.getEnabled() && !this.getReadonly()) {
            this.setValue(null);
            this.__triggerChange();

            URL.revokeObjectURL(this.__previewURL);
            this.ui.image.css('background-image', 'none');
            this.ui.remove.hide();
            this.ui.initials.show();

            this.__removed = true;
        }

        return false;
    },

    __preview(image) {
        this.ui.initials.hide();
        URL.revokeObjectURL(this.__previewURL);
        let previewURL;

        if (typeof image === 'string') {
            // URL
            previewURL = image;
        } else if (_.isObject(image) && {}.toString.call(image).slice(8, -1) === 'File') {
            // file
            previewURL = this.__previewURL = URL.createObjectURL(image);
        }

        previewURL && this.ui.image.css('background-image', `url("${previewURL}")`);
    }
}));
<commit_msg>Fix user avatar abbreviation visibility<commit_after>// @flow
import { helpers } from 'utils';
import BaseEditorView from './base/BaseEditorView';
import template from './templates/avatarEditor.hbs';
import formRepository from '../formRepository';

const defaultOptions = {
    removable: true,
    autoUpload: false,
    refreshPreviewAfterUpload: false,
    controller: undefined
};

/**
 * @name AvatarEditorView
 * @memberof module:core.form.editors
 * @class Editor used to set (or unset) an image to be used mainly as user avatar and process it any way (e.g. upload to server).
 * @extends module:core.form.editors.base.BaseEditorView
 * @param {string} options.fullName - Full name used to fill editor with initials when no value is provided.
 * @param {boolean} options.removable - Flags whether an image may be removed (editor's value is set to null).
 * @param {boolean} options.autoUpload - Flags whether to upload (or process any other way) an image after it has been selected via file explorer.
 * Instead, method upload can be called on editor to do it manually.
 * @param {boolean} options.refreshPreviewAfterUpload - Flags whether to refresh editor with value returned by upload method.
 * This only makes sense when upload method returns value coresponding to image other than image used as argument to upload method.
 * @param {BaseAvatarEditorController} options.controller - Data provider controller in the form of subclass of
 * {@link module:core.form.editors.avatar.controllers.BaseAvatarEditorController BaseAvatarEditorController}.
 */

export default (formRepository.editors.Avatar = BaseEditorView.extend({
    className: 'user-avatar-wrp',

    attributes: {
        tabindex: 0
    },

    template: Handlebars.compile(template),

    ui: {
        image: '.js-image',
        remove: '.js-remove',
        initials: '.js-initials',
        tooltip: '.js-tooltip'
    },

    events: {
        click: '__attach',
        'click @ui.remove': '__remove'
    },

    initialize(options = {}) {
        _.defaults(this.options, options.schema, defaultOptions);

        helpers.ensureOption(this.options, 'controller');
        this.controller = this.getOption('controller');
        this.__removed = false;
        this.__previewURL = null;
        this.__initFileInput();
    },

    onRender() {
        this.ui.initials.append(this.__getInitialsOrDefaultImage(this.getOption('fullName') || ''));

        if (this.getValue()) {
            this.__preview(this.controller.getImage(this.getValue()));
        } else if (this.controller.getImage()) {
            this.__preview(this.controller.getImage());
        }

        this.ui.tooltip.hide();
        this.ui.remove.hide();

        this.$el.hover(
            () => {
                if (this.getEnabled() && !this.getReadonly()) {
                    this.ui.tooltip.show();
                }

                if (this.getEnabled() && !this.getReadonly() && this.getOption('removable') && this.ui.image.css('background-image') !== 'none') {
                    this.ui.remove.show();
                }
            },
            () => {
                this.ui.tooltip.hide();
                this.ui.remove.hide();
            }
        );
    },

    onBeforeDestroy() {
        URL.revokeObjectURL(this.__previewURL);
    },

    upload() {
        const file = this.fileInput.files[0];
        this.__initFileInput();

        if (file) {
            return this.controller.upload(file).then(data => {
                if (!this.__removed) {
                    this.setValue(data.value);
                    this.__triggerChange();

                    if (this.getOption('refreshPreviewAfterUpload')) {
                        this.__preview(this.controller.getImage(this.getValue()));
                    }
                }
            });
        }
        return Promise.resolve();
    },

    __initFileInput() {
        this.fileInput = document.createElement('input');
        this.fileInput.type = 'file';
        this.fileInput.accept = 'image/*';
        this.fileInput.style.display = 'none';

        this.fileInput.oninput = this.fileInput.onchange = () => {
            if (!(this.fileInput.files && this.fileInput.files.length)) {
                return;
            }

            this.__removed = false;
            this.__preview(this.fileInput.files[0]);

            if (this.getOption('autoUpload')) {
                this.upload();
            }
        };
    },

    __getInitialsOrDefaultImage(fullName) {
        const words = fullName.split(' ');
        let userInitials;

        switch (words.length) {
            case 0:
                userInitials = null;
                break;
            case 1:
                if (words[0] === '') {
                    userInitials = null;
                }
                userInitials = fullName.substr(0, 2).toUpperCase();
                break;
            default:
                userInitials = (words[0].charAt(0) + words[1].charAt(0)).toUpperCase();
                break;
        }
        this.el.querySelector('.user-avatar-default-icon').style.visibility = userInitials ? 'hidden' : 'visible';
        return userInitials;
    },

    __attach() {
        if (this.getEnabled() && !this.getReadonly() && document.body) {
            document.body.appendChild(this.fileInput);
            this.fileInput.click();
            if (document.body) {
                document.body.removeChild(this.fileInput);
            }
        }
    },

    __remove() {
        if (this.getEnabled() && !this.getReadonly()) {
            this.setValue(null);
            this.__triggerChange();

            URL.revokeObjectURL(this.__previewURL);
            this.ui.image.css('background-image', 'none');
            this.ui.remove.hide();

            this.__removed = true;
        }

        return false;
    },

    __preview(image) {
        URL.revokeObjectURL(this.__previewURL);
        let previewURL;

        if (typeof image === 'string') {
            // URL
            previewURL = image;
        } else if (_.isObject(image) && {}.toString.call(image).slice(8, -1) === 'File') {
            // file
            previewURL = this.__previewURL = URL.createObjectURL(image);
        }

        previewURL && this.ui.image.css('background-image', `url("${previewURL}")`);
    }
}));
<|endoftext|>


<commit_before>/*global html,isHostObjectProperty,isHostMethod */

/*
Description:
Cutting edge and wide support
*/

/*
Degrades:
IE4, IE3, NN4
*/

/*
Author:
Adam Silver
*/

var addClass;

if (html && isHostObjectProperty(html, "classList") && isHostMethod(html.classList, "add") ) {
	addClass = function(el, className) {
		return el.classList.add(className);
	};
} else if (html && "string" === typeof html.className ) {
    addClass = function(el, className) {
		var re;
		if (!el.className) {
			el.className = className;
		}
		else {
			re = new RegExp('(^|\\s)' + className + '(\\s|$)');
			if (!re.test(el.className)) { el.className += ' ' + className; }
		}
    };
}<commit_msg>Update rendition2.js<commit_after>/*global html,isHostObjectProperty,isHostMethod */

/*
Description:
Cutting edge and wide support
*/

/*
Degrades:
IE4, IE3, NN4
*/

/*
Author:
Adam Silver
*/

var addClass;

if (html && isHostObjectProperty(html, "classList") && isHostMethod(html.classList, "add") ) {
	addClass = function(el, className) {
		el.classList.add(className);
	};
} else if (html && "string" === typeof html.className ) {
    addClass = function(el, className) {
		var re;
		if (!el.className) {
			el.className = className;
		}
		else {
			re = new RegExp('(^|\\s)' + className + '(\\s|$)');
			if (!re.test(el.className)) { el.className += ' ' + className; }
		}
    };
}
<|endoftext|>


<commit_before>/**
 * Based on octree search results tries to find index of a point which is
 * nearest to the ray in z-direction, and is closer than maxDistanceFromRay
 */

export default getNearestIndex;

function getNearestIndex(allPoints, intersectedIndexes, ray, maxDistanceFromRay) {
  if (intersectedIndexes.length === 0) return intersectedIndexes;

  // This is not necessary the fastest solution, but in practice it is very fast
  intersectedIndexes.sort(byProximityToRay);

  var candidate = intersectedIndexes[0];

  if (getDistanceToRay(candidate) < maxDistanceFromRay) {
    return candidate;
  }

  // No point is closer than maxDistanceFromRay, return undefined answer
  return;

  function byProximityToRay(x, y) {
    var distX = getDistanceToRay(x);
    var distY = getDistanceToRay(y);
    return distX - distY;
  }

  function getDistanceToRay(idx) {
    var x = allPoints[idx];
    var y = allPoints[idx + 1];
    var z = allPoints[idx + 2];

    var dx = ray.direction.x * (x - ray.origin.x);
    var dy = ray.direction.y * (y - ray.origin.y);
    var dz = ray.direction.z * (z - ray.origin.z);

    var directionDistance = dx + dy + dz;
    var vx = ray.direction.x * directionDistance + ray.origin.x;
    var vy = ray.direction.y * directionDistance + ray.origin.y;
    var vz = ray.direction.z * directionDistance + ray.origin.z;

    return (vx - x) * (vx - x) + (vy - y) * (vy - y) + (vz - z) * (vz - z);
  }
}
<commit_msg>Fixed wrong return type for 0 intersection<commit_after>/**
 * Based on octree search results tries to find index of a point which is
 * nearest to the ray in z-direction, and is closer than maxDistanceFromRay
 */

export default getNearestIndex;

function getNearestIndex(allPoints, intersectedIndexes, ray, maxDistanceFromRay) {
  if (intersectedIndexes.length === 0) return;

  // This is not necessary the fastest solution, but in practice it is very fast
  intersectedIndexes.sort(byProximityToRay);

  var candidate = intersectedIndexes[0];

  if (getDistanceToRay(candidate) < maxDistanceFromRay) {
    return candidate;
  }

  // No point is closer than maxDistanceFromRay, return undefined answer
  return;

  function byProximityToRay(x, y) {
    var distX = getDistanceToRay(x);
    var distY = getDistanceToRay(y);
    return distX - distY;
  }

  function getDistanceToRay(idx) {
    var x = allPoints[idx];
    var y = allPoints[idx + 1];
    var z = allPoints[idx + 2];

    var dx = ray.direction.x * (x - ray.origin.x);
    var dy = ray.direction.y * (y - ray.origin.y);
    var dz = ray.direction.z * (z - ray.origin.z);

    var directionDistance = dx + dy + dz;
    var vx = ray.direction.x * directionDistance + ray.origin.x;
    var vy = ray.direction.y * directionDistance + ray.origin.y;
    var vz = ray.direction.z * directionDistance + ray.origin.z;

    return (vx - x) * (vx - x) + (vy - y) * (vy - y) + (vz - z) * (vz - z);
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/takinIndicky/01.jpg'),
  require('../../images/animals/takinIndicky/02.jpg'),
  require('../../images/animals/takinIndicky/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/takinIndicky/01-thumb.jpg'),
  require('../../images/animals/takinIndicky/02-thumb.jpg'),
  require('../../images/animals/takinIndicky/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          Takin indický, latinsky <Text style={styles.italic}>Budorcas taxicolor taxicolor</Text>, je velmi zvláštní sudokopytník čeledi turovitých. V čem tkví jeho zvláštnost? Jaké jiné zvíře připomíná tolik dalších? Je to bizon, pakůň, los nebo kamzík? Právě všechna tato zvířata se svojí určitou vlastností snoubí v jednom takiním těle.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Bohužel i přes svoji hbitost, připisovanou spíše kamzíkům, je takin indický na stupních ohrožení zranitelným druhem – na světě už jich není více než půl čtvrtého tisíce. Vyskytuje se na jihu Číny, v indickém státě Asám, v Tibetu a Bhútánu, ale i v Barmě. Obvykle žije ve výšce 2 500 až 4 500 metrů nad mořem. Takini se naštěstí docela činí, takže zatím není všem takiním dnům konec.
        </AnimalText>
        <InPageImage indexes={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Jedinec takina indického může vážit až 350 kilogramů a měřit v kohoutku i 130 centimetrů, na délku pak 170 až 220 centimetrů. Kůže takina produkuje olej, který mu pomáhá chránit se proti drsným povětrnostním podmínkám panujícím v jeho přirozeném prostředí, zejména proti mlze a dešti. Takin se živí trávou, listy, bambusovými nebo pěnišníkovými výhonky.
        </AnimalText>
        <AnimalText>
          Žije v menších stádech (tvořených deseti až třiceti zvířaty), jeho samice je březí až 220 dní a má obvykle jen jedno mládě. Ve volné přírodě se dožívá dvanácti až patnácti let, v lidské péči i dvaceti let.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<commit_msg>Update takinIndicky.adult.js<commit_after>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/takinIndicky/01.jpg'),
  require('../../images/animals/takinIndicky/02.jpg'),
  require('../../images/animals/takinIndicky/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/takinIndicky/01-thumb.jpg'),
  require('../../images/animals/takinIndicky/02-thumb.jpg'),
  require('../../images/animals/takinIndicky/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          Takin indický, latinsky <Text style={styles.italic}>Budorcas taxicolor taxicolor</Text>, je velmi zvláštní sudokopytník čeledi turovitých. V čem tkví jeho zvláštnost? Jaké jiné zvíře připomíná tolik dalších? Je to bizon, pakůň, los nebo kamzík? Právě všechna tato zvířata se svojí určitou vlastností snoubí v jednom takiním těle.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Bohužel i přes svoji hbitost, připisovanou spíše kamzíkům, je takin indický na stupních ohrožení zranitelným druhem – na světě už jich není více než půl čtvrtého tisíce. Vyskytuje se na jihu Číny, v indickém státě Asám, v Tibetu a Bhútánu, ale i v Barmě. Obvykle žije ve výšce 2 500 až 4 500 metrů nad mořem. Takini se naštěstí docela činí, takže zatím není všem takiním dnům konec.
        </AnimalText>
        <InPageImage indexes={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Jedinec takina indického může vážit až 350 kilogramů a v kohoutku měřit i 130 centimetrů, na délku pak 170 až 220 centimetrů. Kůže takina produkuje olej, který mu pomáhá chránit se proti drsným povětrnostním podmínkám panujícím v jeho přirozeném prostředí, zejména proti mlze a dešti. Takin se živí trávou, listy, bambusovými nebo pěnišníkovými výhonky.
        </AnimalText>
        <AnimalText>
          Žije v menších stádech (tvořených deseti až třiceti zvířaty), jeho samice je březí až 220 dní a má obvykle jen jedno mládě. Ve volné přírodě se dožívá dvanácti až patnácti let, v lidské péči i dvaceti let.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<|endoftext|>


<commit_before>import io from 'socket.io-client';
import Cookies from 'js-cookie';
import log from './log';
import userInfo from './userInfo';
import calcMsgHistorySize from './msg-history-sizer';

const ioSocket = io.connect(); // Start connection as early as possible.

class Socket {
  constructor() {
    this.sessionId = 0;
    this.connected = false;
    this.sendQueue = [];
    this.disconnectedTimer = null;
    this.maxBacklogMsgs = 0;
  }

  configure(store) {
    this.store = store;
  }

  start() {
    Socket._emitInit();

    ioSocket.on('initok', data => {
      this.connected = true;
      this.sessionId = data.sessionId;
      this.maxBacklogMsgs = data.maxBacklogMsgs;

      Cookies.set('mas', data.refreshCookie, { expires: 7 });

      userInfo.userId = `m${data.userId}`;

      this._emitReq(); // In case there are items in sendQueue from previous session
    });

    ioSocket.on('terminate', () => {
      Cookies.remove('mas');
      window.location.assign('/');
    });

    ioSocket.on('ntf', notification => this.store.dispatch(notification));

    ioSocket.on('disconnect', () => {
      log.info('Socket.io connection lost.');

      this.connected = false;

      this.disconnectedTimer = setTimeout(() => {
        this.store.dispatch({
          type: 'OPEN_PRIORITY_MODAL',
          name: 'non-interactive-modal',
          model: {
            title: 'Connection error',
            body: 'Connection to server lost. Trying to reconnect…'
          }
        }); // TODO: Use action creator

        this.disconnectedTimer = null;
      }, 5000);
    });

    ioSocket.on('reconnect', () => {
      const timer = this.disconnectedTimer;

      if (timer) {
        clearTimeout(timer);
      } else {
        this.store.dispatch({ type: 'CLOSE_PRIORITY_MODAL' }); // TODO: Use action creator
      }

      this._emitInit();
    });
  }

  send(request) {
    const promise = new Promise((resolve, reject) => {
      this.sendQueue.push({ request, resolve, reject });

      if (this.sendQueue.length === 1 && this.connected) {
        this._emitReq();
      }
    });

    return promise;
  }

  static _emitInit() {
    const cookie = Cookies.get('mas'); // TODO: Abort if not found
    const maxBacklogMsgs = calcMsgHistorySize();

    ioSocket.emit('init', {
      cookie,
      maxBacklogMsgs,
      clientName: 'web',
      clientOS: navigator.platform,
      version: '1.0',
      cachedUpto: 0 // TODO: Implement local storage based caching
    });

    log.info(`→ INIT: cachedUpto: 0, maxBacklogMsgs: ${maxBacklogMsgs}`);
  }

  _emitReq() {
    if (this.sendQueue.length === 0) {
      return;
    }

    const req = this.sendQueue[0];

    ioSocket.emit('req', req.request, data => {
      log.info('← RESP');
      req.resolve(data);
    });

    this.sendQueue.shift();
    this._emitReq();

    log.info(`→ REQ: ${req.request.id}`);
  }
}

export default new Socket();
<commit_msg>[newclient] Support new refresh session mechanism<commit_after>import io from 'socket.io-client';
import Cookies from 'js-cookie';
import log from './log';
import userInfo from './userInfo';
import calcMsgHistorySize from './msg-history-sizer';

const ioSocket = io.connect(); // Start connection as early as possible.

class Socket {
  constructor() {
    this.sessionId = 0;
    this.connected = false;
    this.sendQueue = [];
    this.disconnectedTimer = null;
    this.maxBacklogMsgs = 0;
  }

  configure(store) {
    this.store = store;
  }

  start() {
    Socket._emitInit();

    ioSocket.on('initok', data => {
      this.connected = true;
      this.sessionId = data.sessionId;
      this.maxBacklogMsgs = data.maxBacklogMsgs;

      userInfo.userId = `m${data.userId}`;

      this._emitReq(); // In case there are items in sendQueue from previous session
    });

    ioSocket.on('terminate', () => {
      Cookies.remove('mas');
      window.location.assign('/');
    });

    ioSocket.on('refresh_session', data => {
      Cookies.set('mas', data.refreshCookie, { expires: 7 });
      ioSocket.emit('refresh_done');
    });

    ioSocket.on('ntf', notification => this.store.dispatch(notification));

    ioSocket.on('disconnect', () => {
      log.info('Socket.io connection lost.');

      this.connected = false;

      this.disconnectedTimer = setTimeout(() => {
        this.store.dispatch({
          type: 'OPEN_PRIORITY_MODAL',
          name: 'non-interactive-modal',
          model: {
            title: 'Connection error',
            body: 'Connection to server lost. Trying to reconnect…'
          }
        }); // TODO: Use action creator

        this.disconnectedTimer = null;
      }, 5000);
    });

    ioSocket.on('reconnect', () => {
      const timer = this.disconnectedTimer;

      if (timer) {
        clearTimeout(timer);
      } else {
        this.store.dispatch({ type: 'CLOSE_PRIORITY_MODAL' }); // TODO: Use action creator
      }

      this._emitInit();
    });
  }

  send(request) {
    const promise = new Promise((resolve, reject) => {
      this.sendQueue.push({ request, resolve, reject });

      if (this.sendQueue.length === 1 && this.connected) {
        this._emitReq();
      }
    });

    return promise;
  }

  static _emitInit() {
    const cookie = Cookies.get('mas'); // TODO: Abort if not found
    const maxBacklogMsgs = calcMsgHistorySize();

    ioSocket.emit('init', {
      cookie,
      maxBacklogMsgs,
      clientName: 'web',
      clientOS: navigator.platform,
      version: '1.0',
      cachedUpto: 0 // TODO: Implement local storage based caching
    });

    log.info(`→ INIT: cachedUpto: 0, maxBacklogMsgs: ${maxBacklogMsgs}`);
  }

  _emitReq() {
    if (this.sendQueue.length === 0) {
      return;
    }

    const req = this.sendQueue[0];

    ioSocket.emit('req', req.request, data => {
      log.info('← RESP');
      req.resolve(data);
    });

    this.sendQueue.shift();
    this._emitReq();

    log.info(`→ REQ: ${req.request.id}`);
  }
}

export default new Socket();
<|endoftext|>


<commit_before>import React from 'react';
import { mount, render } from 'enzyme';
import Radio from '../radio';
import RadioGroup from '../group';
import RadioButton from '../radioButton';

describe('Radio', () => {
  function createRadioGroup(props) {
    return (
      <RadioGroup {...props}>
        <Radio value="A">A</Radio>
        <Radio value="B">B</Radio>
        <Radio value="C">C</Radio>
      </RadioGroup>
    );
  }

  function createRadioGroupByOption(props) {
    const options = [
      { label: 'A', value: 'A' },
      { label: 'B', value: 'B' },
      { label: 'C', value: 'C' },
    ];

    return <RadioGroup {...props} options={options} />;
  }

  it('responses hover events', () => {
    const onMouseEnter = jest.fn();
    const onMouseLeave = jest.fn();

    const wrapper = mount(
      <RadioGroup onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
        <Radio />
      </RadioGroup>,
    );

    wrapper
      .find('div')
      .at(0)
      .simulate('mouseenter');
    expect(onMouseEnter).toHaveBeenCalled();

    wrapper
      .find('div')
      .at(0)
      .simulate('mouseleave');
    expect(onMouseLeave).toHaveBeenCalled();
  });

  it('fire change events when value changes', () => {
    const onChange = jest.fn();

    const wrapper = mount(
      createRadioGroup({
        onChange,
      }),
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(1);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(2);
  });

  it('both of radio and radioGroup will trigger onchange event when they exists', () => {
    const onChange = jest.fn();
    const onChangeRadioGroup = jest.fn();

    const wrapper = mount(
      <RadioGroup onChange={onChangeRadioGroup}>
        <Radio value="A" onChange={onChange}>
          A
        </Radio>
        <Radio value="B" onChange={onChange}>
          B
        </Radio>
        <Radio value="C" onChange={onChange}>
          C
        </Radio>
      </RadioGroup>,
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(1);
    expect(onChangeRadioGroup.mock.calls.length).toBe(1);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(2);
  });

  it('Trigger onChange when both of radioButton and radioGroup exists', () => {
    const onChange = jest.fn();

    const wrapper = mount(
      <RadioGroup onChange={onChange}>
        <RadioButton value="A">A</RadioButton>
        <RadioButton value="B">B</RadioButton>
        <RadioButton value="C">C</RadioButton>
      </RadioGroup>,
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(1);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(2);
  });

  it('should only trigger once when in group with options', () => {
    const onChange = jest.fn();
    const options = [{ label: 'Bamboo', value: 'Bamboo' }];
    const wrapper = mount(<RadioGroup options={options} onChange={onChange} />);

    wrapper.find('input').simulate('change');
    expect(onChange).toHaveBeenCalledTimes(1);
  });

  it("won't fire change events when value not changes", () => {
    const onChange = jest.fn();

    const wrapper = mount(
      createRadioGroup({
        onChange,
      }),
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(0);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(0);
  });

  it('optional should correct render', () => {
    if (process.env.REACT === '15') {
      return;
    }
    const wrapper = mount(createRadioGroupByOption());
    const radios = wrapper.find('input');

    expect(radios.length).toBe(3);
  });

  it('all children should have a name property', () => {
    const GROUP_NAME = 'radiogroup';
    const wrapper = mount(createRadioGroup({ name: GROUP_NAME }));

    wrapper.find('input[type="radio"]').forEach(el => {
      expect(el.props().name).toEqual(GROUP_NAME);
    });
  });

  it('passes prefixCls down to radio', () => {
    const options = [{ label: 'Apple', value: 'Apple' }, { label: 'Orange', value: 'Orange' }];

    const wrapper = render(<RadioGroup prefixCls="my-radio" options={options} />);

    expect(wrapper).toMatchSnapshot();
  });
});
<commit_msg>test(radio): re-check in react 15<commit_after>import React from 'react';
import { mount, render } from 'enzyme';
import Radio from '../radio';
import RadioGroup from '../group';
import RadioButton from '../radioButton';

describe('Radio', () => {
  function createRadioGroup(props) {
    return (
      <RadioGroup {...props}>
        <Radio value="A">A</Radio>
        <Radio value="B">B</Radio>
        <Radio value="C">C</Radio>
      </RadioGroup>
    );
  }

  function createRadioGroupByOption(props) {
    const options = [
      { label: 'A', value: 'A' },
      { label: 'B', value: 'B' },
      { label: 'C', value: 'C' },
    ];

    return <RadioGroup {...props} options={options} />;
  }

  it('responses hover events', () => {
    const onMouseEnter = jest.fn();
    const onMouseLeave = jest.fn();

    const wrapper = mount(
      <RadioGroup onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
        <Radio />
      </RadioGroup>,
    );

    wrapper
      .find('div')
      .at(0)
      .simulate('mouseenter');
    expect(onMouseEnter).toHaveBeenCalled();

    wrapper
      .find('div')
      .at(0)
      .simulate('mouseleave');
    expect(onMouseLeave).toHaveBeenCalled();
  });

  it('fire change events when value changes', () => {
    const onChange = jest.fn();

    const wrapper = mount(
      createRadioGroup({
        onChange,
      }),
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(1);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(2);
  });

  it('both of radio and radioGroup will trigger onchange event when they exists', () => {
    const onChange = jest.fn();
    const onChangeRadioGroup = jest.fn();

    const wrapper = mount(
      <RadioGroup onChange={onChangeRadioGroup}>
        <Radio value="A" onChange={onChange}>
          A
        </Radio>
        <Radio value="B" onChange={onChange}>
          B
        </Radio>
        <Radio value="C" onChange={onChange}>
          C
        </Radio>
      </RadioGroup>,
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(1);
    expect(onChangeRadioGroup.mock.calls.length).toBe(1);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(2);
  });

  it('Trigger onChange when both of radioButton and radioGroup exists', () => {
    const onChange = jest.fn();

    const wrapper = mount(
      <RadioGroup onChange={onChange}>
        <RadioButton value="A">A</RadioButton>
        <RadioButton value="B">B</RadioButton>
        <RadioButton value="C">C</RadioButton>
      </RadioGroup>,
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(1);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(2);
  });

  it('should only trigger once when in group with options', () => {
    const onChange = jest.fn();
    const options = [{ label: 'Bamboo', value: 'Bamboo' }];
    const wrapper = mount(<RadioGroup options={options} onChange={onChange} />);

    wrapper.find('input').simulate('change');
    expect(onChange).toHaveBeenCalledTimes(1);
  });

  it("won't fire change events when value not changes", () => {
    const onChange = jest.fn();

    const wrapper = mount(
      createRadioGroup({
        onChange,
      }),
    );
    const radios = wrapper.find('input');

    // uncontrolled component
    wrapper.setState({ value: 'B' });
    radios.at(1).simulate('change');
    expect(onChange.mock.calls.length).toBe(0);

    // controlled component
    wrapper.setProps({ value: 'A' });
    radios.at(0).simulate('change');
    expect(onChange.mock.calls.length).toBe(0);
  });

  it('optional should correct render', () => {
    const wrapper = mount(createRadioGroupByOption());
    const radios = wrapper.find('input');

    expect(radios.length).toBe(3);
  });

  it('all children should have a name property', () => {
    const GROUP_NAME = 'radiogroup';
    const wrapper = mount(createRadioGroup({ name: GROUP_NAME }));

    wrapper.find('input[type="radio"]').forEach(el => {
      expect(el.props().name).toEqual(GROUP_NAME);
    });
  });

  it('passes prefixCls down to radio', () => {
    const options = [{ label: 'Apple', value: 'Apple' }, { label: 'Orange', value: 'Orange' }];

    const wrapper = render(<RadioGroup prefixCls="my-radio" options={options} />);

    expect(wrapper).toMatchSnapshot();
  });
});
<|endoftext|>


<commit_before>'use strict';

var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var _projectJson = require('./templates/_package.json');
var _projectPath = '';
var log = console.log;
var dir = console.dir;

var XtcGenerator = module.exports = function XtcGenerator(args, options, config) {
	yeoman.generators.Base.apply(this, arguments);

	this.pkg = _projectJson;
	this.projectPath = this.options.path ? path.resolve(process.cwd(), this.options.path) : process.cwd();
	_projectPath = this.projectPath;

	this.on('end', onEnd);

	/*this.on('end', function () {
		this.installDependencies({
			skipInstall: options['skip-install'],
			callback: onDependenciesInstalled.bind(this)
		});
	});*/

	var intro =
		'\n' +
		chalk.magenta("    _/__    _  __  ._  _ _/_  _  _  _ ") + '\n' +
		chalk.magenta("  ></ /_   /_///_///_'/_ /   /_//_'/ /") + '\n' +
		chalk.magenta("          /     |/           _/       ") + '\n\n' +
		chalk.blue(' * express-terrific project generator *\n\n') +
		//chalk.cyan('This generator will install xtc@%s\n') +
		chalk.cyan('Please answer a few questions to set up your new project.\n')
	;

	//log(welcome, _projectJson.dependencies.xtc);
	log(intro);
};

util.inherits(XtcGenerator, yeoman.generators.Base);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NAME AND REPOSITORY

XtcGenerator.prototype.basics = function basics() {
	var cb = this.async()
		,prompts = [
		{
			name: 'name'
			,message: 'Enter a package name for the new project (no spaces)'
			,validate: validateString
		},
		{
			name: 'repoUri'
			,message: '"Read-only" repository URI (https://host/path/to/project.git or blank)'
			,validate: validateGitUri
		}
	];

	this.repository = {};

	this.prompt(prompts, function(props) {
		this.name = props.name;
		this.repository.uri = props.repoUri;
		cb();
	}.bind(this));
};

XtcGenerator.prototype.gitBranch = function gitBranch() {
	var cb, prompts;

	if (!this.repository.uri) { return }
	cb = this.async();

	prompts = [
		{
			name: 'branch'
			,message: 'What branch should be used when linking to project source files'
			,default: 'develop'
		}
	];

	this.prompt(prompts, function(props) {
		this.repository.branch = props.branch;
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHOOSE SERVER AND BUILD PARTS

XtcGenerator.prototype.parts = function parts() {
	var cb = this.async()
		,prompts = [
		{
			name: 'neededParts'
			,type: 'checkbox'
			,message: 'What parts of xtc do you need'
			,choices: [
				{
					name: 'Server'
					,value: 'needServer'
					,checked: true
				}
				,{
					name: 'Build'
					,value: 'needBuild'
					,checked: true
				}
			]
		}
	];

	this.needBuild = false;
	this.needServer = false;
	this.configs = ['"default"'];

	this.prompt(prompts, function(props) {
		var i;
		for (i = 0; i < props.neededParts.length; i++) {
			var value = props.neededParts[i];
			this[value] = true;
		}

		this.needBuild && this.configs.push('"build"');
		this.needServer && this.configs.push('"server"', '"secret"');
		this.configs.push('"local"');
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BUILD CONFIG

XtcGenerator.prototype.glue = function glue() {
	var cb, prompts;

	if (!this.needBuild) { return }
	cb = this.async();

	prompts = [
		{
			name: 'enableSprites'
			,message: 'Enable sprites generation? Note: Needs a working "glue" (Python) installation.'
			,type: 'confirm'
			,default: false
		}
	];

	this.prompt(prompts, function(props) {
		this.enableSprites = props.enableSprites;
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SERVER CONFIG

XtcGenerator.prototype.sitename = function sitename() {
	var cb, prompts;

	if (!this.needServer) { return }
	cb = this.async();

	prompts = [
		{
			name: 'siteName'
			,message: 'Enter the website\'s name'
		}
	];

	this.prompt(prompts, function(props) {
		this.siteName = props.siteName;
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copy Files

XtcGenerator.prototype.copyFiles = function copyFiles() {

	// Project
	this.copy('_package.json', projectPath('package.json'));
	this.copy('_.gitignore', projectPath('.gitignore'));
	//this.copy('_bower.json', 'bower.json');
	//this.copy('editorconfig', '.editorconfig');
	//this.copy('jshintrc', '.jshintrc');

	// Config
	this.mkdir(projectPath('_config'));
	this.copy('_config/configs.json', projectPath('_config/configs.json'));
	this.copy('_config/config-default.js', projectPath('_config/config-default.js'));
	this.copy('_config/config-local.json', projectPath('_config/config-local.json'));

	// README.md
	this.copy('_README.md', projectPath('README.md'));

	// Frontend
	this.directory('frontend-example', projectPath('frontend'));

	// Server
	if (this.needServer) {
		this.copy('_config/config-server.json', projectPath('_config/config-server.json'));
		this.copy('_config/config-secret.json', projectPath('_config/config-secret.json'));
		this.copy('_config/pinned-views.json', projectPath('_config/pinned-views.json'));
		this.directory('_controllers', projectPath('controllers'));

		// Helpers
		this.mkdir(projectPath('lib'));
		this.copy('_lib/handlebars-helpers.js', projectPath('lib/handlebars-helpers.js'));
		//this.copy('server.js', projectPath('server.js'));
	}

	// Build
	if (this.needBuild) {
		this.copy('Gruntfile.js', projectPath('Gruntfile.js'));
		this.copy('_config/config-build.json', projectPath('_config/config-build.json'));
	}

	// Deployment
	/*if (this.buildPackDeployment) {
		this.copy('Procfile', projectPath('Procfile'));
	}*/

};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Outro

//function onDependenciesInstalled() {
function onEnd() {

	var outro =
		'\nInstallation complete!\n\n' +

		chalk.cyan('xtc build')     +'\t\tstarts dev build\n' +
		chalk.cyan('xtc start')     +'\t\tstarts the server\n\n' +

		chalk.cyan('xtc help')      +'\t\tlist available commends\n\n'

		//chalk.cyan('npm run mkmod') +    '\t\tcreate a frontend module\n' +
		//chalk.cyan('npm run mkskin') +    '\t\tcreate a skin for a frontend module\n'
	;
	log(outro);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Helpers

function projectPath(joinPath) {
	return path.join(_projectPath, joinPath);
}

function validateString(value) {
	return typeof value === 'string' && value.length > 0;
}

function validateGitUri(value) {
	return value === '' || /^https:\/\/[\w\.\:/\-~]+\.git$/.test(value);
}<commit_msg>Move generator intro back in a method, so that generator context is available.<commit_after>'use strict';

var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var _projectJson = require('./templates/_package.json');
var _projectPath = '';
var log = console.log;
var dir = console.dir;

var XtcGenerator = module.exports = function XtcGenerator(args, options, config) {
	yeoman.generators.Base.apply(this, arguments);

	this.pkg = _projectJson;
	this.projectPath = this.options.path ? path.resolve(process.cwd(), this.options.path) : process.cwd();
	_projectPath = this.projectPath;

	this.on('end', onEnd);

	/*this.on('end', function () {
		this.installDependencies({
			skipInstall: options['skip-install'],
			callback: onDependenciesInstalled.bind(this)
		});
	});*/

	var intro =
		chalk.cyan('\nxtc@%s\n\n') +
		chalk.magenta("    _/__    _  __  ._  _ _/_  _  _  _ ") + '\n' +
		chalk.magenta("  ></ /_   /_///_///_'/_ /   /_//_'/ /") + '\n' +
		chalk.magenta("          /     |/           _/       ") + '\n\n' +
		chalk.blue(' * express-terrific project generator *\n\n') +
		chalk.cyan('Please answer a few questions to set up your new project.\n')
	;

	log(intro, _projectJson.dependencies.xtc);
};

util.inherits(XtcGenerator, yeoman.generators.Base);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NAME AND REPOSITORY

XtcGenerator.prototype.basics = function basics() {
	var cb = this.async()
		,prompts = [
		{
			name: 'name'
			,message: 'Enter a package name for the new project (no spaces)'
			,validate: validateString
		},
		{
			name: 'repoUri'
			,message: '"Read-only" repository URI (https://host/path/to/project.git or blank)'
			,validate: validateGitUri
		}
	];

	this.repository = {};

	this.prompt(prompts, function(props) {
		this.name = props.name;
		this.repository.uri = props.repoUri;
		cb();
	}.bind(this));
};

XtcGenerator.prototype.gitBranch = function gitBranch() {
	var cb, prompts;

	if (!this.repository.uri) { return }
	cb = this.async();

	prompts = [
		{
			name: 'branch'
			,message: 'What branch should be used when linking to project source files'
			,default: 'develop'
		}
	];

	this.prompt(prompts, function(props) {
		this.repository.branch = props.branch;
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CHOOSE SERVER AND BUILD PARTS

XtcGenerator.prototype.parts = function parts() {
	var cb = this.async()
		,prompts = [
		{
			name: 'neededParts'
			,type: 'checkbox'
			,message: 'What parts of xtc do you need'
			,choices: [
				{
					name: 'Server'
					,value: 'needServer'
					,checked: true
				}
				,{
					name: 'Build'
					,value: 'needBuild'
					,checked: true
				}
			]
		}
	];

	this.needBuild = false;
	this.needServer = false;
	this.configs = ['"default"'];

	this.prompt(prompts, function(props) {
		var i;
		for (i = 0; i < props.neededParts.length; i++) {
			var value = props.neededParts[i];
			this[value] = true;
		}

		this.needBuild && this.configs.push('"build"');
		this.needServer && this.configs.push('"server"', '"secret"');
		this.configs.push('"local"');
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BUILD CONFIG

XtcGenerator.prototype.glue = function glue() {
	var cb, prompts;

	if (!this.needBuild) { return }
	cb = this.async();

	prompts = [
		{
			name: 'enableSprites'
			,message: 'Enable sprites generation? Note: Needs a working "glue" (Python) installation.'
			,type: 'confirm'
			,default: false
		}
	];

	this.prompt(prompts, function(props) {
		this.enableSprites = props.enableSprites;
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SERVER CONFIG

XtcGenerator.prototype.sitename = function sitename() {
	var cb, prompts;

	if (!this.needServer) { return }
	cb = this.async();

	prompts = [
		{
			name: 'siteName'
			,message: 'Enter the website\'s name'
		}
	];

	this.prompt(prompts, function(props) {
		this.siteName = props.siteName;
		cb();
	}.bind(this));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copy Files

XtcGenerator.prototype.copyFiles = function copyFiles() {

	// Project
	this.copy('_package.json', projectPath('package.json'));
	this.copy('_.gitignore', projectPath('.gitignore'));
	//this.copy('_bower.json', 'bower.json');
	//this.copy('editorconfig', '.editorconfig');
	//this.copy('jshintrc', '.jshintrc');

	// Config
	this.mkdir(projectPath('_config'));
	this.copy('_config/configs.json', projectPath('_config/configs.json'));
	this.copy('_config/config-default.js', projectPath('_config/config-default.js'));
	this.copy('_config/config-local.json', projectPath('_config/config-local.json'));

	// README.md
	this.copy('_README.md', projectPath('README.md'));

	// Frontend
	this.directory('frontend-example', projectPath('frontend'));

	// Server
	if (this.needServer) {
		this.copy('_config/config-server.json', projectPath('_config/config-server.json'));
		this.copy('_config/config-secret.json', projectPath('_config/config-secret.json'));
		this.copy('_config/pinned-views.json', projectPath('_config/pinned-views.json'));
		this.directory('_controllers', projectPath('controllers'));

		// Helpers
		this.mkdir(projectPath('lib'));
		this.copy('_lib/handlebars-helpers.js', projectPath('lib/handlebars-helpers.js'));
		//this.copy('server.js', projectPath('server.js'));
	}

	// Build
	if (this.needBuild) {
		this.copy('Gruntfile.js', projectPath('Gruntfile.js'));
		this.copy('_config/config-build.json', projectPath('_config/config-build.json'));
	}

	// Deployment
	/*if (this.buildPackDeployment) {
		this.copy('Procfile', projectPath('Procfile'));
	}*/

};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Outro

//function onDependenciesInstalled() {
function onEnd() {

	var outro =
		'\nInstallation complete!\n\n' +

		chalk.cyan('xtc build')     +'\t\tstarts dev build\n' +
		chalk.cyan('xtc start')     +'\t\tstarts the server\n\n' +

		chalk.cyan('xtc help')      +'\t\tlist available commends\n\n'

		//chalk.cyan('npm run mkmod') +    '\t\tcreate a frontend module\n' +
		//chalk.cyan('npm run mkskin') +    '\t\tcreate a skin for a frontend module\n'
	;
	log(outro);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Helpers

function projectPath(joinPath) {
	return path.join(_projectPath, joinPath);
}

function validateString(value) {
	return typeof value === 'string' && value.length > 0;
}

function validateGitUri(value) {
	return value === '' || /^https:\/\/[\w\.\:/\-~]+\.git$/.test(value);
}<|endoftext|>


<commit_before>/*
**	elation panel component
**
**		Contents:
**			Panel
*/

elation.extend('panel', new function(options) {
  this.options = options;
  this.panels = [];
  this.panelmap = {};

	this.add = function(name, args, data, content, parent) {
    if (!this.panelmap[name]) {
			this.panelmap[name] = this.panels.length;
			this.panels.push(args || {});
    }

		this.Init(name, args);
  }

  this.Init = function(name, args) {
    elation.timing.set(true);
    var panel = this.panels[this.panelmap[name]] || null;

    if (args) {
			if (args.id)
				panel.element = $TF("#"+args.id);

			panel.items = {};
			if (args.cfg && args.cfg.items) {
				$TF.each(args.cfg.items, function(k, v) {
					panel.items[k] = new elation.panel.add_item(k, v, panel);
				});
			}

			if (panel.cfg.jsobject && panel.cfg.jsobject != "false") {
				var obj = eval(panel.cfg.jsobject);

				if (typeof obj == 'function') {
					panel.jsobj = new obj(this, panel);
					elation[panel.name] = panel.jsobj;

          if (typeof panel.jsobj.init == 'function')
            panel.jsobj.init();
				}
			}

			if (panel.cfg.navigation == "true") {
				panel.container = document.getElementById(panel.cfg.targetid);
				this.lis = $TF('div.tf_utils_panel_' + name + ' ul li');;

        for (var i=0; i<this.lis.length; i++)
          if (elation.html.hasclass(this.lis[i], 'selected'))
            panel.li = this.lis[i];

				for (var item in panel.items) {
					var	element = panel.items[item].element;

					if (typeof element == 'object' && element.length > 0) {
						elation.events.add(element[0], 'click', this);
						element[0].onselectstart = function() { return(false); };
					}
				}

				panel.item = this.get_item(panel, $TF('div.tf_utils_panel_' + name + ' ul li.selected')[0]);
			}

			panel.content = {};
		}
    elation.timing.print(name + ' panel', true);
	}

	this.handleEvent = function(event) {
		event = event || window.event;
		target = event.target || event.srcElement;

		switch (event.type) {
			case "click":
				this.click(event, target);
				break;
		}
	}

	this.click = function(event, target) {
		while (target && target.nodeName != 'LI')
			target = target.parentNode;

		if (!target || elation.html.hasclass(target, 'tf_utils_state_disabled'))
			return;

		// find the proper panel for event and item for target
		for (var key in this.panelmap) {
			var	panel	= this.panels[this.panelmap[key]],
					item	= this.get_item(panel, target);

			if (item)
				break;
		}

		if (elation.utils.arrayget(item, 'args.unselectable'))
			return;

		event.preventDefault();
		event.stopPropagation();

		if (item.name == panel.item.name)
			return;

    if (typeof pandoraLog == 'object') {
			pandoraLog.mouseovertype = item.name;
    }

    if (typeof googleAnalytics == 'object') {
      googleAnalytics.mouseovertype = item.name;
      if (item.name == "shoplikeme")
        googleAnalytics.trackEvent(['tab', 'shoplikeme', googleAnalytics.pagetype]);
      else if (item.name == "theweb")
        googleAnalytics.trackEvent(['tab', 'theWeb', googleAnalytics.pagetype]);
			else if (item.name == "nearby")
        googleAnalytics.trackEvent(['tab', 'nearby', googleAnalytics.pagetype]);
      else if (item.name == "shoplikefriends")
        googleAnalytics.trackEvent(['tab', 'shoplikefriends', googleAnalytics.pagetype]);
			else if (item.name == "myfinds")
        googleAnalytics.trackEvent(['tab', 'myfinds', googleAnalytics.pagetype]);
      else
        googleAnalytics.trackEvent(['popup_tab', googleAnalytics.mouseovertype]);
    }

		this.load_tab_content(panel, target, item);
	}

	this.load_tab_content = function(panel, target, item) {
		var	target = (typeof target == 'string')
					? document.getElementById(target)
					: target,
				panel = (typeof panel == 'object')
					? panel
					: this.panels[this.panelmap[panel]],
				item = item || this.get_item(panel, target);

		if (!panel.container) {
			var href = target.getElementsByTagName('a').length > 0
						? target.getElementsByTagName('a')[0].href
						: '';

			if (href) {
				var	input = elation.find('input.tf_search_input_element')[0],
            query = input
              ? input.value
              : '',
						queryString;

				// stop tab switch reloading on default_query
				if (query == elation.default_query)
					query = '';

				if (query)
					query = encodeURIComponent(query);

				(query) ? queryString = (href.indexOf('?') == -1 ? '?' : '&') + 'query=' + query : queryString = '';

				if ((query || !input) && href.search('/myfinds') === -1) {
				  window.location.href = href + queryString;
				} else if (input) {
          // FIXME - quick hack to disable the form-focus thing for tabs since we now have homepages for all of them
					if (true || href.search('/myfinds') !== -1) {
						window.location.href = href;
					}
					else {
						var form = elation.utils.getParent(input, 'FORM');

						if (form)
							form.action = href;

						elation.html.addclass(input, 'tf_util_form_error');
						input.focus();
					}
				}
			}

			this.select_item(item, panel);

			return panel.item = item;
		}

		this.select_item(item, panel);

		// cache content of tab for later retrieval
		if (!panel.cfg.nocache) {
			if ($TF('img.tf_results_ajax_spinner',panel.container).length == 0) // kludgy - dont save content if content still loading
				panel.content[panel.item.name] = panel.container.innerHTML;
			}
			panel.item = item;

			if (!panel.cfg.nocache) {
			// if cached copy exists use that
			if (panel.content[item.name])
				return panel.container.innerHTML = panel.content[item.name];
		} else {
			// tab fade-in effect
			if (elation.browser && elation.browser.type != 'msie')
				$TF(panel.container).animate({ opacity: 0 }, 'fast');
		}
		if (!panel.container.style.minHeight)
			panel.container.style.minHeight = panel.container.offsetHeight + 'px';

		if (panel.cfg.spinner)
			panel.container.innerHTML = panel.cfg.spinner;

		// Merge args from both the panel and any specified contentcomponentargs
		var urlargs = {};

		if (typeof panel.args == 'object')
			for (var k in panel.args)
				if (panel.args.hasOwnProperty(k))
					urlargs[k] = panel.args[k];

		if (typeof item.args.contentcomponentargs == 'object')
			for (var k in item.args.contentcomponentargs)
				if (item.args.contentcomponentargs.hasOwnProperty(k))
					urlargs[k] = item.args.contentcomponentargs[k];

		urlargs['targetid'] = panel.cfg.targetid;
		urlargs['tab'] = item.args.argname;
		panel.active_argname = item.args.argname;

		var parms = elation.utils.encodeURLParams(urlargs);

		if (panel.jsobj) {
      if (typeof panel.jsobj.setTab == 'function')
        panel.jsobj.setTab(target, item, panel);

      if (panel.jsobj.args)
        parms = parms + (parms ? '&' : '') + elation.utils.encodeURLParams(panel.jsobj.args);
		}

		var componentname = item.args.contentcomponent || panel.cfg.contentcomponent;

		// ajax-fetch tab content
		ajaxlib.Queue({
			url: componentname,
			args: parms,
			callback: [
				this,
				function(response) {
					// tab fade-in effect
					if (elation.browser && elation.browser.type != 'msie')
						$TF(panel.container).css({ opacity: 0 })
							.animate({ opacity: 1 }, 'fast')
							.animate({ opacity: 'auto' }, 0);

          if (panel.jsobj && typeof panel.jsobj.success == 'function') {
            panel.jsobj.success(response);
          }
        }
			]
		});
	}

	this.select_item = function(item, panel) {
		var	li = elation.utils.arrayget(item, 'element'),
        li = li.length > 0 ? li[0] : li;

		if (elation.html.hasclass(li, 'tf_utils_state_disabled'))
			return;

		if (panel.li)
			elation.html.removeclass(panel.li, 'selected');

		elation.html.addclass(li, 'selected');

		return panel.li = li;
	}

  this.set_args = function(panelname, args) {
		var panel, item;

  	if (panel = this.panels[this.panelmap[panelname]]) {
      for (var key in args)
        elation.utils.arrayset(panel.args, key, args[key]);

			for (var item_key in panel.items) {
				item = panel.items[item_key];
				if ((item.args.disableiffalse && !elation.utils.isTrue(args[item.args.disableiffalse])) || (item.args.disableiftrue && elation.utils.isTrue(args[item.args.disableiftrue])) || (item.args.disableifempty && elation.utils.isEmpty(args[item.args.disableifempty]))) {
					elation.html.addclass(item.element[0], 'tf_utils_state_disabled');

          if(item.args.disabledtype)
  					elation.html.addclass(item.element[0], 'tf_utils_state_disabled_'+item.args.disabledtype);
        }
			}
		}
  }

	this.get_item = function(panel, target) {
		for (var key in panel.items) {
			var	item = panel.items[key],
					element = item.element[0];

			if (target == element)
				return item;
		}

		return false;
	}

  this.add_item = function(name, args, panel, content) {
    this.name = name;
    this.args = args || {};
    this.panel = panel;

    this.init = function() {
      if (!this.panel)
				return;

			this.element = $TF("ul.tf_utils_panel_content li#" + this.panel.id + "_" + this.name);

			if (this.args.contentcomponent && !this.args.nopopup && this.element.length > 0) {
				var panelname = this.panel.name.replace(/\./g, "_") + "_" + this.name;

				elation.ui.infobox.add(
					panelname,
					{
						width:			this.args.contentwidth		|| '20em',
						titlebar:		this.args.contenttitle		|| true,
						label:			this.args.contentlabel		|| false,
						loading:		this.args.contentloading	|| false,
            fullscreen: this.args.fullscreen			|| false,
            absolute:   this.args.absolute				|| false,
            animation:  this.args.animation			|| '',
						lightbox: 	'tf_infobox_lightbox',
						border:			'div',
						classname:	'tf_myfinds_infobox_popup',
						activecss:	'tf_myfinds_infobox_selected',
						bgcolor:		'white',
						event:			'click',
						tailsrc:		'div',
            killscroll: true,
						vertical:		true,
						nocache:		true,
						resize:   	true,
						ajax:				true
					},
					this.args.contentcomponentargs || null,
					"/" + this.args.contentcomponent.replace(/\./, "/"),
					this.element[0]
				);
			}
    }

    this.init();
  }
});
<commit_msg>for errors on no panel<commit_after>/*
**	elation panel component
**
**		Contents:
**			Panel
*/

elation.extend('panel', new function(options) {
  this.options = options;
  this.panels = [];
  this.panelmap = {};

	this.add = function(name, args, data, content, parent) {
    if (!this.panelmap[name]) {
			this.panelmap[name] = this.panels.length;
			this.panels.push(args || {});
    }

		this.Init(name, args);
  }

  this.Init = function(name, args) {
    elation.timing.set(true);
    var panel = this.panels[this.panelmap[name]] || null;

    if (args) {
			if (args.id)
				panel.element = $TF("#"+args.id);

			panel.items = {};
			if (args.cfg && args.cfg.items) {
				$TF.each(args.cfg.items, function(k, v) {
					panel.items[k] = new elation.panel.add_item(k, v, panel);
				});
			}
      if (panel.cfg) {
        if (panel.cfg.jsobject && panel.cfg.jsobject != "false") {
          var obj = eval(panel.cfg.jsobject);

          if (typeof obj == 'function') {
            panel.jsobj = new obj(this, panel);
            elation[panel.name] = panel.jsobj;

            if (typeof panel.jsobj.init == 'function')
              panel.jsobj.init();
          }
        }

        if (panel.cfg.navigation == "true") {
          panel.container = document.getElementById(panel.cfg.targetid);
          this.lis = $TF('div.tf_utils_panel_' + name + ' ul li');;

          for (var i=0; i<this.lis.length; i++)
            if (elation.html.hasclass(this.lis[i], 'selected'))
              panel.li = this.lis[i];

          for (var item in panel.items) {
            var	element = panel.items[item].element;

            if (typeof element == 'object' && element.length > 0) {
              elation.events.add(element[0], 'click', this);
              element[0].onselectstart = function() { return(false); };
            }
          }

          panel.item = this.get_item(panel, $TF('div.tf_utils_panel_' + name + ' ul li.selected')[0]);
        }
      }
			panel.content = {};
		}
    elation.timing.print(name + ' panel', true);
	}

	this.handleEvent = function(event) {
		event = event || window.event;
		target = event.target || event.srcElement;

		switch (event.type) {
			case "click":
				this.click(event, target);
				break;
		}
	}

	this.click = function(event, target) {
		while (target && target.nodeName != 'LI')
			target = target.parentNode;

		if (!target || elation.html.hasclass(target, 'tf_utils_state_disabled'))
			return;

		// find the proper panel for event and item for target
		for (var key in this.panelmap) {
			var	panel	= this.panels[this.panelmap[key]],
					item	= this.get_item(panel, target);

			if (item)
				break;
		}

		if (elation.utils.arrayget(item, 'args.unselectable'))
			return;

		event.preventDefault();
		event.stopPropagation();

		if (item.name == panel.item.name)
			return;

    if (typeof pandoraLog == 'object') {
			pandoraLog.mouseovertype = item.name;
    }

    if (typeof googleAnalytics == 'object') {
      googleAnalytics.mouseovertype = item.name;
      if (item.name == "shoplikeme")
        googleAnalytics.trackEvent(['tab', 'shoplikeme', googleAnalytics.pagetype]);
      else if (item.name == "theweb")
        googleAnalytics.trackEvent(['tab', 'theWeb', googleAnalytics.pagetype]);
			else if (item.name == "nearby")
        googleAnalytics.trackEvent(['tab', 'nearby', googleAnalytics.pagetype]);
      else if (item.name == "shoplikefriends")
        googleAnalytics.trackEvent(['tab', 'shoplikefriends', googleAnalytics.pagetype]);
			else if (item.name == "myfinds")
        googleAnalytics.trackEvent(['tab', 'myfinds', googleAnalytics.pagetype]);
      else
        googleAnalytics.trackEvent(['popup_tab', googleAnalytics.mouseovertype]);
    }

		this.load_tab_content(panel, target, item);
	}

	this.load_tab_content = function(panel, target, item) {
		var	target = (typeof target == 'string')
					? document.getElementById(target)
					: target,
				panel = (typeof panel == 'object')
					? panel
					: this.panels[this.panelmap[panel]],
				item = item || this.get_item(panel, target);

		if (!panel.container) {
			var href = target.getElementsByTagName('a').length > 0
						? target.getElementsByTagName('a')[0].href
						: '';

			if (href) {
				var	input = elation.find('input.tf_search_input_element')[0],
            query = input
              ? input.value
              : '',
						queryString;

				// stop tab switch reloading on default_query
				if (query == elation.default_query)
					query = '';

				if (query)
					query = encodeURIComponent(query);

				(query) ? queryString = (href.indexOf('?') == -1 ? '?' : '&') + 'query=' + query : queryString = '';

				if ((query || !input) && href.search('/myfinds') === -1) {
				  window.location.href = href + queryString;
				} else if (input) {
          // FIXME - quick hack to disable the form-focus thing for tabs since we now have homepages for all of them
					if (true || href.search('/myfinds') !== -1) {
						window.location.href = href;
					}
					else {
						var form = elation.utils.getParent(input, 'FORM');

						if (form)
							form.action = href;

						elation.html.addclass(input, 'tf_util_form_error');
						input.focus();
					}
				}
			}

			this.select_item(item, panel);

			return panel.item = item;
		}

		this.select_item(item, panel);

		// cache content of tab for later retrieval
		if (!panel.cfg.nocache) {
			if ($TF('img.tf_results_ajax_spinner',panel.container).length == 0) // kludgy - dont save content if content still loading
				panel.content[panel.item.name] = panel.container.innerHTML;
			}
			panel.item = item;

			if (!panel.cfg.nocache) {
			// if cached copy exists use that
			if (panel.content[item.name])
				return panel.container.innerHTML = panel.content[item.name];
		} else {
			// tab fade-in effect
			if (elation.browser && elation.browser.type != 'msie')
				$TF(panel.container).animate({ opacity: 0 }, 'fast');
		}
		if (!panel.container.style.minHeight)
			panel.container.style.minHeight = panel.container.offsetHeight + 'px';

		if (panel.cfg.spinner)
			panel.container.innerHTML = panel.cfg.spinner;

		// Merge args from both the panel and any specified contentcomponentargs
		var urlargs = {};

		if (typeof panel.args == 'object')
			for (var k in panel.args)
				if (panel.args.hasOwnProperty(k))
					urlargs[k] = panel.args[k];

		if (typeof item.args.contentcomponentargs == 'object')
			for (var k in item.args.contentcomponentargs)
				if (item.args.contentcomponentargs.hasOwnProperty(k))
					urlargs[k] = item.args.contentcomponentargs[k];

		urlargs['targetid'] = panel.cfg.targetid;
		urlargs['tab'] = item.args.argname;
		panel.active_argname = item.args.argname;

		var parms = elation.utils.encodeURLParams(urlargs);

		if (panel.jsobj) {
      if (typeof panel.jsobj.setTab == 'function')
        panel.jsobj.setTab(target, item, panel);

      if (panel.jsobj.args)
        parms = parms + (parms ? '&' : '') + elation.utils.encodeURLParams(panel.jsobj.args);
		}

		var componentname = item.args.contentcomponent || panel.cfg.contentcomponent;

		// ajax-fetch tab content
		ajaxlib.Queue({
			url: componentname,
			args: parms,
			callback: [
				this,
				function(response) {
					// tab fade-in effect
					if (elation.browser && elation.browser.type != 'msie')
						$TF(panel.container).css({ opacity: 0 })
							.animate({ opacity: 1 }, 'fast')
							.animate({ opacity: 'auto' }, 0);

          if (panel.jsobj && typeof panel.jsobj.success == 'function') {
            panel.jsobj.success(response);
          }
        }
			]
		});
	}

	this.select_item = function(item, panel) {
		var	li = elation.utils.arrayget(item, 'element'),
        li = li.length > 0 ? li[0] : li;

		if (elation.html.hasclass(li, 'tf_utils_state_disabled'))
			return;

		if (panel.li)
			elation.html.removeclass(panel.li, 'selected');

		elation.html.addclass(li, 'selected');

		return panel.li = li;
	}

  this.set_args = function(panelname, args) {
		var panel, item;

  	if (panel = this.panels[this.panelmap[panelname]]) {
      for (var key in args)
        elation.utils.arrayset(panel.args, key, args[key]);

			for (var item_key in panel.items) {
				item = panel.items[item_key];
				if ((item.args.disableiffalse && !elation.utils.isTrue(args[item.args.disableiffalse])) || (item.args.disableiftrue && elation.utils.isTrue(args[item.args.disableiftrue])) || (item.args.disableifempty && elation.utils.isEmpty(args[item.args.disableifempty]))) {
					elation.html.addclass(item.element[0], 'tf_utils_state_disabled');

          if(item.args.disabledtype)
  					elation.html.addclass(item.element[0], 'tf_utils_state_disabled_'+item.args.disabledtype);
        }
			}
		}
  }

	this.get_item = function(panel, target) {
		for (var key in panel.items) {
			var	item = panel.items[key],
					element = item.element[0];

			if (target == element)
				return item;
		}

		return false;
	}

  this.add_item = function(name, args, panel, content) {
    this.name = name;
    this.args = args || {};
    this.panel = panel;

    this.init = function() {
      if (!this.panel)
				return;

			this.element = $TF("ul.tf_utils_panel_content li#" + this.panel.id + "_" + this.name);

			if (this.args.contentcomponent && !this.args.nopopup && this.element.length > 0) {
				var panelname = this.panel.name.replace(/\./g, "_") + "_" + this.name;

				elation.ui.infobox.add(
					panelname,
					{
						width:			this.args.contentwidth		|| '20em',
						titlebar:		this.args.contenttitle		|| true,
						label:			this.args.contentlabel		|| false,
						loading:		this.args.contentloading	|| false,
            fullscreen: this.args.fullscreen			|| false,
            absolute:   this.args.absolute				|| false,
            animation:  this.args.animation			|| '',
						lightbox: 	'tf_infobox_lightbox',
						border:			'div',
						classname:	'tf_myfinds_infobox_popup',
						activecss:	'tf_myfinds_infobox_selected',
						bgcolor:		'white',
						event:			'click',
						tailsrc:		'div',
            killscroll: true,
						vertical:		true,
						nocache:		true,
						resize:   	true,
						ajax:				true
					},
					this.args.contentcomponentargs || null,
					"/" + this.args.contentcomponent.replace(/\./, "/"),
					this.element[0]
				);
			}
    }

    this.init();
  }
});
<|endoftext|>


<commit_before>
function renderGaugeItems () {
  updateDataFromGauageItems();
  renderGaugeItemsFromScratch();
}

function updateDataFromGauageItems () {
  $.each(gauge_data, function (index, item) {
    item['time'] = new Date();
  });
}

function renderGaugeItemsFromScratch () {
  var guage_row = $('
', { class: "row", id: "gauge-row"});
  $.each(gauge_data, function (index, item) {
    guage_row.append(createGaugeBox(item));
  });
  $("#gauge-row").replaceWith(guage_row);
}

function createGaugeBox (item_data) {
  var _div = $("
", { class: "col-lg-2 col-xs-6"});
  var _div_color = $("
", { class: "small-box " + item_data.color });
  var _div_text = $("
", { class: "inner"});

  var _div_value = $("
", { text: item_data.value });
  if (item_data.unit) {
    $("", { style: "font-size: 20px", text: item_data.unit }).appendTo(_div_value);
  }
  _div_value.appendTo(_div_text);
  $("
", { text: item_data.name }).appendTo(_div_text);
  _div_text.appendTo(_div_color);

  var _div_icon = $("
", { class: "icon"}).append($("", { class: item_data.icon}));
  _div_icon.appendTo(_div_color);

  var _str_time = "Updated at " + $.format.date(item_data.time, 'MM/dd HH:mm:ss') + " ";
  var _div_time = $("
", { class: "small-box-footer", href: "#", text: _str_time });
  _div_time.append($("", { class: "fa fa-arrow-circle-right"}));
  _div_time.appendTo(_div_color);

  // $('More info ').appendTo(_div_color);

  _div_color.appendTo(_div);

  return _div;
}
<commit_msg>Make value in gauge data varies randomly<commit_after>
function renderGaugeItems () {
  updateDataForGauageItems();
  renderGaugeItemsFromScratch();
}

function updateDataForGauageItems () {
  $.each(gauge_data, function (index, item) {
    item['time'] = new Date();
    item['value'] *= 1 + (Math.random() - 0.5) * 0.1;
  });
}

function renderGaugeItemsFromScratch () {
  var guage_row = $('
', { class: "row", id: "gauge-row"});
  $.each(gauge_data, function (index, item) {
    guage_row.append(createGaugeBox(item));
  });
  $("#gauge-row").replaceWith(guage_row);
}

function createGaugeBox (item_data) {
  var _div = $("
", { class: "col-lg-2 col-xs-6"});
  var _div_color = $("
", { class: "small-box " + item_data.color });
  var _div_text = $("
", { class: "inner"});

  var _div_value = $("
", { text: item_data.value.toFixed(3) });
  if (item_data.unit) {
    $("", { style: "font-size: 20px", text: item_data.unit }).appendTo(_div_value);
  }
  _div_value.appendTo(_div_text);
  $("
", { text: item_data.name }).appendTo(_div_text);
  _div_text.appendTo(_div_color);

  var _div_icon = $("
", { class: "icon"}).append($("", { class: item_data.icon}));
  _div_icon.appendTo(_div_color);

  var _str_time = "Updated at " + $.format.date(item_data.time, 'MM/dd HH:mm:ss') + " ";
  var _div_time = $("
", { class: "small-box-footer", href: "#", text: _str_time });
  _div_time.append($("", { class: "fa fa-arrow-circle-right"}));
  _div_time.appendTo(_div_color);

  _div_color.appendTo(_div);

  return _div;
}
<|endoftext|>


<commit_before>var gImageForward = {

    minHeightPreferencesKey: "extensions.imageforward.minHeight",
    minWidthPreferencesKey: "extensions.imageforward.minWidth",
    linkURLRegexpPreferencesKey: "extensions.imageforward.linkURLRegExp",
    imageURLRegexpPreferencesKey: "extensions.imageforward.imageURLRegExp",

    preferences: Components
                     .classes["@mozilla.org/preferences-service;1"]
                     .getService(Components.interfaces.nsIPrefService),

    onLoad: function() {
        if ('undefined' == typeof gBrowser) {
            return;
        }
        window.removeEventListener('load', gImageForward.onLoad, false);
        window.addEventListener('unload', gImageForward.onUnload, false);
    },

    onUnload: function() {
        window.removeEventListener('unload', gImageForward.onUnload, false);
    },

    iterateImages: function() {
        gImageForward.go(function(document){return document.images}, gImageForward.filterImages);
    },

    iterateImageLinks: function() {
        gImageForward.go(function(document){return document.links}, gImageForward.matchLinkURLs);
    },

    go: function(extractorFunction, filterFunction) {
        var browser = gBrowser.selectedBrowser;
        if (!browser) {
            return;
        }
        if (!browser.imageForwardLinks) {
            var documents = gImageForward.getDocuments();
            var urlsAndReferrers =
                gImageForward.getURLsAndReferrers(documents, extractorFunction, filterFunction);
            if (urlsAndReferrers.length == 0) {
                return;
            }
            gImageForward.initialize(browser, urlsAndReferrers);
        }
        // need to keep track of back/forward movements and new pages
        gImageForward.ensureHistoryListener(browser);
        // user went in back in history, just go forward in history
        if (browser.imageForwardHistoryAdjust < 0) {
            browser.contentWindow.history.forward();
            return;
        }
        // reached last image, go back in history to initial page
        if (browser.imageForwardNextIndex > browser.imageForwardLinks.length - 1) {
            // have to manually keep track of steps taken forward as urls can
            // skip history when iterating to fast
            // browser.imageForwardLinks.length would point to before the
            // initial page then
            var backToStartAdjustment = -browser.imageForwardHistoryIndex;
            gImageForward.reset(browser);
            browser.contentWindow.history.go(backToStartAdjustment);
            return;
        }
        // actually load the next image
        gImageForward.goForward(browser);
    },

    initialize: function(browser, urlsAndReferrers) {
        browser.imageForwardLinks = urlsAndReferrers;
        browser.imageForwardNextIndex = 0;
        browser.imageForwardHistoryAdjust = 0;
        browser.imageForwardHistoryIndex = 0;
    },

    reset: function(browser) {
        browser.imageForwardLinks = undefined;
        browser.imageForwardNextIndex = -1;
        browser.imageForwardHistoryAdjust = 0;
        browser.imageForwardHistoryIndex = 0;
    },

    getDocuments: function() {
        var documents = new Array();
        documents.push(gBrowser.selectedBrowser.contentWindow.document);
        for(var index = 0; index < gBrowser.selectedBrowser.contentWindow.frames.length; index++) {
            documents.push(gBrowser.selectedBrowser.contentWindow.frames[index].document);
        }
        return documents;
    },

    goForward: function(browser) {
        var urlAndReferrer = browser.imageForwardLinks[browser.imageForwardNextIndex];
        var url = urlAndReferrer[0];
        if (url.indexOf("file://") == 0) {
            // can't use loadURI for local links - that's ok, no need for referrer here
            browser.contentDocument.location.assign(url)
        } else {
            var referrerURL = urlAndReferrer[1];
            browser.loadURI(url, makeURI(referrerURL), null);
        }
        browser.imageForwardNextIndex += 1;
    },

    getURLsAndReferrers: function(documents, extractorFunction, filterFunction) {
        var result = new Array()
        for(var documentIndex = 0; documentIndex < documents.length; documentIndex++) {
            var extractedThings = extractorFunction(documents[documentIndex]);
            var urls = filterFunction(extractedThings);
            var referrer = documents[documentIndex].URL;
            for(var urlIndex = 0; urlIndex < urls.length; urlIndex++) {
                result.push(gImageForward.makeTuple(urls[urlIndex], referrer));
            }
        }
        return result;
    },

    makeTuple: function(first, second) {
        var tuple = new Array()
        tuple.push(first);
        tuple.push(second);
        return tuple;
    },

    filterImages: function(images) {
        var result = new Array();
        var minHeight = gImageForward.preferences.getIntPref(gImageForward.minHeightPreferencesKey);
        var minWidth = gImageForward.preferences.getIntPref(gImageForward.minWidthPreferencesKey);
        var regexpString = gImageForward.preferences.getCharPref(gImageForward.imageURLRegexpPreferencesKey);
        var regexp = new RegExp(regexpString, "i");
        for(var index = 0; index < images.length; index++) {
            var image = images[index];
            var imageURL = image.src;
            var isMatch = imageURL.match(regexp);
            var isHighEnough = image.height >= minHeight;
            var isWideEnough = image.width >= minWidth;
            var isKnown = result.indexOf(imageURL) >= 0;
            if (isMatch && !isKnown && isHighEnough && isWideEnough) {
                result.push(imageURL);
            }
        }
        return result;
    },

    matchLinkURLs: function(urls) {
        var result = new Array();
        var regexpString = gImageForward.preferences.getCharPref(gImageForward.linkURLRegexpPreferencesKey);
        var regexp = new RegExp(regexpString, "i");
        for(var index = 0; index < urls.length; index++) {
            var urlString = urls[index].toString();
            var isMatch = urlString.match(regexp);
            var isKnown = result.indexOf(urlString) >= 0;
            if (isMatch && !isKnown) {
                result.push(urlString);
            }
        }
        return result;
    },

    ensureHistoryListener: function(browser) {
        if (browser.imageForwardListener) {
            return
        }
        // need to keep a reference, seems to be garbage collected otherwise
        browser.imageForwardListener = gImageForward.historyListener(browser);
        browser.sessionHistory.addSHistoryListener(browser.imageForwardListener);
    },

    containsURL: function(urlsAndReferrers, url) {
        for(var index = 0; index < urlsAndReferrers.length; index++) {
            if (urlsAndReferrers[index][0] == url){
                return true;
            }
        }
        return false;
    },

    historyListener: function(browser) {
        return {
            QueryInterface: XPCOMUtils.generateQI([
                Components.interfaces.nsISHistoryListener,
                Components.interfaces.nsISupports,
                Components.interfaces.nsISupportsWeakReference
            ]),

            OnHistoryGoBack: function (uri) {
                console.log("HistoryGoBack");
                // TODO reset when back on start
                if (browser.imageForwardLinks){
                    browser.imageForwardHistoryAdjust -= 1;
                }
                return true;
            },

            OnHistoryGoForward: function (uri) {
                console.log("HistoryGoForward");
                if (browser.imageForwardLinks){
                    browser.imageForwardHistoryAdjust += 1;
                }
                return true;
            },

            OnHistoryGotoIndex: function (index, uri) {
                console.log("HistoryGotoIndex " + index);
                // TODO reset when back on start
                if (browser.imageForwardLinks){
                    browser.imageForwardHistoryAdjust = index - browser.sessionHistory.index;
                }
                return true;
            },

            OnHistoryNewEntry: function (uri) {
                console.log("HistoryNewEntry");
                if (browser.imageForwardLinks){
                    if (gImageForward.containsURL(browser.imageForwardLinks, uri.asciiSpec)) {
                        browser.imageForwardHistoryIndex += 1;
                    } else {
                        gImageForward.reset(browser);
                    }
                }
                return true;
            }
        }
    }
};

window.addEventListener('load', gImageForward.onLoad, false);

<commit_msg>Better naming<commit_after>var gImageForward = {

    minHeightPreferencesKey: "extensions.imageforward.minHeight",
    minWidthPreferencesKey: "extensions.imageforward.minWidth",
    linkURLRegexpPreferencesKey: "extensions.imageforward.linkURLRegExp",
    imageURLRegexpPreferencesKey: "extensions.imageforward.imageURLRegExp",

    preferences: Components
                     .classes["@mozilla.org/preferences-service;1"]
                     .getService(Components.interfaces.nsIPrefService),

    onLoad: function() {
        if ('undefined' == typeof gBrowser) {
            return;
        }
        window.removeEventListener('load', gImageForward.onLoad, false);
        window.addEventListener('unload', gImageForward.onUnload, false);
    },

    onUnload: function() {
        window.removeEventListener('unload', gImageForward.onUnload, false);
    },

    iterateImages: function() {
        gImageForward.go(function(document){return document.images}, gImageForward.filterImages);
    },

    iterateImageLinks: function() {
        gImageForward.go(function(document){return document.links}, gImageForward.matchLinkURLs);
    },

    go: function(extractorFunction, filterFunction) {
        var browser = gBrowser.selectedBrowser;
        if (!browser) {
            return;
        }
        if (!browser.imageForwardLinks) {
            var documents = gImageForward.getDocuments();
            var urlsAndReferrers =
                gImageForward.getURLsAndReferrers(documents, extractorFunction, filterFunction);
            if (urlsAndReferrers.length == 0) {
                return;
            }
            gImageForward.initialize(browser, urlsAndReferrers);
        }
        // need to keep track of back/forward movements and new pages
        gImageForward.ensureHistoryListener(browser);
        // user went in back in history, just go forward in history
        if (browser.imageForwardHistoryAdjust < 0) {
            browser.contentWindow.history.forward();
            return;
        }
        // reached last image, go back in history to initial page
        if (browser.imageForwardNextIndex > browser.imageForwardLinks.length - 1) {
            // have to manually keep track of steps taken forward as urls can
            // skip history when iterating to fast
            // browser.imageForwardLinks.length would point to before the
            // initial page then
            var backToStartAdjustment = -browser.imageForwardHistoryIndex;
            gImageForward.reset(browser);
            browser.contentWindow.history.go(backToStartAdjustment);
            return;
        }
        gImageForward.loadNextImage(browser);
    },

    initialize: function(browser, urlsAndReferrers) {
        browser.imageForwardLinks = urlsAndReferrers;
        browser.imageForwardNextIndex = 0;
        browser.imageForwardHistoryAdjust = 0;
        browser.imageForwardHistoryIndex = 0;
    },

    reset: function(browser) {
        browser.imageForwardLinks = undefined;
        browser.imageForwardNextIndex = -1;
        browser.imageForwardHistoryAdjust = 0;
        browser.imageForwardHistoryIndex = 0;
    },

    getDocuments: function() {
        var documents = new Array();
        documents.push(gBrowser.selectedBrowser.contentWindow.document);
        for(var index = 0; index < gBrowser.selectedBrowser.contentWindow.frames.length; index++) {
            documents.push(gBrowser.selectedBrowser.contentWindow.frames[index].document);
        }
        return documents;
    },

    loadNextImage: function(browser) {
        var urlAndReferrer = browser.imageForwardLinks[browser.imageForwardNextIndex];
        var url = urlAndReferrer[0];
        if (url.indexOf("file://") == 0) {
            // can't use loadURI for local links - that's ok, no need for referrer here
            browser.contentDocument.location.assign(url)
        } else {
            var referrerURL = urlAndReferrer[1];
            browser.loadURI(url, makeURI(referrerURL), null);
        }
        browser.imageForwardNextIndex += 1;
    },

    getURLsAndReferrers: function(documents, extractorFunction, filterFunction) {
        var result = new Array()
        for(var documentIndex = 0; documentIndex < documents.length; documentIndex++) {
            var extractedThings = extractorFunction(documents[documentIndex]);
            var urls = filterFunction(extractedThings);
            var referrer = documents[documentIndex].URL;
            for(var urlIndex = 0; urlIndex < urls.length; urlIndex++) {
                result.push(gImageForward.makeTuple(urls[urlIndex], referrer));
            }
        }
        return result;
    },

    makeTuple: function(first, second) {
        var tuple = new Array()
        tuple.push(first);
        tuple.push(second);
        return tuple;
    },

    filterImages: function(images) {
        var result = new Array();
        var minHeight = gImageForward.preferences.getIntPref(gImageForward.minHeightPreferencesKey);
        var minWidth = gImageForward.preferences.getIntPref(gImageForward.minWidthPreferencesKey);
        var regexpString = gImageForward.preferences.getCharPref(gImageForward.imageURLRegexpPreferencesKey);
        var regexp = new RegExp(regexpString, "i");
        for(var index = 0; index < images.length; index++) {
            var image = images[index];
            var imageURL = image.src;
            var isMatch = imageURL.match(regexp);
            var isHighEnough = image.height >= minHeight;
            var isWideEnough = image.width >= minWidth;
            var isKnown = result.indexOf(imageURL) >= 0;
            if (isMatch && !isKnown && isHighEnough && isWideEnough) {
                result.push(imageURL);
            }
        }
        return result;
    },

    matchLinkURLs: function(urls) {
        var result = new Array();
        var regexpString = gImageForward.preferences.getCharPref(gImageForward.linkURLRegexpPreferencesKey);
        var regexp = new RegExp(regexpString, "i");
        for(var index = 0; index < urls.length; index++) {
            var urlString = urls[index].toString();
            var isMatch = urlString.match(regexp);
            var isKnown = result.indexOf(urlString) >= 0;
            if (isMatch && !isKnown) {
                result.push(urlString);
            }
        }
        return result;
    },

    ensureHistoryListener: function(browser) {
        if (browser.imageForwardListener) {
            return
        }
        // need to keep a reference, seems to be garbage collected otherwise
        browser.imageForwardListener = gImageForward.historyListener(browser);
        browser.sessionHistory.addSHistoryListener(browser.imageForwardListener);
    },

    containsURL: function(urlsAndReferrers, url) {
        for(var index = 0; index < urlsAndReferrers.length; index++) {
            if (urlsAndReferrers[index][0] == url){
                return true;
            }
        }
        return false;
    },

    historyListener: function(browser) {
        return {
            QueryInterface: XPCOMUtils.generateQI([
                Components.interfaces.nsISHistoryListener,
                Components.interfaces.nsISupports,
                Components.interfaces.nsISupportsWeakReference
            ]),

            OnHistoryGoBack: function (uri) {
                console.log("HistoryGoBack");
                // TODO reset when back on start
                if (browser.imageForwardLinks){
                    browser.imageForwardHistoryAdjust -= 1;
                }
                return true;
            },

            OnHistoryGoForward: function (uri) {
                console.log("HistoryGoForward");
                if (browser.imageForwardLinks){
                    browser.imageForwardHistoryAdjust += 1;
                }
                return true;
            },

            OnHistoryGotoIndex: function (index, uri) {
                console.log("HistoryGotoIndex " + index);
                // TODO reset when back on start
                if (browser.imageForwardLinks){
                    browser.imageForwardHistoryAdjust = index - browser.sessionHistory.index;
                }
                return true;
            },

            OnHistoryNewEntry: function (uri) {
                console.log("HistoryNewEntry");
                if (browser.imageForwardLinks){
                    if (gImageForward.containsURL(browser.imageForwardLinks, uri.asciiSpec)) {
                        browser.imageForwardHistoryIndex += 1;
                    } else {
                        gImageForward.reset(browser);
                    }
                }
                return true;
            }
        }
    }
};

window.addEventListener('load', gImageForward.onLoad, false);

<|endoftext|>