<commit_before>import { AbstractPlugin, CONSTANTS, DEFAULTS, PSVError, registerButton, utils } from 'photo-sphere-viewer';
import GyroscopePlugin from 'photo-sphere-viewer/plugins/gyroscope';
import * as THREE from 'three';
import 'three/examples/js/effects/StereoEffect';
import mobileRotateIcon from './mobile-rotate.svg';
import { StereoButton } from './StereoButton';

/**
 * @typedef {Object} external:THREE.StereoEffect
 * @summary {@link https://github.com/mrdoob/three.js/blob/dev/examples/js/effects/StereoEffect.js}
 */

/**
 * @external NoSleep
 * @description {@link https://github.com/richtr/NoSleep.js}
 */

// add stereo button
DEFAULTS.navbar.splice(-1, 0, StereoButton.id);
DEFAULTS.lang[StereoButton.id] = 'Stereo view';
registerButton(StereoButton);

// other lang strings
DEFAULTS.lang.stereoNotification = 'Click anywhere to exit stereo view.';
DEFAULTS.lang.pleaseRotate = ['Please rotate your device', '(or tap to continue)'];

/**
 * @summary Adds stereo view on mobile devices
 * @extends PSV.plugins.AbstractPlugin
 * @memberof PSV.plugins
 */
export default class StereoPlugin extends AbstractPlugin {

  static id = 'stereo';

  /**
   * @summary Identifier of the overlay "please rotate your screen"
   * @type {string}
   * @constant
   */
  static ID_OVERLAY_PLEASE_ROTATE = 'pleaseRotate';

  /**
   * @summary Available events
   * @enum {string}
   * @memberof PSV.plugins.StereoPlugin
   * @constant
   */
  static EVENTS = {
    STEREO_UPDATED: 'stereo-updated',
  };

  /**
   * @param {PSV.Viewer} psv
   */
  constructor(psv) {
    super(psv);

    /**
     * @type {PSV.plugins.GyroscopePlugin}
     * @readonly
     * @private
     */
    this.gyroscope = psv.getPlugin(GyroscopePlugin);

    if (!this.gyroscope) {
      throw new PSVError('Stereo plugin requires the gyroscope plugin');
    }

    /**
     * @member {Object}
     * @protected
     * @property {Promise<boolean>} isSupported - indicates of the gyroscope API is available
     * @property {external:THREE.WebGLRenderer} renderer - original renderer
     * @property {external:NoSleep} noSleep
     */
    this.prop = {
      isSupported: this.gyroscope.prop.isSupported,
      renderer   : null,
      noSleep    : null,
    };

    /**
     * @type {PSV.plugins.MarkersPlugin}
     * @private
     */
    this.markers = this.psv.getPlugin('markers');

    this.psv.on(CONSTANTS.EVENTS.STOP_ALL, this);
    this.psv.on(CONSTANTS.EVENTS.CLICK, this);
  }

  /**
   * @package
   */
  destroy() {
    this.psv.off(CONSTANTS.EVENTS.STOP_ALL, this);
    this.psv.off(CONSTANTS.EVENTS.CLICK, this);

    this.stop();

    super.destroy();
  }

  /**
   * @private
   */
  handleEvent(e) {
    switch (e.type) {
      case CONSTANTS.EVENTS.STOP_ALL:
      case CONSTANTS.EVENTS.CLICK:
        this.stop();
        break;
      default:
        break;
    }
  }

  /**
   * @summary Checks if the stereo view is enabled
   * @returns {boolean}
   */
  isEnabled() {
    return !!this.prop.stereoEffect;
  }

  /**
   * @summary Enables the stereo view
   * @description
   *  - enables NoSleep.js
   *  - enables full screen
   *  - starts gyroscope controle
   *  - hides markers, navbar and panel
   *  - instanciate {@link external:THREE.StereoEffect}
   * @returns {Promise}
   * @fires PSV.plugins.StereoPlugin.stereo-updated
   * @throws {PSV.PSVError} if the gyroscope API is not available/granted
   */
  start() {
    // Need to be in the main event queue
    this.psv.enterFullscreen();
    this.__startNoSleep();
    this.__lockOrientation();

    return this.gyroscope.start().then(() => {
      // switch renderer
      this.prop.renderer = this.psv.renderer.renderer;
      this.psv.renderer.renderer = new THREE.StereoEffect(this.psv.renderer.renderer);

      this.psv.needsUpdate();

      if (this.markers) {
        this.markers.hide();
      }
      this.psv.navbar.hide();
      this.psv.panel.hide();

      /**
       * @event stereo-updated
       * @memberof PSV.plugins.StereoPlugin
       * @summary Triggered when the stereo view is enabled/disabled
       * @param {boolean} enabled
       */
      this.trigger(StereoPlugin.EVENTS.STEREO_UPATED, true);

      this.psv.notification.show({
        content: this.psv.config.lang.stereoNotification,
        timeout: 3000,
      });
    }, () => {
      this.__unlockOrientation();
      this.__stopNoSleep();
      this.psv.exitFullscreen();
    });
  }

  /**
   * @summary Disables the stereo view
   * @fires PSV.plugins.StereoPlugin.stereo-updated
   */
  stop() {
    if (this.isEnabled()) {
      this.psv.renderer.renderer = this.prop.renderer;
      this.prop.renderer = null;

      this.psv.needsUpdate();

      if (this.markers) {
        this.markers.show();
      }
      this.psv.navbar.show();

      this.__unlockOrientation();
      this.__stopNoSleep();
      this.psv.exitFullscreen();
      this.gyroscope.stop();

      this.trigger(StereoPlugin.EVENTS.STEREO_UPATED, false);
    }
  }

  /**
   * @summary Enables or disables the stereo view
   */
  toggle() {
    if (this.isEnabled()) {
      this.stop();
    }
    else {
      this.start();
    }
  }

  /**
   * @summary Enables NoSleep.js
   * TODO WakeLock API when available https://web.dev/wakelock
   * @private
   */
  __startNoSleep() {
    if (!('NoSleep' in window)) {
      utils.logWarn('NoSleep is not available');
      return;
    }

    if (!this.prop.noSleep) {
      this.prop.noSleep = new window.NoSleep();
    }

    this.prop.noSleep.enable();
  }

  /**
   * @summary Disables NoSleep.js
   * @private
   */
  __stopNoSleep() {
    if (this.prop.noSleep) {
      this.prop.noSleep.disable();
    }
  }

  /**
   * @summary Tries to lock the device in landscape or display a message
   * @private
   */
  __lockOrientation() {
    let displayRotateMessageTimeout;

    const displayRotateMessage = () => {
      if (this.isEnabled() && window.innerHeight > window.innerWidth) {
        this.psv.overlay.show({
          id     : StereoPlugin.ID_OVERLAY_PLEASE_ROTATE,
          image  : mobileRotateIcon,
          text   : this.psv.config.lang.pleaseRotate[0],
          subtext: this.psv.config.lang.pleaseRotate[1],
        });
      }

      if (displayRotateMessageTimeout) {
        clearTimeout(displayRotateMessageTimeout);
        displayRotateMessageTimeout = null;
      }
    };

    if (window.screen?.orientation) {
      window.screen.orientation.lock('landscape').then(null, () => displayRotateMessage());
      displayRotateMessageTimeout = setTimeout(() => displayRotateMessage(), 500);
    }
    else {
      displayRotateMessage();
    }
  }

  /**
   * @summary Unlock the device orientation
   * @private
   */
  __unlockOrientation() {
    if (window.screen?.orientation) {
      window.screen.orientation.unlock();
    }
    else {
      this.psv.overlay.hide(StereoPlugin.ID_OVERLAY_PLEASE_ROTATE);
    }
  }

}
<commit_msg>Fix stereo enabled state<commit_after>import { AbstractPlugin, CONSTANTS, DEFAULTS, PSVError, registerButton, utils } from 'photo-sphere-viewer';
import GyroscopePlugin from 'photo-sphere-viewer/plugins/gyroscope';
import * as THREE from 'three';
import 'three/examples/js/effects/StereoEffect';
import mobileRotateIcon from './mobile-rotate.svg';
import { StereoButton } from './StereoButton';

/**
 * @typedef {Object} external:THREE.StereoEffect
 * @summary {@link https://github.com/mrdoob/three.js/blob/dev/examples/js/effects/StereoEffect.js}
 */

/**
 * @external NoSleep
 * @description {@link https://github.com/richtr/NoSleep.js}
 */

// add stereo button
DEFAULTS.navbar.splice(-1, 0, StereoButton.id);
DEFAULTS.lang[StereoButton.id] = 'Stereo view';
registerButton(StereoButton);

// other lang strings
DEFAULTS.lang.stereoNotification = 'Click anywhere to exit stereo view.';
DEFAULTS.lang.pleaseRotate = ['Please rotate your device', '(or tap to continue)'];

/**
 * @summary Adds stereo view on mobile devices
 * @extends PSV.plugins.AbstractPlugin
 * @memberof PSV.plugins
 */
export default class StereoPlugin extends AbstractPlugin {

  static id = 'stereo';

  /**
   * @summary Identifier of the overlay "please rotate your screen"
   * @type {string}
   * @constant
   */
  static ID_OVERLAY_PLEASE_ROTATE = 'pleaseRotate';

  /**
   * @summary Available events
   * @enum {string}
   * @memberof PSV.plugins.StereoPlugin
   * @constant
   */
  static EVENTS = {
    STEREO_UPDATED: 'stereo-updated',
  };

  /**
   * @param {PSV.Viewer} psv
   */
  constructor(psv) {
    super(psv);

    /**
     * @type {PSV.plugins.GyroscopePlugin}
     * @readonly
     * @private
     */
    this.gyroscope = GyroscopePlugin ? psv.getPlugin(GyroscopePlugin) : null;

    if (!this.gyroscope) {
      throw new PSVError('Stereo plugin requires the gyroscope plugin');
    }

    /**
     * @member {Object}
     * @protected
     * @property {Promise<boolean>} isSupported - indicates of the gyroscope API is available
     * @property {external:THREE.WebGLRenderer} renderer - original renderer
     * @property {external:NoSleep} noSleep
     */
    this.prop = {
      isSupported: this.gyroscope.prop.isSupported,
      renderer   : null,
      noSleep    : null,
    };

    /**
     * @type {PSV.plugins.MarkersPlugin}
     * @private
     */
    this.markers = this.psv.getPlugin('markers');

    this.psv.on(CONSTANTS.EVENTS.STOP_ALL, this);
    this.psv.on(CONSTANTS.EVENTS.CLICK, this);
  }

  /**
   * @package
   */
  destroy() {
    this.psv.off(CONSTANTS.EVENTS.STOP_ALL, this);
    this.psv.off(CONSTANTS.EVENTS.CLICK, this);

    this.stop();

    super.destroy();
  }

  /**
   * @private
   */
  handleEvent(e) {
    switch (e.type) {
      case CONSTANTS.EVENTS.STOP_ALL:
      case CONSTANTS.EVENTS.CLICK:
        this.stop();
        break;
      default:
        break;
    }
  }

  /**
   * @summary Checks if the stereo view is enabled
   * @returns {boolean}
   */
  isEnabled() {
    return !!this.prop.renderer;
  }

  /**
   * @summary Enables the stereo view
   * @description
   *  - enables NoSleep.js
   *  - enables full screen
   *  - starts gyroscope controle
   *  - hides markers, navbar and panel
   *  - instanciate {@link external:THREE.StereoEffect}
   * @returns {Promise}
   * @fires PSV.plugins.StereoPlugin.stereo-updated
   * @throws {PSV.PSVError} if the gyroscope API is not available/granted
   */
  start() {
    // Need to be in the main event queue
    this.psv.enterFullscreen();
    this.__startNoSleep();
    this.__lockOrientation();

    return this.gyroscope.start().then(() => {
      // switch renderer
      this.prop.renderer = this.psv.renderer.renderer;
      this.psv.renderer.renderer = new THREE.StereoEffect(this.psv.renderer.renderer);

      this.psv.needsUpdate();

      if (this.markers) {
        this.markers.hide();
      }
      this.psv.navbar.hide();
      this.psv.panel.hide();

      /**
       * @event stereo-updated
       * @memberof PSV.plugins.StereoPlugin
       * @summary Triggered when the stereo view is enabled/disabled
       * @param {boolean} enabled
       */
      this.trigger(StereoPlugin.EVENTS.STEREO_UPATED, true);

      this.psv.notification.show({
        content: this.psv.config.lang.stereoNotification,
        timeout: 3000,
      });
    }, () => {
      this.__unlockOrientation();
      this.__stopNoSleep();
      this.psv.exitFullscreen();
    });
  }

  /**
   * @summary Disables the stereo view
   * @fires PSV.plugins.StereoPlugin.stereo-updated
   */
  stop() {
    if (this.isEnabled()) {
      this.psv.renderer.renderer = this.prop.renderer;
      this.prop.renderer = null;

      this.psv.needsUpdate();

      if (this.markers) {
        this.markers.show();
      }
      this.psv.navbar.show();

      this.__unlockOrientation();
      this.__stopNoSleep();
      this.psv.exitFullscreen();
      this.gyroscope.stop();

      this.trigger(StereoPlugin.EVENTS.STEREO_UPATED, false);
    }
  }

  /**
   * @summary Enables or disables the stereo view
   */
  toggle() {
    if (this.isEnabled()) {
      this.stop();
    }
    else {
      this.start();
    }
  }

  /**
   * @summary Enables NoSleep.js
   * TODO WakeLock API when available https://web.dev/wakelock
   * @private
   */
  __startNoSleep() {
    if (!('NoSleep' in window)) {
      utils.logWarn('NoSleep is not available');
      return;
    }

    if (!this.prop.noSleep) {
      this.prop.noSleep = new window.NoSleep();
    }

    this.prop.noSleep.enable();
  }

  /**
   * @summary Disables NoSleep.js
   * @private
   */
  __stopNoSleep() {
    if (this.prop.noSleep) {
      this.prop.noSleep.disable();
    }
  }

  /**
   * @summary Tries to lock the device in landscape or display a message
   * @private
   */
  __lockOrientation() {
    let displayRotateMessageTimeout;

    const displayRotateMessage = () => {
      if (this.isEnabled() && window.innerHeight > window.innerWidth) {
        this.psv.overlay.show({
          id     : StereoPlugin.ID_OVERLAY_PLEASE_ROTATE,
          image  : mobileRotateIcon,
          text   : this.psv.config.lang.pleaseRotate[0],
          subtext: this.psv.config.lang.pleaseRotate[1],
        });
      }

      if (displayRotateMessageTimeout) {
        clearTimeout(displayRotateMessageTimeout);
        displayRotateMessageTimeout = null;
      }
    };

    if (window.screen?.orientation) {
      window.screen.orientation.lock('landscape').then(null, () => displayRotateMessage());
      displayRotateMessageTimeout = setTimeout(() => displayRotateMessage(), 500);
    }
    else {
      displayRotateMessage();
    }
  }

  /**
   * @summary Unlock the device orientation
   * @private
   */
  __unlockOrientation() {
    if (window.screen?.orientation) {
      window.screen.orientation.unlock();
    }
    else {
      this.psv.overlay.hide(StereoPlugin.ID_OVERLAY_PLEASE_ROTATE);
    }
  }

}
<|endoftext|>


<commit_before>let gulp = require('gulp');
let merge = require('merge2');
let sass = require('node-sass');
let clean = require('gulp-clean');
let ts = require('gulp-typescript');
let runSequence = require('run-sequence');
let sourcemaps = require('gulp-sourcemaps');
let inlineNg2Template = require('gulp-inline-ng2-template');
let gulpFile = require('gulp-file');
let doc = require('./misc/api-doc');
let glob = require('glob');

const INLINE_OPTIONS = {
	useRelativePaths: true,
	styleProcessor: compileScss,
	removeLineBreaks: true,
	target: 'es5'
}

const TSCONFIG_PATH = './src/tsconfig.json';
const OUT_DIR = './dist';

gulp.task('build', callback => runSequence(
	'dist:clean',
	'build:inline-and-compile',
	callback
));

gulp.task('dist:clean', () => {
	return gulp.src(OUT_DIR, { read: false })
		.pipe(clean());
});

gulp.task('build:inline-and-compile', () => {
	let tsProject = ts.createProject(TSCONFIG_PATH);

	const tsResult = tsProject.src()
		.pipe(inlineNg2Template(INLINE_OPTIONS))
		.pipe(sourcemaps.init())
		.pipe(tsProject());

	return merge([
		tsResult.dts
			.pipe(gulp.dest(OUT_DIR)),
		tsResult.js
			.pipe(sourcemaps.write('./'))
			.pipe(gulp.dest(OUT_DIR)),
	]);
});

function compileScss(stylePath, ext, styleFile, callback) {
	if (ext[0] === '.scss') {
		let sassObj = sass.renderSync({
			file: stylePath,
			includePaths: [
				'node_modules/@lucca-front/scss/src/overrides',
			],
		});

		if (sassObj && sassObj['css']){
			styleFile = sassObj.css.toString('utf8');
		}
	}
	return callback(null, styleFile);
}

// DOC

// Generate doc from the code
// copy-pasted from ng-bootstrap
// https://github.com/ng-bootstrap/ng-bootstrap/blob/master/gulpfile.js#L235
function getFileNames() {
	return glob.sync('src/**/*.ts', {
		ignore: ['src/**/*.spec.ts', 'src/util/**']
	});
}

function getApiDocs() {
	return doc(getFileNames());
}

gulp.task('generatedoc', () => {
	var docs = `const API_DOCS = ${JSON.stringify(getApiDocs(), null, 2)};\n\nexport default API_DOCS;`;

	return gulpFile('api-docs.ts', docs, {src: true}).pipe(gulp.dest("demo"));
})<commit_msg>[FIX] Fix Gulp build<commit_after>let gulp = require('gulp');
let merge = require('merge2');
let sass = require('node-sass');
let clean = require('gulp-clean');
let ts = require('gulp-typescript');
let runSequence = require('run-sequence');
let sourcemaps = require('gulp-sourcemaps');
let inlineNg2Template = require('gulp-inline-ng2-template');
let gulpFile = require('gulp-file');
let doc = require('./misc/api-doc');
let glob = require('glob');

const INLINE_OPTIONS = {
	useRelativePaths: true,
	styleProcessor: compileScss,
	removeLineBreaks: true,
	target: 'es5'
}

const TSCONFIG_PATH = './src/tsconfig.json';
const OUT_DIR = './dist';

gulp.task('build', callback => runSequence(
	'dist:clean',
	'build:inline-and-compile',
	callback
));

gulp.task('dist:clean', () => {
	return gulp.src(OUT_DIR, { read: false })
		.pipe(clean());
});

gulp.task('build:inline-and-compile', () => {
	let tsProject = ts.createProject(TSCONFIG_PATH);

	const tsResult = tsProject.src()
		.pipe(inlineNg2Template(INLINE_OPTIONS))
		.pipe(sourcemaps.init())
		.pipe(tsProject());

	return merge([
		tsResult.dts
			.pipe(gulp.dest(OUT_DIR)),
		tsResult.js
			.pipe(sourcemaps.write('./'))
			.pipe(gulp.dest(OUT_DIR)),
	]);
});

function compileScss(stylePath, ext, styleFile, callback) {
	if (ext[0] === '.scss') {
		let sassObj = sass.renderSync({
			file: stylePath,
			includePaths: [
				'src/style/overrides',
				'node_modules/@lucca-front/scss/src/overrides',
			],
		});

		if (sassObj && sassObj['css']){
			styleFile = sassObj.css.toString('utf8');
		}
	}
	return callback(null, styleFile);
}

// DOC

// Generate doc from the code
// copy-pasted from ng-bootstrap
// https://github.com/ng-bootstrap/ng-bootstrap/blob/master/gulpfile.js#L235
function getFileNames() {
	return glob.sync('src/**/*.ts', {
		ignore: ['src/**/*.spec.ts', 'src/util/**']
	});
}

function getApiDocs() {
	return doc(getFileNames());
}

gulp.task('generatedoc', () => {
	var docs = `const API_DOCS = ${JSON.stringify(getApiDocs(), null, 2)};\n\nexport default API_DOCS;`;

	return gulpFile('api-docs.ts', docs, {src: true}).pipe(gulp.dest("demo"));
})<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var Redux = require('redux');
var ReactRedux = require('react-redux');
var ReduxThunkMiddleware = require('redux-thunk').default;

var Context = require('hops-react').Context;

var INITIAL_STATE = 'INITIAL_STATE';

exports.Context = exports.createContext = Context.extend({
  initialize: function (options) {
    Context.prototype.initialize.call(this, options);
    this.reducers = options.reducers || (options.reducers = {});
    Object.keys(this.reducers).forEach(function (key) {
      this.registerReducer(key, this.reducers[key]);
    }.bind(this));
  },
  registerReducer: function (namespace, reducer) {
    this.reducers[namespace] = reducer;
    if (this.store) {
      this.store.replaceReducer(Redux.combineReducers(this.reducers));
    }
  },
  getStore: function () {
    if (module.hot) {
      this.store = global.store || (global.store = this.createStore());
    }
    return this.store || (this.store = this.createStore());
  },
  createStore: function () {
    return Redux.createStore(
      Redux.combineReducers(this.reducers),
      global[INITIAL_STATE],
      (global.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || Redux.compose)(
        Redux.applyMiddleware(ReduxThunkMiddleware)
      )
    );
  },
  enhanceElement: function (reactElement) {
    return Context.prototype.enhanceElement.call(this, React.createElement(
      ReactRedux.Provider,
      { store: this.getStore() },
      reactElement
    ));
  },
  getTemplateData: function () {
    var templateData = Context.prototype.getTemplateData.call(this);
    return Object.assign(templateData, {
      globals: templateData.globals.concat([{
        name: INITIAL_STATE,
        value: this.getStore().getState()
      }])
    });
  }
});
<commit_msg>feat(redux): add support for hops-graphql<commit_after>'use strict';

var React = require('react');
var Redux = require('redux');
var ReactRedux = require('react-redux');
var ReduxThunkMiddleware = require('redux-thunk').default;

var Context = require('hops-react').Context;

var INITIAL_STATE = 'INITIAL_STATE';

exports.Context = exports.createContext = Context.extend({
  initialize: function (options) {
    Context.prototype.initialize.call(this, options);
    this.reducers = options.reducers || (options.reducers = {});
    Object.keys(this.reducers).forEach(function (key) {
      this.registerReducer(key, this.reducers[key]);
    }.bind(this));
  },
  registerReducer: function (namespace, reducer) {
    this.reducers[namespace] = reducer;
    if (this.store) {
      this.store.replaceReducer(Redux.combineReducers(this.reducers));
    }
  },
  getStore: function () {
    if (module.hot) {
      this.store = global.store || (global.store = this.createStore());
    }
    return this.store || (this.store = this.createStore());
  },
  createStore: function () {
    return Redux.createStore(
      Redux.combineReducers(this.reducers),
      global[INITIAL_STATE],
      (global.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || Redux.compose)(
        Redux.applyMiddleware(ReduxThunkMiddleware)
      )
    );
  },
  createProvider: function (reactElement) {
    return React.createElement(
      ReactRedux.Provider,
      { store: this.getStore() },
      reactElement
    );
  },
  enhanceElement: function (reactElement) {
    return Context.prototype.enhanceElement.call(
      this,
      this.createProvider(reactElement)
    );
  },
  getTemplateData: function () {
    var templateData = Context.prototype.getTemplateData.call(this);
    return Object.assign(templateData, {
      globals: templateData.globals.concat([{
        name: INITIAL_STATE,
        value: this.getStore().getState()
      }])
    });
  }
});
<|endoftext|>


<commit_before>var gTabDeque = {

    deque: undefined,
    selectionChanged: false,
    mimickingAllTabMinimized: false,

    onLoad: function() {
        if ('undefined' == typeof gBrowser) {
            return;
        }
        window.removeEventListener('load', gTabDeque.onLoad, false);
        window.addEventListener('unload', gTabDeque.onUnload, false);
        window.addEventListener("keyup", gTabDeque.onKeyUp, false);
        // need to listen on window for mousegestures
        window.addEventListener("mouseup", gTabDeque.onMouseUp, false);
        gBrowser.tabContainer.addEventListener("TabOpen", gTabDeque.onTabOpen, false);
        gBrowser.tabContainer.addEventListener("TabSelect", gTabDeque.onTabSelect, false);
        gBrowser.tabContainer.addEventListener("TabClose", gTabDeque.onTabClose, false);
    },

    onUnload: function() {
        window.removeEventListener('unload', gTabDeque.onUnload, false);
        window.removeEventListener("keyup", gTabDeque.onKeyUp, false);
        window.removeEventListener("mouseup", gTabDeque.onMouseUp, false);
        gBrowser.tabContainer.removeEventListener("TabOpen", gTabDeque.onTabOpen, false);
        gBrowser.tabContainer.removeEventListener("TabSelect", gTabDeque.onTabSelect, false);
        gBrowser.tabContainer.removeEventListener("TabClose", gTabDeque.onTabClose, false);
    },

    onTabOpen: function(anEvent) {
        // can't check whether tab is being opened in background - start at the
        // beginning and move to end of deque in onTabSelect if necessary
        var tab = anEvent.target;
        gTabDeque.moveTabToDequeBeginning(tab);
        if (!gTabDeque.mimickingAllTabMinimized) {
            gBrowser.moveTabTo(tab, gBrowser.mCurrentTab.nextSibling._tPos);
        }
    },

    onTabSelect: function(anEvent) {
        gTabDeque.moveTabToDequeEnd(anEvent.target);
        gTabDeque.selectionChanged = true;
    },

    onTabClose: function(anEvent) {
        var closingTab = anEvent.target;
        gTabDeque.ensureInitialization();
        gTabDeque.removeTabFromDeque(closingTab);
        if (gTabDeque.deque.length == 0) {
            gTabDeque.mimicAllTabsMinimized();
        } else {
            if (closingTab.selected) {
                var currentIndex = gTabDeque.getTabIndex(closingTab);
                var nextIndex = gTabDeque.getTabIndex(gTabDeque.getNextTab());
                // the closing tab is still there when calculating the index,
                // but not when selecting
                var adjustment = currentIndex < nextIndex ? -1 : 0;
                gBrowser.selectTabAtIndex(nextIndex + adjustment);
            }
        }
    },

    // can't differentiate between click on selected or unselected tab
    // so selectionChanged has to be checked to see whether selection changed
    // the relevant event order is (TabSelect ->) *Down -> *Up -> Click
    onMouseUp: function(anEvent) {
        gTabDeque.ensureInitialization();
        if (anEvent.button == 0 &&
            anEvent.target.nodeName == "tab" &&
            anEvent.target.selected &&
            !gTabDeque.selectionChanged) {
            gTabDeque.minimizeTab(anEvent.target);
        }
        // need this for selecting/closing with mouse: click/mousegesture
        gTabDeque.selectionChanged = false;
    },
    onKeyUp: function(anEvent) {
        // need this for selecting/closing with keyboard
        gTabDeque.selectionChanged = false;
    },

    minimizeTab: function(tab) {
        gTabDeque.removeTabFromDeque(tab);
        var tabToSelect = undefined;
        if (gTabDeque.deque.length == 0) {
            gTabDeque.mimicAllTabsMinimized();
        } else {
            gBrowser.selectTabAtIndex(gTabDeque.getTabIndex(gTabDeque.getNextTab()));
        }
    },

    mimicAllTabsMinimized: function() {
        var preferences = Components
            .classes['@mozilla.org/preferences-service;1']
            .getService(Components.interfaces.nsIPrefBranch);
        var url = preferences.getCharPref("browser.newtab.url");
        gTabDeque.mimickingAllTabMinimized = true;
        var tab = gBrowser.loadOneTab(url, null, null, null, false, false);
        gTabDeque.mimickingAllTabMinimized = false;
    },
    moveTabToDequeBeginning: function(tab) {
        gTabDeque.ensureInitialization();
        // getting duplicates sometimes...
        gTabDeque.removeTabFromDeque(tab);
        gTabDeque.deque.unshift(tab);
    },

    moveTabToDequeEnd: function(tab) {
        gTabDeque.ensureInitialization();
        // getting duplicates sometimes...
        gTabDeque.removeTabFromDeque(tab);
        gTabDeque.deque.push(tab);
    },

    // can't be sure that events are fired for all tabs on startup
    // tabs are missing if initialized too early, use this before first access
    ensureInitialization: function() {
        if (!gTabDeque.deque) {
            gTabDeque.initDeque();
            gTabDeque.selectionChanged = false;
        }
    },

    initDeque: function() {
        gTabDeque.deque = new Array();
        for (var tabIndex = 0; tabIndex < gBrowser.tabs.length; tabIndex++) {
            gTabDeque.deque.push(gBrowser.tabs[tabIndex]);
        }
        return gTabDeque.deque;
    },

    removeTabFromDeque: function(tab) {
        var dequeIndex = gTabDeque.deque.indexOf(tab)
        if (gTabDeque.deque.indexOf(tab) >= 0) {
            gTabDeque.deque.splice(gTabDeque.deque.indexOf(tab), 1);
        }
    },

    getTabIndex: function(givenTab) {
        for (var tabIndex = 0; tabIndex < gBrowser.tabs.length; tabIndex++) {
            if (gBrowser.tabs[tabIndex] === givenTab) {
                return tabIndex;
            }
        }
        return -1;
    },

    getNextTab: function() {
        return gTabDeque.deque[gTabDeque.deque.length - 1];
    },

    // for debugging
    getDequeURLs: function() {
        var urls = new Array();
        var length = gTabDeque.deque.length
        for (var tabIndex = 0; tabIndex < gTabDeque.deque.length; tabIndex++) {
            urls.push(gTabDeque.getTabURL(gTabDeque.deque[tabIndex]));
        }
        return urls;
    },

    getTabURL: function(tab) {
        var browser = gBrowser.getBrowserForTab(tab);
        return browser.currentURI.spec;
    }
};

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

<commit_msg>Make new tab for when all tabs are minimized invisible for user<commit_after>var gTabDeque = {

    deque: undefined,
    selectionChanged: false,
    mimickingAllTabMinimized: false,
    allTabsMinimizedMimic: undefined,

    onLoad: function() {
        if ('undefined' == typeof gBrowser) {
            return;
        }
        window.removeEventListener('load', gTabDeque.onLoad, false);
        window.addEventListener('close', gTabDeque.onClose, false);
        window.addEventListener('unload', gTabDeque.onUnload, false);
        window.addEventListener("keyup", gTabDeque.onKeyUp, false);
        // need to listen on window for mousegestures
        window.addEventListener("mouseup", gTabDeque.onMouseUp, false);
        gBrowser.tabContainer.addEventListener("TabOpen", gTabDeque.onTabOpen, false);
        gBrowser.tabContainer.addEventListener("TabSelect", gTabDeque.onTabSelect, false);
        gBrowser.tabContainer.addEventListener("TabClose", gTabDeque.onTabClose, false);
    },

    onClose: function() {
        if (gTabDeque.allTabsMinimizedMimic) {
            // we don't want this to be restored...
            gBrowser.removeTab(gTabDeque.allTabsMinimizedMimic);
        }
    },

    onUnload: function() {
        window.removeEventListener('unload', gTabDeque.onUnload, false);
        window.removeEventListener('close', gTabDeque.onClose, false);
        window.removeEventListener("keyup", gTabDeque.onKeyUp, false);
        window.removeEventListener("mouseup", gTabDeque.onMouseUp, false);
        gBrowser.tabContainer.removeEventListener("TabOpen", gTabDeque.onTabOpen, false);
        gBrowser.tabContainer.removeEventListener("TabSelect", gTabDeque.onTabSelect, false);
        gBrowser.tabContainer.removeEventListener("TabClose", gTabDeque.onTabClose, false);
    },

    onTabOpen: function(anEvent) {
        if (!gTabDeque.mimickingAllTabMinimized) {
            var tab = anEvent.target;
            // can't check whether tab is being opened in background - start at the
            // beginning and move to end of deque in onTabSelect if necessary
            gTabDeque.moveTabToDequeBeginning(tab);
            gBrowser.moveTabTo(tab, gBrowser.mCurrentTab.nextSibling._tPos);
        }
    },

    onTabSelect: function(anEvent) {
        gTabDeque.selectionChanged = true;
        if (!gTabDeque.mimickingAllTabMinimized) {
            gTabDeque.moveTabToDequeEnd(anEvent.target);
        }
        if (anEvent.target === gTabDeque.allTabsMinimizedMimic) {
            document.getElementById('nav-bar').collapsed = true;
        } else {
            document.getElementById('nav-bar').collapsed = false;
        }
    },

    onTabClose: function(anEvent) {
        var closingTab = anEvent.target;
        gTabDeque.ensureInitialization();
        gTabDeque.removeTabFromDeque(closingTab);
        if (gTabDeque.deque.length == 0) {
            gTabDeque.mimicAllTabsMinimized();
        } else {
            if (closingTab.selected) {
                var currentIndex = gTabDeque.getTabIndex(closingTab);
                var nextIndex = gTabDeque.getTabIndex(gTabDeque.getNextTab());
                // the closing tab is still there when calculating the index,
                // but not when selecting
                var adjustment = currentIndex < nextIndex ? -1 : 0;
                gBrowser.selectTabAtIndex(nextIndex + adjustment);
            }
        }
    },

    // can't differentiate between click on selected or unselected tab
    // so selectionChanged has to be checked to see whether selection changed
    // the relevant event order is (TabSelect ->) *Down -> *Up -> Click
    onMouseUp: function(anEvent) {
        gTabDeque.ensureInitialization();
        if (anEvent.button == 0 &&
            anEvent.target.nodeName == "tab" &&
            anEvent.target.selected &&
            !gTabDeque.selectionChanged) {
            gTabDeque.minimizeTab(anEvent.target);
        }
        // need this for selecting/closing with mouse: click/mousegesture
        gTabDeque.selectionChanged = false;
    },
    onKeyUp: function(anEvent) {
        // need this for selecting/closing with keyboard
        gTabDeque.selectionChanged = false;
    },

    minimizeTab: function(tab) {
        gTabDeque.removeTabFromDeque(tab);
        if (gTabDeque.deque.length == 0) {
            gTabDeque.mimicAllTabsMinimized();
        } else {
            gBrowser.selectTabAtIndex(gTabDeque.getTabIndex(gTabDeque.getNextTab()));
        }
    },

    mimicAllTabsMinimized: function() {
        if (!gTabDeque.allTabsMinimizedMimic) {
            gTabDeque.mimickingAllTabMinimized = true;
            var preferences = Components
                .classes['@mozilla.org/preferences-service;1']
                .getService(Components.interfaces.nsIPrefBranch);
            var url = preferences.getCharPref("browser.newtab.url");
            gTabDeque.allTabsMinimizedMimic = gBrowser.loadOneTab(url, null, null, null, false, false);
            gTabDeque.allTabsMinimizedMimic.collapsed = true;
            gTabDeque.allTabsMinimizedMimic.disabled = true;
            // TabSelect is triggered before gTabDeque.allTabsMinimizedMimic is set
            document.getElementById('nav-bar').collapsed = true;
            gTabDeque.mimickingAllTabMinimized = false;
        } else {
            gBrowser.selectTabAtIndex(gTabDeque.getTabIndex(gTabDeque.allTabsMinimizedMimic));
        }
    },

    moveTabToDequeBeginning: function(tab) {
        gTabDeque.ensureInitialization();
        // getting duplicates sometimes...
        gTabDeque.removeTabFromDeque(tab);
        gTabDeque.deque.unshift(tab);
    },

    moveTabToDequeEnd: function(tab) {
        gTabDeque.ensureInitialization();
        // getting duplicates sometimes...
        gTabDeque.removeTabFromDeque(tab);
        gTabDeque.deque.push(tab);
    },

    // can't be sure that events are fired for all tabs on startup
    // tabs are missing if initialized too early, use this before first access
    ensureInitialization: function() {
        if (!gTabDeque.deque) {
            gTabDeque.initDeque();
            gTabDeque.selectionChanged = false;
        }
    },

    initDeque: function() {
        gTabDeque.deque = new Array();
        for (var tabIndex = 0; tabIndex < gBrowser.tabs.length; tabIndex++) {
            gTabDeque.deque.push(gBrowser.tabs[tabIndex]);
        }
        return gTabDeque.deque;
    },

    removeTabFromDeque: function(tab) {
        var dequeIndex = gTabDeque.deque.indexOf(tab)
        if (gTabDeque.deque.indexOf(tab) >= 0) {
            gTabDeque.deque.splice(gTabDeque.deque.indexOf(tab), 1);
        }
    },

    getTabIndex: function(givenTab) {
        for (var tabIndex = 0; tabIndex < gBrowser.tabs.length; tabIndex++) {
            if (gBrowser.tabs[tabIndex] === givenTab) {
                return tabIndex;
            }
        }
        return -1;
    },

    getNextTab: function() {
        return gTabDeque.deque[gTabDeque.deque.length - 1];
    },

    // for debugging
    getDequeURLs: function() {
        var urls = new Array();
        var length = gTabDeque.deque.length
        for (var tabIndex = 0; tabIndex < gTabDeque.deque.length; tabIndex++) {
            urls.push(gTabDeque.getTabURL(gTabDeque.deque[tabIndex]));
        }
        return urls;
    },

    getTabURL: function(tab) {
        var browser = gBrowser.getBrowserForTab(tab);
        return browser.currentURI.spec;
    }
};

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

<|endoftext|>


<commit_before>

// All right, this is a little crazy, but let's try it for the demo.
//
// `Template.foo({ ... props ... })` sets properties on an underlying
// Component object.  `Template.foo()` (with `arguments.length === 0`)
// returns this underlying object.
//
// We can't easily have the `Template.foo({...})` syntax and have
// `Template.foo` actually *be* a Component, because making Components
// sometimes have typeof function would complicate things a lot.
// However, we can make `Template.foo` just as good in situations where
// a function will do (templates, `buf.write`) and when that doesn't
// work you can write `Template.foo()` instead.
//
// The potential downside is that this is just too confusing.

var chainers = { init: 1, rendered: 1, destroyed: 1 };

var makeGetter = function (obj, propName, initialValue) {
  var getter = function (newValue) {
    if (this !== obj) {
      // if we're being called on a subclass, copy ourselves!
      // XXX lazy copying is probably not the right way to do this.
      this[propName] = makeGetter(this, propName, initialValue);
      return arguments.length ? this[propName](newValue) :
        this[propName]();
    }
    if (arguments.length) {
      // setter doubles as a getter.  that way we have access to `this`
      // both ways.
      getter.$value = newValue;
      getter.$dep.changed();
    } else {
      getter.$dep.depend();
      return getter.$value;
    }
  };
  getter.$value = initialValue;
  getter.$dep = new Deps.Dependency;

  return getter;
};

UI.makeTemplate = function (underlying) {
  return function (options) {
    if (! arguments.length)
      return underlying;

    for (var k in options) {
      if (options.hasOwnProperty(k)) {
        var oldProp = underlying[k];
        var givenProp = options[k];

        if (k === 'fields') {
          // XXX basic fields impl
          // XXX could support functions as initial field values
          _.each(givenProp, function (fieldValue, fieldName) {
            underlying[fieldName] = makeGetter(underlying, fieldName,
                                               fieldValue);
          });

        } else if (k.indexOf(' ') >= 0) {
          // event handler
          // XXX clean up
          var eventType = k.slice(0, k.indexOf(' '));
          var selector = k.slice(k.indexOf(' ') + 1);

          underlying._events = (underlying._events || []);
          underlying._events.push({
            type: eventType,
            selector: selector,
            handler: (function (handler) {
              return function (evt) {
                // XXX
                var comp = UI.body.findByElement(evt.target);
                evt.component = comp;
                var data = comp.get();
                handler.call(data, evt);
              };
            })(givenProp)
          });

        } else if (chainers.hasOwnProperty(k)) {
          // init, rendered, destroyed
          if (typeof oldProp === 'function') {
            underlying[k] = (function (oldCb) {
              return function () {
                oldCb.call(this);
                givenProp.call(this);
              };
            })(oldProp);
          } else {
            underlying[k] = givenProp;
          }
        } else if (typeof givenProp === 'function') {
          // helper
          if (k === 'data')
            throw new Error("'data' is reserved and can't be used as a helper name");
          underlying[k] = (function (helper) {
            return function (/**/) {
              // XXX total hack!!  this line:
              UI.Component.current = this;

              var data = this.get();
              return helper.apply(data, arguments);
            };
          })(givenProp);
        } else {
          underlying[k] = givenProp;
        }
      }
    }

    // no use case for this return value, but maybe making it
    // same as no-arg form is less weird.
    return underlying;
  };
};<commit_msg>Component.current in event handlers<commit_after>

// All right, this is a little crazy, but let's try it for the demo.
//
// `Template.foo({ ... props ... })` sets properties on an underlying
// Component object.  `Template.foo()` (with `arguments.length === 0`)
// returns this underlying object.
//
// We can't easily have the `Template.foo({...})` syntax and have
// `Template.foo` actually *be* a Component, because making Components
// sometimes have typeof function would complicate things a lot.
// However, we can make `Template.foo` just as good in situations where
// a function will do (templates, `buf.write`) and when that doesn't
// work you can write `Template.foo()` instead.
//
// The potential downside is that this is just too confusing.

var chainers = { init: 1, rendered: 1, destroyed: 1 };

var makeGetter = function (obj, propName, initialValue) {
  var getter = function (newValue) {
    if (this !== obj) {
      // if we're being called on a subclass, copy ourselves!
      // XXX lazy copying is probably not the right way to do this.
      this[propName] = makeGetter(this, propName, initialValue);
      return arguments.length ? this[propName](newValue) :
        this[propName]();
    }
    if (arguments.length) {
      // setter doubles as a getter.  that way we have access to `this`
      // both ways.
      getter.$value = newValue;
      getter.$dep.changed();
    } else {
      getter.$dep.depend();
      return getter.$value;
    }
  };
  getter.$value = initialValue;
  getter.$dep = new Deps.Dependency;

  return getter;
};

UI.makeTemplate = function (underlying) {
  return function (options) {
    if (! arguments.length)
      return underlying;

    for (var k in options) {
      if (options.hasOwnProperty(k)) {
        var oldProp = underlying[k];
        var givenProp = options[k];

        if (k === 'fields') {
          // XXX basic fields impl
          // XXX could support functions as initial field values
          _.each(givenProp, function (fieldValue, fieldName) {
            underlying[fieldName] = makeGetter(underlying, fieldName,
                                               fieldValue);
          });

        } else if (k.indexOf(' ') >= 0) {
          // event handler
          // XXX clean up
          var eventType = k.slice(0, k.indexOf(' '));
          var selector = k.slice(k.indexOf(' ') + 1);

          underlying._events = (underlying._events || []);
          underlying._events.push({
            type: eventType,
            selector: selector,
            handler: (function (handler) {
              return function (evt) {
                // XXX
                var comp = UI.body.findByElement(evt.target);
                evt.component = comp;
                UI.Component.current = comp;
                var data = comp.get();
                handler.call(data, evt);
              };
            })(givenProp)
          });

        } else if (chainers.hasOwnProperty(k)) {
          // init, rendered, destroyed
          if (typeof oldProp === 'function') {
            underlying[k] = (function (oldCb) {
              return function () {
                oldCb.call(this);
                givenProp.call(this);
              };
            })(oldProp);
          } else {
            underlying[k] = givenProp;
          }
        } else if (typeof givenProp === 'function') {
          // helper
          if (k === 'data')
            throw new Error("'data' is reserved and can't be used as a helper name");
          underlying[k] = (function (helper) {
            return function (/**/) {
              // XXX total hack!!  this line:
              UI.Component.current = this;

              var data = this.get();
              return helper.apply(data, arguments);
            };
          })(givenProp);
        } else {
          underlying[k] = givenProp;
        }
      }
    }

    // no use case for this return value, but maybe making it
    // same as no-arg form is less weird.
    return underlying;
  };
};<|endoftext|>


<commit_before>"use strict";
var Vomnibar = {
  box: null,
  port: null,
  status: 0,
  options: null,
  width: 0,
  destroy: null,
  sameOrigin: false,
  activate: function(count, options, forceCurrent) {
    if (!options.secret || !options.vomnibar) { return false; }
    if (document.readyState === "loading") {
      if (!this.width) {
        this.width = setTimeout(this.activate.bind(this, options), 500);
        return;
      }
      this.width = 0;
    }
    if (!(document.documentElement instanceof HTMLElement)) { return false; }
    Object.setPrototypeOf(options || (options = {}), null);
    if (options.url === true && !options.topUrl) {
      options.topUrl = window.location.href;
      options.count = +count || 1;
    }
    if ((forceCurrent |= 0) < 2 &&
        VHints.tryNestedFrame("Vomnibar.activate", [1, options, 2])) {
      return;
    }
    var secret = options.secret, url = options.vomnibar;
    delete options.secret; delete options.vomnibar;
    this.width = Math.max(window.innerWidth - 24, document.documentElement.clientWidth);
    this.options = options;
    if (this.Init) {
      setTimeout(this.Init, 0, secret, url);
      this.status = 1;
      this.Init = null;
    } else if (!this.status) {
      this.status = 2;
      this.show();
    } else if (this.status >= 3) {
      this.box.contentWindow.focus();
      return this.show();
    }
    VHandler.remove(this);
    VHandler.push(VDom.UI.SuppressMost, this);
  },
  show: function() {
    if (this.status < 2) { return; }
    var options = this.options, url, upper = 0;
    options.width = this.width, options.name = "activate";
    this.options = null;
    url = options.url;
    if (url === true) {
      if (url = VDom.getSelectionText()) {
        options.forceNewTab = true;
      } else {
        url = options.topUrl;
      }
      upper = 1 - options.count;
      delete options.topUrl; delete options.count;
      options.url = url;
    }
    if (!url || url.indexOf("://") === -1) {
      options.search = "";
      this.port.postMessage(options);
      return;
    }
    VPort.sendMessage({
      handler: "parseSearchUrl",
      upper: upper,
      trailing_slash: options.trailing_slash,
      url: url
    }, function(search) {
      options.search = search;
      if (search != null) { options.url = ""; }
      Vomnibar.port.postMessage(options);
    });
  },
  hide: function(isMsg) {
    if (!this.status) { return; }
    VHandler.remove(this);
    this.width = this.status = 0;
    this.options = null;
    if (!this.box) { return; }
    var style = this.box.style;
    style.display = "none", style.width = "", style.height = "";
    if (isMsg !== true) {
      this.port.postMessage("hide");
      setTimeout(function() { window.focus(); }, 17);
    }
  },
  Init: function(secret, page) {
    var _this = Vomnibar, el;
    el = _this.box = VDom.createElement("iframe");
    el.className = "LS Omnibar";
    el.style.visibility = "hidden";
    el.src = page;
    el.onload = function() {
      var channel, port, i = page.indexOf("://"), wnd = this.contentWindow;
      page = page.substring(0, page.indexOf("/", i + 3));
      if (location.origin !== page) {
        channel = new MessageChannel();
        _this.port = channel.port1;
        _this.port.onmessage = _this.onMessage.bind(_this);
        wnd.postMessage(secret, page, [channel.port2]);
        return;
      }
      port = {
        onmessage: null,
        postMessage: function(data) { Vomnibar.onMessage({ data: data }); }
      };
      _this.sameOrigin = true;
      _this.port = { postMessage: function(data) { port.onmessage({ data: data}); } };
      if (location.hash === "#chrome-ui") { this.style.top = "5px"; }
      wnd.Vomnibar.showFavIcon = true;
      wnd.onmessage({ source: window, data: secret, ports: [port] });
    };
    VDom.UI.addElement(el, false);
  },
  onMessage: function(event) {
    var data = event.data;
    switch (data.name || data) {
    case "uiComponentIsReady":
      this.box.onload = null;
      if (this.status !== 1) { return; }
      this.status = 2;
      this.show();
      break;
    case "style":
      if (this.status < 2) { return; }
      if (this.status === 2) {
        this.port.postMessage("afterOmni");
        this.onShown();
      }
      this.box.style.height = data.height + "px";
      break;
    case "focus": window.focus(); VEventMode.suppress(data.lastKey); break;
    case "hide": this.hide(true); break;
    case "scrollBy": VScroller.scrollBy(1, data.amount); break;
    case "scrollGoing": VScroller.keyIsDown = VScroller.Core.maxInterval; break;
    case "scrollEnd": VScroller.keyIsDown = 0; break;
    case "evalJS": VUtils.evalIfOK(data.url); break;
    case "broken": window.focus(); Vomnibar && this.destroy && this.destroy(); break;
    default: break;
    }
  },
  onShown: function() {
    this.status = 3;
    var style = this.box.style, width = this.width * 0.8;
    if (style.visibility) {
      style.visibility = "";
      style = VDom.UI.box.style;
    }
    this.sameOrigin ? (style.display = "")
      : setTimeout(function() { style.display = ""; }, 0);
    if (width !== (width | 0)) {
      this.box.style.width = (width | 0) / (width / 0.8) * 100 + "%";
    }
    VHandler.remove(this);
    VHandler.push(this.onKeydown, this);
  },
  onKeydown: function(event) {
    if (VKeyboard.isEscape(event)) { this.hide(); return 2; }
    var key = event.keyCode - VKeyCodes.f1;
    if (key === 0 || key === 1) {
      this.focus(key);
      return 2;
    }
    return 0;
  },
  focus: function(f2) {
    if (this.status < 3) { return; }
    this.box.contentWindow.focus();
    this.port.postMessage(f2 ? "focus" : "backspace");
  }
};
<commit_msg>iframe omnibar: wait 17ms before showing the box to avoid a blank list<commit_after>"use strict";
var Vomnibar = {
  box: null,
  port: null,
  status: 0,
  options: null,
  width: 0,
  destroy: null,
  sameOrigin: false,
  activate: function(count, options, forceCurrent) {
    if (!options.secret || !options.vomnibar) { return false; }
    if (document.readyState === "loading") {
      if (!this.width) {
        this.width = setTimeout(this.activate.bind(this, options), 500);
        return;
      }
      this.width = 0;
    }
    if (!(document.documentElement instanceof HTMLElement)) { return false; }
    Object.setPrototypeOf(options || (options = {}), null);
    if (options.url === true && !options.topUrl) {
      options.topUrl = window.location.href;
      options.count = +count || 1;
    }
    if ((forceCurrent |= 0) < 2 &&
        VHints.tryNestedFrame("Vomnibar.activate", [1, options, 2])) {
      return;
    }
    var secret = options.secret, url = options.vomnibar;
    delete options.secret; delete options.vomnibar;
    this.width = Math.max(window.innerWidth - 24, document.documentElement.clientWidth);
    this.options = options;
    if (this.Init) {
      setTimeout(this.Init, 0, secret, url);
      this.status = 1;
      this.Init = null;
    } else if (!this.status) {
      this.status = 2;
      this.show();
    } else if (this.status >= 3) {
      this.box.contentWindow.focus();
      return this.show();
    }
    VHandler.remove(this);
    VHandler.push(VDom.UI.SuppressMost, this);
  },
  show: function() {
    if (this.status < 2) { return; }
    var options = this.options, url, upper = 0;
    options.width = this.width, options.name = "activate";
    this.options = null;
    url = options.url;
    if (url === true) {
      if (url = VDom.getSelectionText()) {
        options.forceNewTab = true;
      } else {
        url = options.topUrl;
      }
      upper = 1 - options.count;
      delete options.topUrl; delete options.count;
      options.url = url;
    }
    if (!url || url.indexOf("://") === -1) {
      options.search = "";
      this.port.postMessage(options);
      return;
    }
    VPort.sendMessage({
      handler: "parseSearchUrl",
      upper: upper,
      trailing_slash: options.trailing_slash,
      url: url
    }, function(search) {
      options.search = search;
      if (search != null) { options.url = ""; }
      Vomnibar.port.postMessage(options);
    });
  },
  hide: function(isMsg) {
    if (!this.status) { return; }
    VHandler.remove(this);
    this.width = this.status = 0;
    this.options = null;
    if (!this.box) { return; }
    var style = this.box.style;
    style.display = "none", style.width = "", style.height = "";
    if (isMsg !== true) {
      this.port.postMessage("hide");
      setTimeout(function() { window.focus(); }, 17);
    }
  },
  Init: function(secret, page) {
    var _this = Vomnibar, el;
    el = _this.box = VDom.createElement("iframe");
    el.className = "LS Omnibar";
    el.style.visibility = "hidden";
    el.src = page;
    el.onload = function() {
      var channel, port, i = page.indexOf("://"), wnd = this.contentWindow;
      this.onload = null;
      page = page.substring(0, page.indexOf("/", i + 3));
      if (location.origin !== page) {
        channel = new MessageChannel();
        _this.port = channel.port1;
        _this.port.onmessage = _this.onMessage.bind(_this);
        wnd.postMessage(secret, page, [channel.port2]);
        return;
      }
      port = {
        onmessage: null,
        postMessage: function(data) { Vomnibar.onMessage({ data: data }); }
      };
      _this.sameOrigin = true;
      _this.port = { postMessage: function(data) { port.onmessage({ data: data}); } };
      if (location.hash === "#chrome-ui") { this.style.top = "5px"; }
      wnd.Vomnibar.showFavIcon = true;
      wnd.onmessage({ source: window, data: secret, ports: [port] });
    };
    VDom.UI.addElement(el, false);
  },
  onMessage: function(event) {
    var data = event.data;
    switch (data.name || data) {
    case "uiComponentIsReady":
      if (this.status !== 1) { return; }
      this.status = 2;
      this.show();
      break;
    case "style":
      if (this.status < 2) { return; }
      if (this.status === 2) {
        this.port.postMessage("afterOmni");
        this.onShown();
      }
      this.box.style.height = data.height + "px";
      break;
    case "focus": window.focus(); VEventMode.suppress(data.lastKey); break;
    case "hide": this.hide(true); break;
    case "scrollBy": VScroller.scrollBy(1, data.amount); break;
    case "scrollGoing": VScroller.keyIsDown = VScroller.Core.maxInterval; break;
    case "scrollEnd": VScroller.keyIsDown = 0; break;
    case "evalJS": VUtils.evalIfOK(data.url); break;
    case "broken": window.focus(); Vomnibar && this.destroy && this.destroy(); break;
    default: break;
    }
  },
  onShown: function() {
    this.status = 3;
    var style = this.box.style, width = this.width * 0.8;
    if (style.visibility) {
      style.visibility = "";
      style = VDom.UI.box.style;
    }
    this.sameOrigin ? (style.display = "")
      : setTimeout(function() { style.display = ""; }, 17);
    if (width !== (width | 0)) {
      this.box.style.width = (width | 0) / (width / 0.8) * 100 + "%";
    }
    VHandler.remove(this);
    VHandler.push(this.onKeydown, this);
  },
  onKeydown: function(event) {
    if (VKeyboard.isEscape(event)) { this.hide(); return 2; }
    var key = event.keyCode - VKeyCodes.f1;
    if (key === 0 || key === 1) {
      this.focus(key);
      return 2;
    }
    return 0;
  },
  focus: function(f2) {
    if (this.status < 3) { return; }
    this.box.contentWindow.focus();
    this.port.postMessage(f2 ? "focus" : "backspace");
  }
};
<|endoftext|>


<commit_before>'use strict';

const Path = require('path');
const Firedoc = require('firedoc').Firedoc;
const Helper = require('./helper.js');

var basicTypeMap = {
  number  : 'Number',
  Number  : 'Number',
  string  : 'String',
  String  : 'String',
  array   : 'Array',
  Array   : 'Array',
  boolean : 'Boolean',
  Boolean : 'Boolean',
  object  : 'Object',
  Object  : 'Object'
};

var basicTypeWithoutConflictMap = {
  number  : 'Number',
  Number  : 'Number',
  string  : 'String',
  String  : 'String',
  array   : 'Array',
  Array   : 'Array',
  boolean : 'Boolean',
  Boolean : 'Boolean'
};

function transforType(module, type, ignoreConflict) {

   var basicType = ignoreConflict ? basicTypeMap : basicTypeWithoutConflictMap;

  // don't transfor basic types
  if (basicType[type])
    return basicType[type];

  if (type === 'cc.Object')
    return 'ccObject';

  // add 'cc' prefix for engine module
  if (module === 'cc')
    return 'cc'.concat(type);

  // just return the type
  // TODO: some special operation for editor framework?
  return type;
}

// retrive necessary information from AST.members
// property = {
//    itemtype: ['method', 'property'], the value is 'method' if it is a method
//    type: the property type if itemtype='property'
//    return: {type: } the return type of method if it is a method
// }
//
// return value {name: description}
function generateMember(property) {
  var name = property.name;
  var description = '';

  if (property.itemtype === 'method') {
    // methods start with '?'
    description = description.concat('?')

    // return type
    var retType = property.return;
    if (retType)
      // FIXME: should change it when the framework comment use full type
      description = description.concat(transforType(property.module, retType, true));
    else
      description = description.concat('undefined');

    // parameter names
    var params = property.params;
    if (params) {
      description = description.concat(':');
      for (var i in params) {
        var param = params[i];
        description = description.concat(param.name);
        description = description.concat(',');
      }
      // remove last ','
      description = description.slice(0, -1);
    }
  }
  else {
    // it is a normal property, we just need its type information
    description = transforType(property.module, property.type, true);
  }

  var ret = {};
  ret[name] = new Definition(description, property.description);
  return ret;
}

function generateClass(clazz) {
  try {
    var ret = {};

    var description = clazz.namespace.split('.').join('');
    var superName = '';

    // super name
    var extend = clazz.extends;
    if (typeof(extend) === 'string')
      // FIXME: should change it when the framework comment use full type
      superName = transforType(clazz.module, extend, false);
    else
      superName = 'Object';

    // parameters for construction
    var params = clazz.params;
    if (params) {
      description = '?'.concat(description);
      description = description.concat(':');
      for (var i in params) {
        var param = params[i];
        description = description.concat(param.name);
        description = description.concat(',');
      }
      // remove last ','
      description.slice(0, -1);
    }

    // it is used to create class declaration
    var name = transforType(clazz.module, clazz.name, false)
    ret.classMeta = {};
    ret.classMeta[name] = {
      $$isBuiltin: true,
      $$proto: new Definition(superName)
    };

    var moduleMeta = {};
    moduleMeta[clazz.name] = new Definition(description, clazz.description);
    ret.moduleMeta = moduleMeta;

    return ret;
  } catch (e) {
    console.log('exception happens in ' + clazz.file);
    console.log('class name is ' + clazz.name);
    console.log(e);
  }
}

function printDashes() {
  console.log('---------------------------------');
}

function mergeObject(dst, src) {
  for (var attr in src) {
    dst[attr] = src[attr];
  }
}

function formatModuleInfos(modulesInfo) {
  for (var moduleName in modulesInfo) {
    var classesInfo = {};
    var module = modulesInfo[moduleName];
    for (var className in module.classes) {
      var classInfo = module.classes[className];
      mergeObject(classesInfo, classInfo);
    }
    module.classesInfo = classesInfo;
    delete module.classes;
  }
}

function generateModules(ast) {

  // modulesInfo = { moduleName: // module name
  //                            classes: {className:
  //                                                 { classMeta }
  //                                      },
  //                            members: [ {name, decription} ]
  //               }
  var modulesInfo = {};

  // get module name
  for (var moduleName in ast.modules) {
    modulesInfo[moduleName] = { classes: {},
                                $$isBuiltin: true,
                                $$proto: new Definition('Object') };
  }

  // get class info
  for (var className in ast.classes) {
    var c = ast.classes[className];
    var moduleName = c.module;
    if (!moduleName)
      continue;

    var classInfo = generateClass(c);
    if (!classInfo)
      continue;

    if (!modulesInfo[moduleName]) {
      console.log('!!!module of class: ' + className + ' is not a valid value: ' + moduleName);
      continue;
    }
    modulesInfo[moduleName].classes[className] = classInfo.classMeta;
    mergeObject(modulesInfo[moduleName], classInfo.moduleMeta);
  }

  // get class property info
  for (var i in ast.members) {
    var member = ast.members[i];
    if (member.name === '') {
      printDashes();
      console.log('!!!Do not have name');
      console.log(member)
      continue;
      printDashes();
    }

    var moduleName= member.module;
    if (!modulesInfo[moduleName]) {
      printDashes();
      console.log('!!!module of ' + member.name + ' is not a valid value: ' + moduleName);
      console.log(member.file);
      printDashes();
      continue;
    }

    var memberInfo = generateMember(member);
    var isModuleFunction = (member.clazz === '');
    if (isModuleFunction) {
      // it is a module member
      mergeObject(modulesInfo[moduleName], memberInfo);
    }
    else {
      // it is a class member
      var className = member.clazz;
      if (!modulesInfo[moduleName].classes[member.clazz]) {
        printDashes();
        console.log('!!!class of ' + member.name + ' is not a valid value: ' + className);
        console.log(member.file);
        printDashes();
        continue;
      }
      var classInfo = modulesInfo[moduleName].classes[className];
      var transformedClassName = transforType(moduleName, className, false);
      mergeObject(classInfo[transformedClassName], memberInfo);
    }
  }

  formatModuleInfos(modulesInfo);
  return modulesInfo;
}

// copy from 'esprima/types.js'
var Definition = function(typeName, description, range, path) {
  this.typeName = typeName;
  this.range = range;
  this.path = path;
  this.description = description;
};

exports.generateBuiltin = function(enginePath, eidtorPath, assetDbPath) {
  var doc = new Firedoc({
    cwd: Helper.editorRoot,
    paths: [enginePath],
    parseOnly: true
  });

  doc.build(function(err, ast, opt) {
    var builtins = generateModules(ast);
    var types = require('./esprima/types.js').Types;
    for (var module in builtins) {
      types.prototype[module] = builtins[module];
      mergeObject(types.prototype, builtins[module].classesInfo);
      delete builtins[module].classesInfo;
    }
  });
}

<commit_msg>enable AssetDB and Editor<commit_after>'use strict';

const Path = require('path');
const Firedoc = require('firedoc').Firedoc;
const Helper = require('./helper.js');

var basicTypeMap = {
  number  : 'Number',
  Number  : 'Number',
  string  : 'String',
  String  : 'String',
  array   : 'Array',
  Array   : 'Array',
  boolean : 'Boolean',
  Boolean : 'Boolean',
  object  : 'Object',
  Object  : 'Object'
};

var basicTypeWithoutConflictMap = {
  number  : 'Number',
  Number  : 'Number',
  string  : 'String',
  String  : 'String',
  array   : 'Array',
  Array   : 'Array',
  boolean : 'Boolean',
  Boolean : 'Boolean'
};

function transforType(module, type, ignoreConflict) {

   var basicType = ignoreConflict ? basicTypeMap : basicTypeWithoutConflictMap;

  // don't transfor basic types
  if (basicType[type])
    return basicType[type];

  if (type === 'cc.Object')
    return 'ccObject';

  // add 'cc' prefix for engine module
  if (module === 'cc')
    return 'cc'.concat(type);

  // just return the type
  // TODO: some special operation for editor framework?
  return type;
}

// retrive necessary information from AST.members
// property = {
//    itemtype: ['method', 'property'], the value is 'method' if it is a method
//    type: the property type if itemtype='property'
//    return: {type: } the return type of method if it is a method
// }
//
// return value {name: description}
function generateMember(property) {
  var name = property.name;
  var description = '';

  if (property.itemtype === 'method') {
    // methods start with '?'
    description = description.concat('?')

    // return type
    var retType = property.return;
    if (retType)
      // FIXME: should change it when the framework comment use full type
      description = description.concat(transforType(property.module, retType, true));
    else
      description = description.concat('undefined');

    // parameter names
    var params = property.params;
    if (params) {
      description = description.concat(':');
      for (var i in params) {
        var param = params[i];
        description = description.concat(param.name);
        description = description.concat(',');
      }
      // remove last ','
      description = description.slice(0, -1);
    }
  }
  else {
    // it is a normal property, we just need its type information
    description = transforType(property.module, property.type, true);
  }

  var ret = {};
  ret[name] = new Definition(description, property.description);
  return ret;
}

function generateClass(clazz) {
  try {
    var ret = {};

    var description = clazz.namespace.split('.').join('');
    var superName = '';

    // super name
    var extend = clazz.extends;
    if (typeof(extend) === 'string')
      // FIXME: should change it when the framework comment use full type
      superName = transforType(clazz.module, extend, false);
    else
      superName = 'Object';

    // parameters for construction
    var params = clazz.params;
    if (params) {
      description = '?'.concat(description);
      description = description.concat(':');
      for (var i in params) {
        var param = params[i];
        description = description.concat(param.name);
        description = description.concat(',');
      }
      // remove last ','
      description.slice(0, -1);
    }

    // it is used to create class declaration
    var name = transforType(clazz.module, clazz.name, false)
    ret.classMeta = {};
    ret.classMeta[name] = {
      $$isBuiltin: true,
      $$proto: new Definition(superName)
    };

    var moduleMeta = {};
    moduleMeta[clazz.name] = new Definition(description, clazz.description);
    ret.moduleMeta = moduleMeta;

    return ret;
  } catch (e) {
    console.log('exception happens in ' + clazz.file);
    console.log('class name is ' + clazz.name);
    console.log(e);
  }
}

function printDashes() {
  console.log('---------------------------------');
}

function mergeObject(dst, src) {
  for (var attr in src) {
    dst[attr] = src[attr];
  }
}

function formatModuleInfos(modulesInfo) {
  for (var moduleName in modulesInfo) {
    var classesInfo = {};
    var module = modulesInfo[moduleName];
    for (var className in module.classes) {
      var classInfo = module.classes[className];
      mergeObject(classesInfo, classInfo);
    }
    module.classesInfo = classesInfo;
    delete module.classes;
  }
}

function generateModules(ast) {

  // modulesInfo = { moduleName: // module name
  //                            classes: {className:
  //                                                 { classMeta }
  //                                      },
  //                            members: [ {name, decription} ]
  //               }
  var modulesInfo = {};

  // get module name
  for (var moduleName in ast.modules) {
    modulesInfo[moduleName] = { classes: {},
                                $$isBuiltin: true,
                                $$proto: new Definition('Object') };
  }

  // get class info
  for (var className in ast.classes) {
    var c = ast.classes[className];
    var moduleName = c.module;
    if (!moduleName)
      continue;

    var classInfo = generateClass(c);
    if (!classInfo)
      continue;

    if (!modulesInfo[moduleName]) {
      console.log('!!!module of class: ' + className + ' is not a valid value: ' + moduleName);
      continue;
    }
    modulesInfo[moduleName].classes[className] = classInfo.classMeta;
    mergeObject(modulesInfo[moduleName], classInfo.moduleMeta);
  }

  // get class property info
  for (var i in ast.members) {
    var member = ast.members[i];
    if (member.name === '') {
      printDashes();
      console.log('!!!Do not have name');
      console.log(member)
      continue;
      printDashes();
    }

    var moduleName= member.module;
    if (!modulesInfo[moduleName]) {
      printDashes();
      console.log('!!!module of ' + member.name + ' is not a valid value: ' + moduleName);
      console.log(member.file);
      printDashes();
      continue;
    }

    var memberInfo = generateMember(member);
    var isModuleFunction = (member.clazz === '');
    if (isModuleFunction) {
      // it is a module member
      mergeObject(modulesInfo[moduleName], memberInfo);
    }
    else {
      // it is a class member
      var className = member.clazz;
      if (!modulesInfo[moduleName].classes[member.clazz]) {
        printDashes();
        console.log('!!!class of ' + member.name + ' is not a valid value: ' + className);
        console.log(member.file);
        printDashes();
        continue;
      }
      var classInfo = modulesInfo[moduleName].classes[className];
      var transformedClassName = transforType(moduleName, className, false);
      mergeObject(classInfo[transformedClassName], memberInfo);
    }
  }

  formatModuleInfos(modulesInfo);
  return modulesInfo;
}

// copy from 'esprima/types.js'
var Definition = function(typeName, description, range, path) {
  this.typeName = typeName;
  this.range = range;
  this.path = path;
  this.description = description;
};

exports.generateBuiltin = function(enginePath, eidtorPath, assetDbPath) {
  var doc = new Firedoc({
    cwd: Helper.editorRoot,
    paths: [enginePath, eidtorPath, assetDbPath],
    parseOnly: true
  });

  doc.build(function(err, ast, opt) {
    var builtins = generateModules(ast);
    var types = require('./esprima/types.js').Types;
    for (var module in builtins) {
      types.prototype[module] = builtins[module];
      mergeObject(types.prototype, builtins[module].classesInfo);
      delete builtins[module].classesInfo;
    }
  });
}

<|endoftext|>


<commit_before>import _ from 'lodash';

import * as ActionTypes from '../action-types';
import * as ActionHelpers from '../action-helpers';
import {userParser} from '../../utils';

const {response} = ActionHelpers;
const indexById = list => _.keyBy(list || [], 'id');
const mergeByIds = (state, array) => _.merge(state, indexById(array));

export default function users(state = {}, action) {
  if (ActionHelpers.isFeedResponse(action)) {
    return mergeByIds(state, (action.payload.users || []).map(userParser));
  }
  switch (action.type) {
    case response(ActionTypes.WHO_AM_I):
    case response(ActionTypes.GET_USER_INFO): {
      let newState = state;

      // Add some users from "subscribers"
      newState = mergeByIds(newState, (action.payload.subscribers || []).map(userParser));

      // Add some users from "admins"
      newState = mergeByIds(newState, (action.payload.admins || []).map(userParser));

      // Add target user
      let userId = action.payload.users.id;
      let oldUser = state[userId] || {};
      let newUser = userParser(action.payload.users);
      return {...newState,
        [userId]: {...oldUser, ...newUser}
      };
    }
    case response(ActionTypes.GET_USER_SUBSCRIBERS): {
      return mergeByIds(state, (action.payload.subscribers || []).map(userParser));
    }
    case response(ActionTypes.CREATE_GROUP): {
      let userId = action.payload.groups.id;
      let newUser = userParser(action.payload.groups);
      return {...state,
        [userId]: {...newUser}
      };
    }
    case response(ActionTypes.UPDATE_GROUP): {
      let userId = action.payload.groups.id;
      let oldUser = state[userId] || {};
      let newUser = userParser(action.payload.groups);
      return {...state,
        [userId]: {...oldUser, ...newUser}
      };
    }
    case response(ActionTypes.PROMOTE_GROUP_ADMIN): {
      const group = _.find(state || [], {username: action.request.groupName});
      const newAdmins = [...group.administrators, action.request.user.id];
      return {...state,
        [group.id]: {...group,
          administrators: newAdmins
        }
      };
    }
    case response(ActionTypes.DEMOTE_GROUP_ADMIN): {
      const group = _.find(state || [], {username: action.request.groupName});
      const newAdmins = _.without(group.administrators, action.request.user.id);
      return {...state,
        [group.id]: {...group,
          administrators: newAdmins
        }
      };
    }
    case response(ActionTypes.SHOW_MORE_COMMENTS):
    case response(ActionTypes.SHOW_MORE_LIKES_ASYNC):
    case response(ActionTypes.GET_SINGLE_POST): {
      return mergeByIds(state, (action.payload.users || []).map(userParser));
    }
    case ActionTypes.REALTIME_POST_NEW:
    case ActionTypes.REALTIME_LIKE_NEW:
    case ActionTypes.REALTIME_COMMENT_NEW: {
      if (!action.users || !action.users.length) {
        return state;
      }
      const newUsers = action.users.filter(user => !state[user.id]);
      if (!newUsers.length) {
        return state;
      }
      return mergeByIds(state, newUsers.map(userParser));
    }
    case ActionTypes.HIGHLIGHT_COMMENT: {
      return state;
    }
    case ActionTypes.UNAUTHENTICATED:
      return {};
  }
  return state;
}
<commit_msg>Remove unused switch case in reducers/users.js<commit_after>import _ from 'lodash';

import * as ActionTypes from '../action-types';
import * as ActionHelpers from '../action-helpers';
import {userParser} from '../../utils';

const {response} = ActionHelpers;
const indexById = list => _.keyBy(list || [], 'id');
const mergeByIds = (state, array) => _.merge(state, indexById(array));

export default function users(state = {}, action) {
  if (ActionHelpers.isFeedResponse(action)) {
    return mergeByIds(state, (action.payload.users || []).map(userParser));
  }
  switch (action.type) {
    case response(ActionTypes.WHO_AM_I):
    case response(ActionTypes.GET_USER_INFO): {
      let newState = state;

      // Add some users from "subscribers"
      newState = mergeByIds(newState, (action.payload.subscribers || []).map(userParser));

      // Add some users from "admins"
      newState = mergeByIds(newState, (action.payload.admins || []).map(userParser));

      // Add target user
      let userId = action.payload.users.id;
      let oldUser = state[userId] || {};
      let newUser = userParser(action.payload.users);
      return {...newState,
        [userId]: {...oldUser, ...newUser}
      };
    }
    case response(ActionTypes.GET_USER_SUBSCRIBERS): {
      return mergeByIds(state, (action.payload.subscribers || []).map(userParser));
    }
    case response(ActionTypes.CREATE_GROUP): {
      let userId = action.payload.groups.id;
      let newUser = userParser(action.payload.groups);
      return {...state,
        [userId]: {...newUser}
      };
    }
    case response(ActionTypes.UPDATE_GROUP): {
      let userId = action.payload.groups.id;
      let oldUser = state[userId] || {};
      let newUser = userParser(action.payload.groups);
      return {...state,
        [userId]: {...oldUser, ...newUser}
      };
    }
    case response(ActionTypes.PROMOTE_GROUP_ADMIN): {
      const group = _.find(state || [], {username: action.request.groupName});
      const newAdmins = [...group.administrators, action.request.user.id];
      return {...state,
        [group.id]: {...group,
          administrators: newAdmins
        }
      };
    }
    case response(ActionTypes.DEMOTE_GROUP_ADMIN): {
      const group = _.find(state || [], {username: action.request.groupName});
      const newAdmins = _.without(group.administrators, action.request.user.id);
      return {...state,
        [group.id]: {...group,
          administrators: newAdmins
        }
      };
    }
    case response(ActionTypes.SHOW_MORE_COMMENTS):
    case response(ActionTypes.SHOW_MORE_LIKES_ASYNC):
    case response(ActionTypes.GET_SINGLE_POST): {
      return mergeByIds(state, (action.payload.users || []).map(userParser));
    }
    case ActionTypes.REALTIME_POST_NEW:
    case ActionTypes.REALTIME_LIKE_NEW:
    case ActionTypes.REALTIME_COMMENT_NEW: {
      if (!action.users || !action.users.length) {
        return state;
      }
      const newUsers = action.users.filter(user => !state[user.id]);
      if (!newUsers.length) {
        return state;
      }
      return mergeByIds(state, newUsers.map(userParser));
    }
    case ActionTypes.UNAUTHENTICATED:
      return {};
  }
  return state;
}
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react'

const renderPure = ComposedComponent => (
	class Pure extends PureComponent {
		shouldComponentUpdate(props, nextProps) {
			return props !== nextProps
		}

		render() {
			return <ComposedComponent {...this.props} />
		}
	}
)

export default renderPure
<commit_msg>Updated renderPure shouldComponentUpdate to not always cause rerenders<commit_after>import React, { PureComponent } from 'react'

const renderPure = ComposedComponent => (
	class Pure extends PureComponent {
		shouldComponentUpdate(props, nextProps) {
			return (
				Object.keys(props)
				.every(key => props[key] === nextProps[key])
				&& (
					Object.keys(nextProps)
					.every(key => nextProps[key] === props[key])
				)
			)
		}

		render() {
			return <ComposedComponent {...this.props} />
		}
	}
)

export default renderPure
<|endoftext|>


<commit_before>/****************
SAVE REPORTERS
*****************/

var savedHeader = "Selected Reporters:\n
";
var currentTmpReporters = "";
var currentTmpReportersCount = 0;

var allReporters = Array();
var allHighlightedReporters = Array();

function A_saveTmpReporter(reporter)	{
	var rep = reporter.value;

	if(reporter.checked == true)	{ // && currentTmpReporters.indexOf(reporter.value)==-1
		DynamicReport.saveTmpReporter(rep, A_saveTmpReporter_cb);
		//alert("Adding " + rep);
	}
	else	{
		DynamicReport.removeTmpReporter(rep, A_saveTmpReporter_cb);
		//alert("removing " + rep);
	}
}

function A_saveTmpReporter_cb(txt)	{
	//look9ing for txt["count"] and txt["reporters"]..txt["reporters"] is a
 delim string
	//reporter has been added to the list,
	//show how many we've saved,
	if(txt["count"] > -1) {
		if($("reporterCount"))
			$("reporterCount").innerHTML = txt["count"] + " reporters selected";
		currentTmpReportersCount = txt["count"];

		//update the running tab for overlib if this is not an init call
		currentTmpReporters = txt["elements"];

		//highlight box in red with the tempReporterName if we have some waiting to be saved
		if($("tmp_prb_queryName") && txt["count"] > 0)
			$("tmp_prb_queryName").style.border = "1px solid red";
	}
	else	{
		A_clearTmpReporters_cb("");
	}
}

function A_initSaveReporter()	{
	DynamicReport.saveTmpReporter("", A_initTmpReporter_cb);
}

function A_initTmpReporter_cb(txt)	{
	A_saveTmpReporter_cb(txt);
	//now, check the ones if theyve been previously selected
	var field = document.getElementsByName('tmpReporter');
	if(field.length > 1 && currentTmpReporters != "")	{
		for (i = 0; i < field.length; i++)	{
			if(currentTmpReporters.indexOf(field[i].value) != -1 )
				field[i].checked = true ;
		}
	}
	else	{
		if(currentTmpReporters.indexOf(field.value) != -1 )
			field.checked = true;
	}
}

function A_clearTmpReporters()	{
	DynamicReport.clearTmpReporters(A_clearTmpReporters_cb);
}

function A_clearTmpReporters_cb(txt)	{
		if($("reporterCount"))
			$("reporterCount").innerHTML = "";
		currentTmpReportersCount = 0;
		currentTmpReporters = "";
		if($("tmp_prb_queryName"))
			$("tmp_prb_queryName").style.border = "1px solid";

		A_uncheckAll(document.getElementsByName('tmpReporter'));
}

function A_checkAll(field)	{
		if(field.length > 1)	{
			for (i = 0; i < field.length; i++)	{
				field[i].checked = true ;
				A_saveTmpReporter(field[i]);
			}
		}
		else
			field.checked = true;
}

function A_checkAllOnAll(box)	{
	//clear the tmp ones weve already checked
	//get all the items on all pages and savethem
	//alert(allReporters.length);
	//update the UI to show which ones are checked and precheck all the boxes
	if(box.checked && allReporters.length && allReporters.length > 1)	{
	//	SaveGenes.A_checkAll(allGenes);
		if(allReporters.length > 1)	{
			DynamicReport.saveTmpGenericFromArray("tmpReporterList",allReporters,A_saveTmpReporter_cb);

			setTimeout(function() { A_initSaveReporter(''); }, 500);
		}
	}
	else if(!box.checked)	{
		A_clearTmpReporters();
	}
}

function A_uncheckAll(field)	{

	if(field.length > 1)	{
		for (i = 0; i < field.length; i++)	{
			field[i].checked = false ;
			A_saveTmpReporter(field[i]);
		}
	}
	else
		field.checked = false;

	$("checkAll").checked = false;

}

function manageCheckAll(box)	{
	if(box.checked)	{
		A_checkAll(document.getElementsByName('tmpReporter'));
	}
	else	{
		A_uncheckAll(document.getElementsByName('tmpReporter'));
	}
}

function A_saveReporters()	{
	//get the name
	var name = $("tmp_prb_queryName").value;
	if(name != "")	{
		//convert the overlib list to a comma seperated list
		if(currentTmpReporters != "")	{
			var replaceme = "
";
			var commaSepList = currentTmpReporters.replace(/
/g, ",");
			if(commaSepList.charAt(commaSepList.length-1) == ",")
				commaSepList = commaSepList.substring(0, commaSepList.length-1);
			//alert("="+commaSepList+"=");
			DynamicReport.saveReporters(commaSepList, name, A_saveReporters_cb);
		}
		else	{
			alert("Please select some reporters to save");
		}
	}
	else	{
		alert("Please enter a name for your reporter group");
	}
}

function A_saveReporters_cb(txt)	{
	var results = txt == "pass" ? "Reporter List Saved" : "There was a problem saving your reporter list";
	alert(results); //pass | fail
	if(txt != "fail")	{
		//erase the name
		$("tmp_prb_queryName").value = "";
		//clear the sample list
		A_clearTmpReporters();
	}

}

/*********************
END SAVE REPORTERS
***********************/

//not going to use this function for now
function filterRow(pvalue)	{
	pvalue = "0.0100";
	var my_table = document.getElementById("dataTable");
	var my_rows = my_table.rows;
	//var rows = document.getElementsByTagName("tr");
	for(i=1; i<my_rows.length; i++)	{ //dont look @ header
		if(my_rows[i].id > pvalue)	{
			//my_rows[i].style.display = "none";
			my_table.deleteRow(i);
		}
	}
}

function checkStep()	{
	var val = document.forms.paginate.p_step.value;
	if(val > "500" || val > 500)	{
		//alert('too many');
		$("checkAllBlock").innerHTML = "reduce size to check all";
	}
}

function initPagination()	{
	var my_table = document.getElementById("dataTable");
	var my_rows = my_table.rows;
	//alert(my_rows.length-1);
}

function initSortArrows()	{

	var element = document.forms['paginate'].p_sort_element.value;
	var method = document.forms['paginate'].p_sort_method.value;

	var imgsrc = "images/sort-none.png";
	var upimgsrc = "images/openUpArrow.png";
	var downimgsrc = "images/openDownArrow.png";

	if(method == "ascending")	{
		downimgsrc = "images/openDownArrow.png";
		upimgsrc = "images/closedUpArrow.png";
	}
	else if(method == "descending")	{
		downimgsrc = "images/closedDownArrow.png";
		upimgsrc = "images/openUpArrow.png";
	}
	if(document.getElementById(element+"_sort_img_up"))	{
		if(document.getElementById(element+"_sort_img_up").src != upimgsrc)	{
			document.getElementById(element+"_sort_img_up").src = upimgsrc;
		}
	}
	if(document.getElementById(element+"_sort_img_down"))	{
		if(document.getElementById(element+"_sort_img_down").src != downimgsrc)	{
			document.getElementById(element+"_sort_img_down").src = downimgsrc;
		}
	}

}

function goSort(element, method, key)	{
	//reuse the paginate form
	if(document.forms['paginate'].p_sort_element)
		 document.forms['paginate'].p_sort_element.value = element;
	if(document.forms['paginate'].p_sort_method)
		 document.forms['paginate'].p_sort_method.value = method;
	//go back to the start
	if(document.forms['paginate'].p_page)
		 document.forms['paginate'].p_page.value = "0";
	if(document.forms['paginate'].p_step)
		 document.forms['paginate'].p_step.value = "25";

	document.forms['paginate'].submit();
}<commit_msg>*** empty log message ***<commit_after>/****************
SAVE REPORTERS
*****************/

var savedHeader = "Selected Reporters:\n
";
var currentTmpReporters = "";
var currentTmpReportersCount = 0;

var allReporters = Array();
var allHighlightedReporters = Array();

function A_saveTmpReporter(reporter)	{
	var rep = reporter.value;

	if(reporter.checked == true)	{ // && currentTmpReporters.indexOf(reporter.value)==-1
		DynamicReport.saveTmpReporter(rep, A_saveTmpReporter_cb);
		//alert("Adding " + rep);
	}
	else	{
		DynamicReport.removeTmpReporter(rep, A_saveTmpReporter_cb);
		//alert("removing " + rep);
	}
}

function A_saveTmpReporter_cb(txt)	{
	//look9ing for txt["count"] and txt["reporters"]..txt["reporters"] is a
 delim string
	//reporter has been added to the list,
	//show how many we've saved,
	if(txt["count"] > -1) {
		if($("reporterCount"))
			$("reporterCount").innerHTML = txt["count"] + " reporters selected";
		currentTmpReportersCount = txt["count"];

		//update the running tab for overlib if this is not an init call
		currentTmpReporters = txt["elements"];

		//highlight box in red with the tempReporterName if we have some waiting to be saved
		if($("tmp_prb_queryName") && txt["count"] > 0)
			$("tmp_prb_queryName").style.border = "1px solid red";
	}
	else	{
		A_clearTmpReporters_cb("");
	}
}

function A_initSaveReporter()	{
	DynamicReport.saveTmpReporter("", A_initTmpReporter_cb);
}

function A_initTmpReporter_cb(txt)	{
	A_saveTmpReporter_cb(txt);
	//now, check the ones if theyve been previously selected
	var field = document.getElementsByName('tmpReporter');
	if(field.length > 1 && (currentTmpReporters != "" || allHighlightedReporters.length>0))	{
		for (i = 0; i < field.length; i++)	{
			if(currentTmpReporters.indexOf(field[i].value) != -1 || allHighlightedReporters.inArray(field[i].value))
				field[i].checked = true ;
		}
	}
	else	{
		if(currentTmpReporters.indexOf(field.value) != -1  || allHighlightedReporters.inArray(field[i].value))
			field.checked = true;
	}
}

function A_clearTmpReporters()	{
	DynamicReport.clearTmpReporters(A_clearTmpReporters_cb);
}

function A_clearTmpReporters_cb(txt)	{
		if($("reporterCount"))
			$("reporterCount").innerHTML = "";
		currentTmpReportersCount = 0;
		currentTmpReporters = "";
		if($("tmp_prb_queryName"))
			$("tmp_prb_queryName").style.border = "1px solid";

		A_uncheckAll(document.getElementsByName('tmpReporter'));
}

function A_checkAll(field)	{
		if(field.length > 1)	{
			for (i = 0; i < field.length; i++)	{
				field[i].checked = true ;
				A_saveTmpReporter(field[i]);
			}
		}
		else
			field.checked = true;
}

function A_checkAllOnAll(box)	{
	//clear the tmp ones weve already checked
	//get all the items on all pages and savethem
	//alert(allReporters.length);
	//update the UI to show which ones are checked and precheck all the boxes
	if(box.checked && allReporters.length && allReporters.length > 1)	{
	//	SaveGenes.A_checkAll(allGenes);
		if(allReporters.length > 1)	{
			DynamicReport.saveTmpGenericFromArray("tmpReporterList",allReporters,A_saveTmpReporter_cb);

			setTimeout(function() { A_initSaveReporter(''); }, 500);
		}
	}
	else if(!box.checked)	{
		A_clearTmpReporters();
	}
}

function A_uncheckAll(field)	{

	if(field.length > 1)	{
		for (i = 0; i < field.length; i++)	{
			field[i].checked = false ;
			A_saveTmpReporter(field[i]);
		}
	}
	else
		field.checked = false;

	$("checkAll").checked = false;

}

function manageCheckAll(box)	{
	if(box.checked)	{
		A_checkAll(document.getElementsByName('tmpReporter'));
	}
	else	{
		A_uncheckAll(document.getElementsByName('tmpReporter'));
	}
}

function A_saveReporters()	{
	//get the name
	var name = $("tmp_prb_queryName").value;
	if(name != "")	{
		//convert the overlib list to a comma seperated list
		if(currentTmpReporters != "")	{
			var replaceme = "
";
			var commaSepList = currentTmpReporters.replace(/
/g, ",");
			if(commaSepList.charAt(commaSepList.length-1) == ",")
				commaSepList = commaSepList.substring(0, commaSepList.length-1);
			//alert("="+commaSepList+"=");
			DynamicReport.saveReporters(commaSepList, name, A_saveReporters_cb);
		}
		else	{
			alert("Please select some reporters to save");
		}
	}
	else	{
		alert("Please enter a name for your reporter group");
	}
}

function A_saveReporters_cb(txt)	{
	var results = txt == "pass" ? "Reporter List Saved" : "There was a problem saving your reporter list";
	alert(results); //pass | fail
	if(txt != "fail")	{
		//erase the name
		$("tmp_prb_queryName").value = "";
		//clear the sample list
		A_clearTmpReporters();
	}

}

/*********************
END SAVE REPORTERS
***********************/

//not going to use this function for now
function filterRow(pvalue)	{
	pvalue = "0.0100";
	var my_table = document.getElementById("dataTable");
	var my_rows = my_table.rows;
	//var rows = document.getElementsByTagName("tr");
	for(i=1; i<my_rows.length; i++)	{ //dont look @ header
		if(my_rows[i].id > pvalue)	{
			//my_rows[i].style.display = "none";
			my_table.deleteRow(i);
		}
	}
}

function checkStep()	{
	var val = document.forms.paginate.p_step.value;
	if(val > "500" || val > 500)	{
		//alert('too many');
		$("checkAllBlock").innerHTML = "reduce size to check all";
	}
}

function initPagination()	{
	var my_table = document.getElementById("dataTable");
	var my_rows = my_table.rows;
	//alert(my_rows.length-1);
}

function initSortArrows()	{

	var element = document.forms['paginate'].p_sort_element.value;
	var method = document.forms['paginate'].p_sort_method.value;

	var imgsrc = "images/sort-none.png";
	var upimgsrc = "images/openUpArrow.png";
	var downimgsrc = "images/openDownArrow.png";

	if(method == "ascending")	{
		downimgsrc = "images/openDownArrow.png";
		upimgsrc = "images/closedUpArrow.png";
	}
	else if(method == "descending")	{
		downimgsrc = "images/closedDownArrow.png";
		upimgsrc = "images/openUpArrow.png";
	}
	if(document.getElementById(element+"_sort_img_up"))	{
		if(document.getElementById(element+"_sort_img_up").src != upimgsrc)	{
			document.getElementById(element+"_sort_img_up").src = upimgsrc;
		}
	}
	if(document.getElementById(element+"_sort_img_down"))	{
		if(document.getElementById(element+"_sort_img_down").src != downimgsrc)	{
			document.getElementById(element+"_sort_img_down").src = downimgsrc;
		}
	}

}

function goSort(element, method, key)	{
	//reuse the paginate form
	if(document.forms['paginate'].p_sort_element)
		 document.forms['paginate'].p_sort_element.value = element;
	if(document.forms['paginate'].p_sort_method)
		 document.forms['paginate'].p_sort_method.value = method;
	//go back to the start
	if(document.forms['paginate'].p_page)
		 document.forms['paginate'].p_page.value = "0";
	if(document.forms['paginate'].p_step)
		 document.forms['paginate'].p_step.value = "25";

	document.forms['paginate'].submit();
}<|endoftext|>


<commit_before>var osmosis = require('osmosis');
var user = require('../user');
var course = require('../course');
var assignmentEntry = require('./assignmentEntry')

// user.
var currUser;

// Osmosis Configuration.

function Owl(id, pass) {
    return new Promise((resolve, reject) => {
        osmosis
        .post('https://owl.uwo.ca/portal/relogin')
        .login(id, pass)
        .then(function(context, data, next) {
            // Redirected if successful login.
            if (context.doc().request.pathname === '/portal/relogin') {
                reject(new Error('INVALID CREDENTIALS'));
            } else {
                // Successful login, create new user.
                currUser = new user(id, pass, context.doc().cookies, new Array())
                // Send data to the next command.
                next(context, data);
            }
        })
        .follow('#allSites @href')
        .set('course_url', 'div.title @href')
        .data(function(data) {
            // Save All Courses URL page.
            currUser.course_url = data.course_url;
        })
        .done(function() {
            // Return current user object.
            resolve(currUser);
        })
    })
}

module.exports = Owl;<commit_msg>Update auth.js<commit_after>const osmosis = require('osmosis');
const user = require('../user');

function Owl(id, pass) {
    let currUser;

    return new Promise((resolve, reject) => {
        osmosis
        .post('https://owl.uwo.ca/portal/relogin')
        .login(id, pass)
        .then(function(context, data, next) {
            // Redirected if successful login.
            if (context.doc().request.pathname === '/portal/relogin') {
                reject(new Error('INVALID CREDENTIALS'));
            } else {
                // Successful login, create new user.
                currUser = new user(id, pass, context.doc().cookies, new Array())
                // Send the current context and data to the next command.
                next(context, data);
            }
        })
        .follow('#allSites @href')
        // Get the direct iframe url...
        .set('course_url', 'div.title @href')
        .data(function(data) {
            // Save All Courses URL page.
            currUser.courses_url = data.course_url;
        })
        .done(() => resolve(currUser))
    })
}

module.exports = Owl;
<|endoftext|>


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

// délègue tous les get/set des propriétés de layout à '_content'
// réutilisable pour tous les cas où l'on veut simplement déléguer à un composant principal, en surchargeant uniquement certaines méthodes
module.exports = {
	width: delegateGetSet('_content', 'width'),
	height: delegateGetSet('_content', 'height'),
	depth: delegateGetSet('_content', 'depth'),
	left: delegateGetSet('_content', 'left'),
	top: delegateGetSet('_content', 'top'),
	zIndex: delegateGetSet('_content', 'zIndex'),
	parentNode: delegateGetSet('_content', 'parentNode'),
	containerVisible: delegateGetSet('_content', 'containerVisible'),
	visible: delegateGetSet('_content', 'visible'),
};<commit_msg>make _ContentDelegate onHeight compatible<commit_after>var delegateGetSet = require('./utils/delegateGetSet');

// délègue tous les get/set des propriétés de layout à '_content'
// réutilisable pour tous les cas où l'on veut simplement déléguer à un composant principal, en surchargeant uniquement certaines méthodes
module.exports = {
	width: delegateGetSet('_content', 'width'),
	height: delegateGetSet('_content', 'height'),
	depth: delegateGetSet('_content', 'depth'),
	left: delegateGetSet('_content', 'left'),
	top: delegateGetSet('_content', 'top'),
	zIndex: delegateGetSet('_content', 'zIndex'),
	parentNode: delegateGetSet('_content', 'parentNode'),
	containerVisible: delegateGetSet('_content', 'containerVisible'),
	visible: delegateGetSet('_content', 'visible'),
	onHeight: function (cb) {
		return this._content.onHeight && this._content.onHeight(cb)
	},
};
<|endoftext|>