<commit_before>
const { BrowserBuilder } = require('@angular-devkit/build-angular/src/browser');
const { ServerBuilder } = require('@angular-devkit/build-angular/src/server');
const { getWebpackStatsConfig } = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/utils');
const {
  statsErrorsToString,
  statsToString,
  statsWarningsToString
} = require('@angular-devkit/build-angular/src/angular-cli-files/utilities/stats');

const { join, normalize, resolve, virtualFs } = require('@angular-devkit/core');

const rimraf = require('rimraf');
const supportsColor = require('supports-color');
const webpackMerge = require('webpack-merge');

const {
  Observable,
  from: fromPromise,
  of: observableOf,
  zip
} = require('rxjs');
const { concatMap, map } = require('rxjs/operators');

const udk = require('../../lib/udk');

class UdkBuilder {
  constructor(context) {
    this.context = context;
  }

  run(builderConfig) {
    return this.buildWebpackConfig(builderConfig.options).pipe(
      concatMap((multiConfig) => new Observable((obs) => {
        if (builderConfig.options.deleteOutputPath) {
          this._deleteOutputPath(multiConfig);
        };

        try {
          const webpackCompiler = udk(multiConfig);

          webpackCompiler.run((err, stats) => {
            if (err) {
              return obs.error(err);
            }

            this._printStats(stats, builderConfig.options.verbose);

            obs.next({ success: !stats.hasErrors() });
            obs.complete();
          });
        } catch (err) {
          if (err) {
            this.context.logger.error(
              '\nAn error occured during the build:\n' + ((err && err.stack) || err));
          }
          throw err;
        }
      }))
    );
  }

  buildWebpackConfig(options) {
    const {
      main,
      browserTarget,
      serverTarget,
      partialBrowserConfig,
      partialServerConfig,
      fileReplacements,
      deleteOutputPath
    } = options;

    return zip(
      this._getWebpackConfigForBuilder(
        BrowserBuilder,
        browserTarget,
        partialBrowserConfig
      ),
      this._getWebpackConfigForBuilder(
        ServerBuilder,
        serverTarget,
        partialServerConfig,
        fileReplacements
      )
    ).pipe(
      map((multiConfig) => {
        const [
          browserConfig,
          serverConfig
        ] = multiConfig;

        if (!browserConfig.name) {
          browserConfig.name = 'browser';
        }

        if (!multiConfig[1].name) {
          serverConfig.name = 'server';
        }

        // set browserConfig as serverConfig's dependency
        serverConfig.dependencies = [ browserConfig.name ];

        serverConfig.entry = {
          ...serverConfig.entry,
          // move options.serverTarget main into ngmodule entry
          ngmodule: serverConfig.entry.main,
          // set options.main as real main entry
          main: resolve(this.context.workspace.root, main)
        };

        return multiConfig;
      })
    );
  }

  _applyPartialWebpackConfig(webpackConfig, partialWebpackConfig$) {
    if (partialWebpackConfig$ && typeof partialWebpackConfig$.then === 'function') {
      partialWebpackConfig$ = fromPromise(partialWebpackConfig$);
    } else if (!partialWebpackConfig$ || typeof partialWebpackConfig$.subscribe !== 'function') {
      partialWebpackConfig$ = observableOf(partialWebpackConfig$);
    }

    return partialWebpackConfig$.pipe(
      concatMap((partialWebpackConfig) => {
        if (typeof partialWebpackConfig === 'string') {
          const partialWebpackConfigPath = resolve(
            this.context.workspace.root,
            partialWebpackConfig
          );

          partialWebpackConfig = require(partialWebpackConfigPath);
        }

        if (typeof partialWebpackConfig === 'function') {
          return this._applyPartialWebpackConfig(
            webpackConfig,
            partialWebpackConfig(webpackConfig)
          );
        }

        if (typeof partialWebpackConfig === 'object') {
          webpackConfig = webpackMerge(webpackConfig, partialWebpackConfig);
        }

        return observableOf(webpackConfig);
      })
    );
  }

  _getBuilderConfig(projectTarget) {
    const architect = this.context.architect;
    const [project, target, configuration] = projectTarget.split(':');
    // Override browser build watch setting.
    // const overrides = { watch: options.watch };
    const targetSpec = { project, target, configuration/*, overrides*/ };
    const builderConfig = architect.getBuilderConfiguration(targetSpec);

    return architect.getBuilderDescription(builderConfig).pipe(
      concatMap(builderDescription => {
        return architect.validateBuilderOptions(builderConfig, builderDescription)
      })
    );
  }

  _deleteOutputPath(webpackConfig) {
    if (Array.isArray(webpackConfig)) {
      return webpackConfig.forEach((c) => {
        this._deleteOutputPath(c);
      });
    }

    rimraf.sync(webpackConfig.output.path);
  }

  _getWebpackConfigForBuilder(BuilderCtor, projectTarget, partialWebpackConfig, fileReplacements) {
    return this._getBuilderConfig(projectTarget).pipe(
      concatMap((builderConfig) => {
        const builder = new BuilderCtor(this.context);

        const { root } = this.context.workspace;
        const projectRoot = resolve(root, builderConfig.root);

        if (fileReplacements) {
          const host = new virtualFs.AliasHost(this.context.host);

          fileReplacements.forEach(({ src, replaceWith }) => {
            host.aliases.set(
              join(root, normalize(src)),
              join(root, normalize(replaceWith)),
            );
          });

          this.context.host = host;
        }

        let webpackConfig;

        webpackConfig = builder.buildWebpackConfig(
          root,
          projectRoot,
          this.context.host,
          builderConfig.options
        );

        return this._applyPartialWebpackConfig(webpackConfig, partialWebpackConfig);
      })
    );
  }

  _printStats(stats, verbose) {
    if (Array.isArray(stats.stats)) {
      return stats.stats.forEach((s) => {
        this._printStats(s, verbose)
      });
    }

    const statsConfig = getWebpackStatsConfig(verbose);
    statsConfig.colors = supportsColor.stdout;

    this.context.logger.info('Child ' + stats.compilation.name);

    const json = stats.toJson(statsConfig);

    if (verbose) {
      this.context.logger.info(stats.toString(statsConfig));
    } else {
      this.context.logger.info(statsToString(json, statsConfig));
      if (stats.hasWarnings()) {
        this.context.logger.warn(statsWarningsToString(json, statsConfig));
      }
      if (stats.hasErrors()) {
        this.context.logger.error(statsErrorsToString(json, statsConfig));
      }
    }
  }
}

module.exports = {
  default: UdkBuilder,
  UdkBuilder
};
<commit_msg>udk/angular: fix udk:udk-builder file replacements<commit_after>
const { BrowserBuilder } = require('@angular-devkit/build-angular/src/browser');
const { ServerBuilder } = require('@angular-devkit/build-angular/src/server');
const { addFileReplacements } = require('@angular-devkit/build-angular/src/utils');
const { getWebpackStatsConfig } = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/utils');
const {
  statsErrorsToString,
  statsToString,
  statsWarningsToString
} = require('@angular-devkit/build-angular/src/angular-cli-files/utilities/stats');

const { join, normalize, resolve, virtualFs } = require('@angular-devkit/core');

const rimraf = require('rimraf');
const supportsColor = require('supports-color');
const webpackMerge = require('webpack-merge');

const {
  Observable,
  from: fromPromise,
  of: observableOf,
  zip
} = require('rxjs');
const { concatMap, map } = require('rxjs/operators');

const udk = require('../../lib/udk');

class UdkBuilder {
  constructor(context) {
    this.context = context;
  }

  run(builderConfig) {
    return this.buildWebpackConfig(builderConfig.options).pipe(
      concatMap((multiConfig) => new Observable((obs) => {
        if (builderConfig.options.deleteOutputPath) {
          this._deleteOutputPath(multiConfig);
        };

        try {
          const webpackCompiler = udk(multiConfig);

          webpackCompiler.run((err, stats) => {
            if (err) {
              return obs.error(err);
            }

            this._printStats(stats, builderConfig.options.verbose);

            obs.next({ success: !stats.hasErrors() });
            obs.complete();
          });
        } catch (err) {
          if (err) {
            this.context.logger.error(
              '\nAn error occured during the build:\n' + ((err && err.stack) || err));
          }
          throw err;
        }
      }))
    );
  }

  buildWebpackConfig(options) {
    const {
      main,
      browserTarget,
      serverTarget,
      partialBrowserConfig,
      partialServerConfig,
      fileReplacements,
      deleteOutputPath
    } = options;

    return zip(
      this._getWebpackConfigForBuilder(
        BrowserBuilder,
        browserTarget,
        partialBrowserConfig
      ),
      this._getWebpackConfigForBuilder(
        ServerBuilder,
        serverTarget,
        partialServerConfig,
        fileReplacements
      )
    ).pipe(
      map((multiConfig) => {
        const [
          browserConfig,
          serverConfig
        ] = multiConfig;

        if (!browserConfig.name) {
          browserConfig.name = 'browser';
        }

        if (!multiConfig[1].name) {
          serverConfig.name = 'server';
        }

        // set browserConfig as serverConfig's dependency
        serverConfig.dependencies = [ browserConfig.name ];

        serverConfig.entry = {
          ...serverConfig.entry,
          // move options.serverTarget main into ngmodule entry
          ngmodule: serverConfig.entry.main,
          // set options.main as real main entry
          main: resolve(this.context.workspace.root, main)
        };

        return multiConfig;
      })
    );
  }

  _applyPartialWebpackConfig(webpackConfig, partialWebpackConfig$) {
    if (partialWebpackConfig$ && typeof partialWebpackConfig$.then === 'function') {
      partialWebpackConfig$ = fromPromise(partialWebpackConfig$);
    } else if (!partialWebpackConfig$ || typeof partialWebpackConfig$.subscribe !== 'function') {
      partialWebpackConfig$ = observableOf(partialWebpackConfig$);
    }

    return partialWebpackConfig$.pipe(
      concatMap((partialWebpackConfig) => {
        if (typeof partialWebpackConfig === 'string') {
          const partialWebpackConfigPath = resolve(
            this.context.workspace.root,
            partialWebpackConfig
          );

          partialWebpackConfig = require(partialWebpackConfigPath);
        }

        if (typeof partialWebpackConfig === 'function') {
          return this._applyPartialWebpackConfig(
            webpackConfig,
            partialWebpackConfig(webpackConfig)
          );
        }

        if (typeof partialWebpackConfig === 'object') {
          webpackConfig = webpackMerge(webpackConfig, partialWebpackConfig);
        }

        return observableOf(webpackConfig);
      })
    );
  }

  _getBuilderConfig(projectTarget) {
    const architect = this.context.architect;
    const [project, target, configuration] = projectTarget.split(':');
    // Override browser build watch setting.
    // const overrides = { watch: options.watch };
    const targetSpec = { project, target, configuration/*, overrides*/ };
    const builderConfig = architect.getBuilderConfiguration(targetSpec);

    return architect.getBuilderDescription(builderConfig).pipe(
      concatMap(builderDescription => {
        return architect.validateBuilderOptions(builderConfig, builderDescription)
      })
    );
  }

  _deleteOutputPath(webpackConfig) {
    if (Array.isArray(webpackConfig)) {
      return webpackConfig.forEach((c) => {
        this._deleteOutputPath(c);
      });
    }

    rimraf.sync(webpackConfig.output.path);
  }

  _getWebpackConfigForBuilder(BuilderCtor, projectTarget, partialWebpackConfig, fileReplacements = []) {
    const { root } = this.context.workspace;
    const host = new virtualFs.AliasHost(this.context.host);

    let options;
    let projectRoot;

    return this._getBuilderConfig(projectTarget).pipe(
      concatMap((builderConfig) => {
        options = builderConfig.options;
        projectRoot = resolve(root, builderConfig.root);

        return observableOf(null);
      }),
      concatMap(() => addFileReplacements(root, host, fileReplacements)),
      concatMap(() => addFileReplacements(root, host, options.fileReplacements || [])),
      concatMap(() => {
        const builder = new BuilderCtor(this.context);
        let webpackConfig;

        webpackConfig = builder.buildWebpackConfig(
          root,
          projectRoot,
          host,
          options
        );

        return this._applyPartialWebpackConfig(webpackConfig, partialWebpackConfig);
      })
    );
  }

  _printStats(stats, verbose) {
    if (Array.isArray(stats.stats)) {
      return stats.stats.forEach((s) => {
        this._printStats(s, verbose)
      });
    }

    const statsConfig = getWebpackStatsConfig(verbose);
    statsConfig.colors = supportsColor.stdout;

    this.context.logger.info('Child ' + stats.compilation.name);

    const json = stats.toJson(statsConfig);

    if (verbose) {
      this.context.logger.info(stats.toString(statsConfig));
    } else {
      this.context.logger.info(statsToString(json, statsConfig));
      if (stats.hasWarnings()) {
        this.context.logger.warn(statsWarningsToString(json, statsConfig));
      }
      if (stats.hasErrors()) {
        this.context.logger.error(statsErrorsToString(json, statsConfig));
      }
    }
  }
}

module.exports = {
  default: UdkBuilder,
  UdkBuilder
};
<|endoftext|>


<commit_before>define(["dojo/_base/declare", "dojo/has", "dojo/on", "../util/misc", "put-selector/put", "dojo/i18n!./nls/columnHider", "xstyle/css!../css/extensions/ColumnHider.css"],
function(declare, has, listen, miscUtil, put, i18n){
/*
 *	Column Hider plugin for dgrid
 *	Originally contributed by TRT 2011-09-28
 *
 *	A dGrid plugin that attaches a menu to a dgrid, along with a way of opening it,
 *	that will allow you to show and hide columns.  A few caveats:
 *
 *	1. Menu placement is entirely based on CSS definitions.
 *	2. If you want columns initially hidden, you must add "hidden: true" to your
 *		column definition.
 *	3. This implementation does NOT support ColumnSet, and has not been tested
 *		with multi-subrow records.
 *	4. Column show/hide is controlled via straight up HTML checkboxes.  If you
 *		are looking for something more fancy, you'll probably need to use this
 *		definition as a template to write your own plugin.
 *
 */

	var activeGrid, // references grid for which the menu is currently open
		bodyListener, // references pausable event handler for body mousedown
		// Need to handle old IE specially for checkbox listener and for attribute.
		hasIE = has("ie"),
		hasIEQuirks = hasIE && has("quirks"),
		forAttr = hasIE < 8 || hasIEQuirks ? "htmlFor" : "for";

	function getColumnIdFromCheckbox(cb, grid){
		// Given one of the checkboxes from the hider menu,
		// return the id of the corresponding column.
		// (e.g. gridIDhere-hider-menu-check-colIDhere -> colIDhere)
		return cb.id.substr(grid.id.length + 18);
	}

	return declare(null, {
		// hiderMenuNode: DOMNode
		//		The node for the menu to show/hide columns.
		hiderMenuNode: null,

		// hiderToggleNode: DOMNode
		//		The node for the toggler to open the menu.
		hiderToggleNode: null,

		// i18nColumnHider: Object
		//		This object contains all of the internationalized strings for
		//		the ColumnHider extension as key/value pairs.
		i18nColumnHider: i18n,

		// _hiderMenuOpened: Boolean
		//		Records the current open/closed state of the menu.
		_hiderMenuOpened: false,

		// _columnHiderRules: Object
		//		Hash containing handles returned from addCssRule.
		_columnHiderRules: null,

		// _columnHiderCheckboxes: Object
		//		Hash containing checkboxes generated for menu items.
		_columnHiderCheckboxes: null,

		_renderHiderMenuEntries: function(){
			// summary:
			//		Iterates over subRows for the sake of adding items to the
			//		column hider menu.

			var subRows = this.subRows,
				first = true,
				srLength, cLength, sr, c, checkbox;

			delete this._columnHiderFirstCheckbox;

			for(sr = 0, srLength = subRows.length; sr < srLength; sr++){
				for(c = 0, cLength = subRows[sr].length; c < cLength; c++){
					this._renderHiderMenuEntry(subRows[sr][c]);
					if(first){
						first = false;
						this._columnHiderFirstCheckbox =
							this._columnHiderCheckboxes[subRows[sr][c].id];
					}
				}
			}
		},

		_renderHiderMenuEntry: function(col){
			var id = col.id,
				div, checkId, checkbox;

			if(col.hidden){
				// Hidden state is true; hide the column.
				this._hideColumn(id);
			}

			// Allow cols to opt out of the hider (e.g. for selector column).
			if(col.unhidable){ return; }

			// Create the checkbox and label for each column selector.
			div = put("div.dgrid-hider-menu-row");
			checkId = this.domNode.id + "-hider-menu-check-" + id;

			this._columnHiderCheckboxes[id] = checkbox = put(div, "input#" + checkId +
					".dgrid-hider-menu-check.hider-menu-check-" + id + "[type=checkbox]");
			put(div, "label.dgrid-hider-menu-label.hider-menu-label" + id +
				"[" + forAttr + "=" + checkId + "]", col.label || col.field || "");

			put(this.hiderMenuNode, div);

			if(!col.hidden){
				// Hidden state is false; checkbox should be initially checked.
				// (Need to do this after adding to DOM to avoid IE6 clobbering it.)
				checkbox.checked = true;
			}
		},

		renderHeader: function(){
			var grid = this,
				hiderMenuNode = this.hiderMenuNode,
				hiderToggleNode = this.hiderToggleNode,
				id;

			function stopPropagation(event){
				event.stopPropagation();
			}

			this.inherited(arguments);

			if(!hiderMenuNode){ // first run
				// Assume that if this plugin is used, then columns are hidable.
				// Create the toggle node.
				hiderToggleNode = this.hiderToggleNode =
					put(this.headerScrollNode, "button.ui-icon.dgrid-hider-toggle[type=button]");

				this._listeners.push(listen(hiderToggleNode, "click", function(e){
					grid._toggleColumnHiderMenu(e);
				}));

				// Create the column list, with checkboxes.
				hiderMenuNode = this.hiderMenuNode =
					put("div#dgrid-hider-menu-" + this.id +
						".dgrid-hider-menu[role=dialog][aria-label=" + this.i18nColumnHider.popupLabel + "]");

				this._listeners.push(listen(hiderMenuNode, "keyup", function (e) {
					var charOrCode = e.charCode || e.keyCode;
					if(charOrCode === /*ESCAPE*/ 27){
						grid._toggleColumnHiderMenu(e);
						hiderToggleNode.focus();
					}
				}));

				// Make sure our menu is initially hidden, then attach to the document.
				hiderMenuNode.style.display = "none";
				put(this.domNode, hiderMenuNode);

				// Hook up delegated listener for modifications to checkboxes.
				this._listeners.push(listen(hiderMenuNode,
						".dgrid-hider-menu-check:" + (hasIE < 9 || hasIEQuirks ? "click" : "change"),
					function(e){
						grid._updateColumnHiddenState(
							getColumnIdFromCheckbox(e.target, grid), !e.target.checked);
					}
				));

				// Stop click events from propagating from menu or trigger nodes,
				// so that we can simply track body clicks for hide without
				// having to drill-up to check.
				this._listeners.push(
					listen(hiderMenuNode, "mousedown", stopPropagation),
					listen(hiderToggleNode, "mousedown", stopPropagation)
				);

				// Hook up top-level mousedown listener if it hasn't been yet.
				if(!bodyListener){
					bodyListener = listen.pausable(document, "mousedown", function(e){
						// If an event reaches this listener, the menu is open,
						// but a click occurred outside, so close the dropdown.
						activeGrid && activeGrid._toggleColumnHiderMenu(e);
					});
					bodyListener.pause(); // pause initially; will resume when menu opens
				}
			}else{ // subsequent run
				// Remove active rules, and clear out the menu (to be repopulated).
				for(id in this._columnHiderRules){
					this._columnHiderRules[id].remove();
				}
				hiderMenuNode.innerHTML = "";
			}

			this._columnHiderCheckboxes = {};
			this._columnHiderRules = {};

			// Populate menu with checkboxes/labels based on current columns.
			this._renderHiderMenuEntries();
		},

		destroy: function(){
			this.inherited(arguments);
			// Remove any remaining rules applied to hidden columns.
			for(var id in this._columnHiderRules){
				this._columnHiderRules[id].remove();
			}
		},

		isColumnHidden: function(id){
			// summary:
			//		Convenience method to determine current hidden state of a column
			return !!this._columnHiderRules[id];
		},

		_toggleColumnHiderMenu: function(){
			var hidden = this._hiderMenuOpened, // reflects hidden state after toggle
				hiderMenuNode = this.hiderMenuNode,
				domNode = this.domNode,
				firstCheckbox;

			// Show or hide the hider menu
			hiderMenuNode.style.display = (hidden ? "none" : "");

			// Adjust height of menu
			if (hidden) {
				// Clear the set size
				hiderMenuNode.style.height = "";
			} else {
				// Adjust height of the menu if necessary
				// Why 12? Based on menu default paddings and border, we need
				// to adjust to be 12 pixels shorter. Given the infrequency of
				// this style changing, we're assuming it will remain this
				// static value of 12 for now, to avoid pulling in any sort of
				// computed styles.
				if (hiderMenuNode.offsetHeight > domNode.offsetHeight - 12) {
					hiderMenuNode.style.height = (domNode.offsetHeight - 12) + "px";
				}
				// focus on the first checkbox
				(firstCheckbox = this._columnHiderFirstCheckbox) && firstCheckbox.focus();
			}

			// Pause or resume the listener for clicks outside the menu
			bodyListener[hidden ? "pause" : "resume"]();

			// Update activeGrid appropriately
			activeGrid = hidden ? null : this;

			// Toggle the instance property
			this._hiderMenuOpened = !hidden;
		},

		_hideColumn: function(id){
			// summary:
			//		Hides the column indicated by the given id.

			// Use miscUtil function directly, since we clean these up ourselves anyway
			var selectorPrefix = "#" + miscUtil.escapeCssIdentifier(this.domNode.id) + " .dgrid-column-",
				tableRule; // used in IE8 code path

			if (this._columnHiderRules[id]) {
				return;
			}

			this._columnHiderRules[id] =
				miscUtil.addCssRule(selectorPrefix + id, "display: none;");

			if(has("ie") === 8 && !has("quirks")){
				tableRule = miscUtil.addCssRule(".dgrid-row-table", "display: inline-table;");

				window.setTimeout(function(){
					tableRule.remove();
				}, 0);
			}
		},

		_updateColumnHiddenState: function(id, hidden){
			// summary:
			//		Performs internal work for toggleColumnHiddenState; see the public
			//		method for more information.

			if(!hidden){
				this._columnHiderRules[id] && this._columnHiderRules[id].remove();
				delete this._columnHiderRules[id];
			}else{
				this._hideColumn(id);
			}

			// Update hidden state in actual column definition,
			// in case columns are re-rendered.
			this.columns[id].hidden = hidden;

			// Emit event to notify of column state change.
			listen.emit(this.domNode, "dgrid-columnstatechange", {
				grid: this,
				column: this.columns[id],
				hidden: hidden,
				bubbles: true
			});

			// Adjust the size of the header.
			this.resize();
		},

		toggleColumnHiddenState: function(id, hidden){
			// summary:
			//		Shows or hides the column with the given id.
			// id: String
			//		ID of column to show/hide.
			// hide: Boolean?
			//		If specified, explicitly sets the hidden state of the specified
			//		column.  If unspecified, toggles the column from the current state.

			if(typeof hidden === "undefined"){ hidden = !this._columnHiderRules[id]; }
			this._updateColumnHiddenState(id, hidden);

			// Since this can be called directly, re-sync the appropriate checkbox.
			this._columnHiderCheckboxes[id].checked = !hidden;
		}
	});
});
<commit_msg>ColumnHider: break out column-showing logic to _showColumn<commit_after>define(["dojo/_base/declare", "dojo/has", "dojo/on", "../util/misc", "put-selector/put", "dojo/i18n!./nls/columnHider", "xstyle/css!../css/extensions/ColumnHider.css"],
function(declare, has, listen, miscUtil, put, i18n){
/*
 *	Column Hider plugin for dgrid
 *	Originally contributed by TRT 2011-09-28
 *
 *	A dGrid plugin that attaches a menu to a dgrid, along with a way of opening it,
 *	that will allow you to show and hide columns.  A few caveats:
 *
 *	1. Menu placement is entirely based on CSS definitions.
 *	2. If you want columns initially hidden, you must add "hidden: true" to your
 *		column definition.
 *	3. This implementation does NOT support ColumnSet, and has not been tested
 *		with multi-subrow records.
 *	4. Column show/hide is controlled via straight up HTML checkboxes.  If you
 *		are looking for something more fancy, you'll probably need to use this
 *		definition as a template to write your own plugin.
 *
 */

	var activeGrid, // references grid for which the menu is currently open
		bodyListener, // references pausable event handler for body mousedown
		// Need to handle old IE specially for checkbox listener and for attribute.
		hasIE = has("ie"),
		hasIEQuirks = hasIE && has("quirks"),
		forAttr = hasIE < 8 || hasIEQuirks ? "htmlFor" : "for";

	function getColumnIdFromCheckbox(cb, grid){
		// Given one of the checkboxes from the hider menu,
		// return the id of the corresponding column.
		// (e.g. gridIDhere-hider-menu-check-colIDhere -> colIDhere)
		return cb.id.substr(grid.id.length + 18);
	}

	return declare(null, {
		// hiderMenuNode: DOMNode
		//		The node for the menu to show/hide columns.
		hiderMenuNode: null,

		// hiderToggleNode: DOMNode
		//		The node for the toggler to open the menu.
		hiderToggleNode: null,

		// i18nColumnHider: Object
		//		This object contains all of the internationalized strings for
		//		the ColumnHider extension as key/value pairs.
		i18nColumnHider: i18n,

		// _hiderMenuOpened: Boolean
		//		Records the current open/closed state of the menu.
		_hiderMenuOpened: false,

		// _columnHiderRules: Object
		//		Hash containing handles returned from addCssRule.
		_columnHiderRules: null,

		// _columnHiderCheckboxes: Object
		//		Hash containing checkboxes generated for menu items.
		_columnHiderCheckboxes: null,

		_renderHiderMenuEntries: function(){
			// summary:
			//		Iterates over subRows for the sake of adding items to the
			//		column hider menu.

			var subRows = this.subRows,
				first = true,
				srLength, cLength, sr, c, checkbox;

			delete this._columnHiderFirstCheckbox;

			for(sr = 0, srLength = subRows.length; sr < srLength; sr++){
				for(c = 0, cLength = subRows[sr].length; c < cLength; c++){
					this._renderHiderMenuEntry(subRows[sr][c]);
					if(first){
						first = false;
						this._columnHiderFirstCheckbox =
							this._columnHiderCheckboxes[subRows[sr][c].id];
					}
				}
			}
		},

		_renderHiderMenuEntry: function(col){
			var id = col.id,
				div, checkId, checkbox;

			if(col.hidden){
				// Hidden state is true; hide the column.
				this._hideColumn(id);
			}

			// Allow cols to opt out of the hider (e.g. for selector column).
			if(col.unhidable){ return; }

			// Create the checkbox and label for each column selector.
			div = put("div.dgrid-hider-menu-row");
			checkId = this.domNode.id + "-hider-menu-check-" + id;

			this._columnHiderCheckboxes[id] = checkbox = put(div, "input#" + checkId +
					".dgrid-hider-menu-check.hider-menu-check-" + id + "[type=checkbox]");
			put(div, "label.dgrid-hider-menu-label.hider-menu-label" + id +
				"[" + forAttr + "=" + checkId + "]", col.label || col.field || "");

			put(this.hiderMenuNode, div);

			if(!col.hidden){
				// Hidden state is false; checkbox should be initially checked.
				// (Need to do this after adding to DOM to avoid IE6 clobbering it.)
				checkbox.checked = true;
			}
		},

		renderHeader: function(){
			var grid = this,
				hiderMenuNode = this.hiderMenuNode,
				hiderToggleNode = this.hiderToggleNode,
				id;

			function stopPropagation(event){
				event.stopPropagation();
			}

			this.inherited(arguments);

			if(!hiderMenuNode){ // first run
				// Assume that if this plugin is used, then columns are hidable.
				// Create the toggle node.
				hiderToggleNode = this.hiderToggleNode =
					put(this.headerScrollNode, "button.ui-icon.dgrid-hider-toggle[type=button]");

				this._listeners.push(listen(hiderToggleNode, "click", function(e){
					grid._toggleColumnHiderMenu(e);
				}));

				// Create the column list, with checkboxes.
				hiderMenuNode = this.hiderMenuNode =
					put("div#dgrid-hider-menu-" + this.id +
						".dgrid-hider-menu[role=dialog][aria-label=" + this.i18nColumnHider.popupLabel + "]");

				this._listeners.push(listen(hiderMenuNode, "keyup", function (e) {
					var charOrCode = e.charCode || e.keyCode;
					if(charOrCode === /*ESCAPE*/ 27){
						grid._toggleColumnHiderMenu(e);
						hiderToggleNode.focus();
					}
				}));

				// Make sure our menu is initially hidden, then attach to the document.
				hiderMenuNode.style.display = "none";
				put(this.domNode, hiderMenuNode);

				// Hook up delegated listener for modifications to checkboxes.
				this._listeners.push(listen(hiderMenuNode,
						".dgrid-hider-menu-check:" + (hasIE < 9 || hasIEQuirks ? "click" : "change"),
					function(e){
						grid._updateColumnHiddenState(
							getColumnIdFromCheckbox(e.target, grid), !e.target.checked);
					}
				));

				// Stop click events from propagating from menu or trigger nodes,
				// so that we can simply track body clicks for hide without
				// having to drill-up to check.
				this._listeners.push(
					listen(hiderMenuNode, "mousedown", stopPropagation),
					listen(hiderToggleNode, "mousedown", stopPropagation)
				);

				// Hook up top-level mousedown listener if it hasn't been yet.
				if(!bodyListener){
					bodyListener = listen.pausable(document, "mousedown", function(e){
						// If an event reaches this listener, the menu is open,
						// but a click occurred outside, so close the dropdown.
						activeGrid && activeGrid._toggleColumnHiderMenu(e);
					});
					bodyListener.pause(); // pause initially; will resume when menu opens
				}
			}else{ // subsequent run
				// Remove active rules, and clear out the menu (to be repopulated).
				for(id in this._columnHiderRules){
					this._columnHiderRules[id].remove();
				}
				hiderMenuNode.innerHTML = "";
			}

			this._columnHiderCheckboxes = {};
			this._columnHiderRules = {};

			// Populate menu with checkboxes/labels based on current columns.
			this._renderHiderMenuEntries();
		},

		destroy: function(){
			this.inherited(arguments);
			// Remove any remaining rules applied to hidden columns.
			for(var id in this._columnHiderRules){
				this._columnHiderRules[id].remove();
			}
		},

		isColumnHidden: function(id){
			// summary:
			//		Convenience method to determine current hidden state of a column
			return !!this._columnHiderRules[id];
		},

		_toggleColumnHiderMenu: function(){
			var hidden = this._hiderMenuOpened, // reflects hidden state after toggle
				hiderMenuNode = this.hiderMenuNode,
				domNode = this.domNode,
				firstCheckbox;

			// Show or hide the hider menu
			hiderMenuNode.style.display = (hidden ? "none" : "");

			// Adjust height of menu
			if (hidden) {
				// Clear the set size
				hiderMenuNode.style.height = "";
			} else {
				// Adjust height of the menu if necessary
				// Why 12? Based on menu default paddings and border, we need
				// to adjust to be 12 pixels shorter. Given the infrequency of
				// this style changing, we're assuming it will remain this
				// static value of 12 for now, to avoid pulling in any sort of
				// computed styles.
				if (hiderMenuNode.offsetHeight > domNode.offsetHeight - 12) {
					hiderMenuNode.style.height = (domNode.offsetHeight - 12) + "px";
				}
				// focus on the first checkbox
				(firstCheckbox = this._columnHiderFirstCheckbox) && firstCheckbox.focus();
			}

			// Pause or resume the listener for clicks outside the menu
			bodyListener[hidden ? "pause" : "resume"]();

			// Update activeGrid appropriately
			activeGrid = hidden ? null : this;

			// Toggle the instance property
			this._hiderMenuOpened = !hidden;
		},

		_hideColumn: function(id){
			// summary:
			//		Hides the column indicated by the given id.

			// Use miscUtil function directly, since we clean these up ourselves anyway
			var selectorPrefix = "#" + miscUtil.escapeCssIdentifier(this.domNode.id) + " .dgrid-column-",
				tableRule; // used in IE8 code path

			if (this._columnHiderRules[id]) {
				return;
			}

			this._columnHiderRules[id] =
				miscUtil.addCssRule(selectorPrefix + id, "display: none;");

			if(has("ie") === 8 && !has("quirks")){
				tableRule = miscUtil.addCssRule(".dgrid-row-table", "display: inline-table;");

				window.setTimeout(function(){
					tableRule.remove();
				}, 0);
			}
		},

		_showColumn: function(id){
			// summary:
			//		Shows the column indicated by the given id
			//		(by removing the rule responsible for hiding it).

			if(this._columnHiderRules[id]){
				this._columnHiderRules[id].remove();
				delete this._columnHiderRules[id];
			}
		},

		_updateColumnHiddenState: function(id, hidden){
			// summary:
			//		Performs internal work for toggleColumnHiddenState; see the public
			//		method for more information.

			this[hidden ? '_hideColumn' : '_showColumn'](id);

			// Update hidden state in actual column definition,
			// in case columns are re-rendered.
			this.columns[id].hidden = hidden;

			// Emit event to notify of column state change.
			listen.emit(this.domNode, "dgrid-columnstatechange", {
				grid: this,
				column: this.columns[id],
				hidden: hidden,
				bubbles: true
			});

			// Adjust the size of the header.
			this.resize();
		},

		toggleColumnHiddenState: function(id, hidden){
			// summary:
			//		Shows or hides the column with the given id.
			// id: String
			//		ID of column to show/hide.
			// hide: Boolean?
			//		If specified, explicitly sets the hidden state of the specified
			//		column.  If unspecified, toggles the column from the current state.

			if(typeof hidden === "undefined"){ hidden = !this._columnHiderRules[id]; }
			this._updateColumnHiddenState(id, hidden);

			// Since this can be called directly, re-sync the appropriate checkbox.
			this._columnHiderCheckboxes[id].checked = !hidden;
		}
	});
});
<|endoftext|>


<commit_before>import Backbone from 'backbone';
import { on, off, getElement } from 'utils/mixins';
const FrameView = require('./FrameView');
const $ = Backbone.$;

module.exports = Backbone.View.extend({
  events: {
    mousewheel: 'onMouseWheel'
  },

  initialize(o) {
    _.bindAll(this, 'renderBody', 'onFrameScroll', 'clearOff');
    on(window, 'scroll resize', this.clearOff);
    this.config = o.config || {};
    this.em = this.config.em || {};
    this.ppfx = this.config.pStylePrefix || '';
    this.className = this.config.stylePrefix + 'canvas';
    this.listenTo(this.em, 'change:canvasOffset', this.clearOff);
    this.listenTo(this.em, 'change:zoom', this.onZoomChange);
    this.frame = new FrameView({
      model: this.model.get('frame'),
      config: this.config
    });
  },

  onMouseWheel(ev) {
    ev.preventDefault();

    if (ev.ctrlKey || ev.metaKey) {
      const { em } = this;
      const delta = Math.max(-1, Math.min(1, ev.wheelDelta || -ev.detail));
      const zoom = em.get('zoom');
      em.set('zoom', zoom + delta);
    }
  },

  onZoomChange() {
    this.frame.el.style.transform = `scale(${this.getZoom()})`;
    this.clearOff();
    this.onFrameScroll();
  },

  getZoom() {
    return this.em.get('zoom') / 100;
  },

  /**
   * Checks if the element is visible in the canvas's viewport
   * @param  {HTMLElement}  el
   * @return {Boolean}
   */
  isElInViewport(el) {
    const rect = getElement(el).getBoundingClientRect();
    const frameRect = this.getFrameOffset();
    const rTop = rect.top;
    const rLeft = rect.left;
    return (
      rTop >= 0 &&
      rLeft >= 0 &&
      rTop <= frameRect.height &&
      rLeft <= frameRect.width
    );
  },

  /**
   * Update tools position
   * @private
   */
  onFrameScroll() {
    var u = 'px';
    var body = this.frame.el.contentDocument.body;
    const zoom = this.getZoom();
    this.toolsEl.style.top = '-' + body.scrollTop * zoom + u;
    this.toolsEl.style.left = '-' + body.scrollLeft * zoom + u;
    this.em.trigger('canvasScroll');
  },

  /**
   * Insert scripts into head, it will call renderBody after all scripts loaded or failed
   * @private
   */
  renderScripts() {
    var frame = this.frame;
    var that = this;

    frame.el.onload = () => {
      var scripts = that.config.scripts.slice(0), // clone
        counter = 0;

      function appendScript(scripts) {
        if (scripts.length > 0) {
          var script = document.createElement('script');
          script.type = 'text/javascript';
          script.src = scripts.shift();
          script.onerror = script.onload = appendScript.bind(null, scripts);
          frame.el.contentDocument.head.appendChild(script);
        } else {
          that.renderBody();
        }
      }
      appendScript(scripts);
    };
  },

  /**
   * Render inside frame's body
   * @private
   */
  renderBody() {
    const { config, model } = this;
    const wrap = this.model.get('frame').get('wrapper');
    const em = config.em;

    if (wrap) {
      const Canvas = em.get('Canvas');
      const ppfx = this.ppfx;
      const body = $(Canvas.getBody());
      const head = $(Canvas.getDocument().head);
      const cssc = em.get('CssComposer');
      const conf = em.get('Config');
      let externalStyles = '';

      config.styles.forEach(style => {
        externalStyles += `<link rel="stylesheet" href="${style}"/>`;
      });

      const colorWarn = '#ffca6f';

      // I need all this styles to make the editor work properly
      // Remove `html { height: 100%;}` from the baseCss as it gives jumpings
      // effects (on ENTER) with RTE like CKEditor (maybe some bug there?!?)
      // With `body {height: auto;}` jumps in CKEditor are removed but in
      // Firefox is impossible to drag stuff in empty canvas, so bring back
      // `body {height: 100%;}`.
      // For the moment I give the priority to Firefox as it might be
      // CKEditor's issue
      var frameCss = `
        ${em.config.baseCss || ''}

        .${ppfx}dashed *[data-highlightable] {
          outline: 1px dashed rgba(170,170,170,0.7);
          outline-offset: -2px;
        }

        .${ppfx}comp-selected {
          outline: 3px solid #3b97e3 !important;
          outline-offset: -3px;
        }

        .${ppfx}comp-selected-parent {
          outline: 2px solid ${colorWarn} !important
        }

        .${ppfx}no-select {
          user-select: none;
          -webkit-user-select:none;
          -moz-user-select: none;
        }

        .${ppfx}freezed {
          opacity: 0.5;
          pointer-events: none;
        }

        .${ppfx}no-pointer {
          pointer-events: none;
        }

        .${ppfx}plh-image {
          background: #f5f5f5;
          border: none;
          height: 50px;
          width: 50px;
          display: block;
          outline: 3px solid #ffca6f;
          cursor: pointer;
          outline-offset: -2px
        }

        .${ppfx}grabbing {
          cursor: grabbing;
          cursor: -webkit-grabbing;
        }

        ${conf.canvasCss || ''}
        ${conf.protectedCss || ''}
      `;

      if (externalStyles) {
        head.append(externalStyles);
      }

      body.append('');
      body.append(wrap.render()).append(cssc.render());
      body.append(this.getJsContainer());
      em.trigger('loaded');
      this.frame.el.contentWindow.onscroll = this.onFrameScroll;
      this.frame.udpateOffset();

      // When the iframe is focused the event dispatcher is not the same so
      // I need to delegate all events to the parent document
      const doc = document;
      const fdoc = this.frame.el.contentDocument;

      // Unfortunately just creating `KeyboardEvent(e.type, e)` is not enough,
      // the keyCode/which will be always `0`. Even if it's an old/deprecated
      // property keymaster (and many others) still use it... using `defineProperty`
      // hack seems the only way
      const createCustomEvent = (e, cls) => {
        let oEvent;
        try {
          oEvent = new window[cls](e.type, e);
        } catch (e) {
          oEvent = document.createEvent(cls);
          oEvent.initEvent(e.type, true, true);
        }
        oEvent.keyCodeVal = e.keyCode;
        ['keyCode', 'which'].forEach(prop => {
          Object.defineProperty(oEvent, prop, {
            get() {
              return this.keyCodeVal;
            }
          });
        });
        return oEvent;
      };

      [
        { event: 'keydown keyup', class: 'KeyboardEvent' }
        //{ event: 'mousedown mousemove mouseup', class: 'MouseEvent' },
      ].forEach(obj =>
        obj.event.split(' ').forEach(event => {
          fdoc.addEventListener(event, e =>
            doc.dispatchEvent(createCustomEvent(e, obj.class))
          );
        })
      );
    }
  },

  /**
   * Get the offset of the element
   * @param  {HTMLElement} el
   * @return {Object}
   */
  offset(el) {
    var rect = el.getBoundingClientRect();
    var docBody = el.ownerDocument.body;
    return {
      top: rect.top + docBody.scrollTop,
      left: rect.left + docBody.scrollLeft,
      width: rect.width,
      height: rect.height
    };
  },

  /**
   * Cleare cached offsets
   * @private
   */
  clearOff() {
    this.frmOff = null;
    this.cvsOff = null;
  },

  /**
   * Return frame offset
   * @return {Object}
   * @private
   */
  getFrameOffset(force = 0) {
    if (!this.frmOff || force) this.frmOff = this.offset(this.frame.el);
    return this.frmOff;
  },

  /**
   * Return canvas offset
   * @return {Object}
   * @private
   */
  getCanvasOffset() {
    if (!this.cvsOff) this.cvsOff = this.offset(this.el);
    return this.cvsOff;
  },

  /**
   * Returns element's data info
   * @param {HTMLElement} el
   * @return {Object}
   * @private
   */
  getElementPos(el, opts) {
    const zoom = this.getZoom();
    var opt = opts || {};
    var frmOff = this.getFrameOffset();
    var cvsOff = this.getCanvasOffset();
    var eo = this.offset(el);

    var frmTop = opt.avoidFrameOffset ? 0 : frmOff.top;
    var frmLeft = opt.avoidFrameOffset ? 0 : frmOff.left;

    const top = eo.top * zoom + frmTop - cvsOff.top;
    const left = eo.left * zoom + frmLeft - cvsOff.left;
    const height = eo.height * zoom;
    const width = eo.width * zoom;

    return { top, left, height, width };
  },

  /**
   * Returns position data of the canvas element
   * @return {Object} obj Position object
   * @private
   */
  getPosition() {
    const doc = this.frame.el.contentDocument;
    if (!doc) return;
    const bEl = doc.body;
    const fo = this.getFrameOffset();
    const co = this.getCanvasOffset();
    return {
      top: fo.top + bEl.scrollTop - co.top,
      left: fo.left + bEl.scrollLeft - co.left
    };
  },

  /**
   * Update javascript of a specific component passed by its View
   * @param {View} view Component's View
   * @private
   */
  updateScript(view) {
    if (!view.scriptContainer) {
      view.scriptContainer = $('
');
      this.getJsContainer().appendChild(view.scriptContainer.get(0));
    }

    const model = view.model;
    const id = model.getId();
    view.el.id = id;
    view.scriptContainer.html('');
    // In editor, I make use of setTimeout as during the append process of elements
    // those will not be available immediately, therefore 'item' variable
    const script = document.createElement('script');
    script.innerHTML = `
        setTimeout(function() {
          var item = document.getElementById('${id}');
          if (!item) return;
          (function(){
            ${model.getScriptString()};
          }.bind(item))()
        }, 1);`;
    // #873
    // Adding setTimeout will make js components work on init of the editor
    setTimeout(() => view.scriptContainer.get(0).appendChild(script), 0);
  },

  /**
   * Get javascript container
   * @private
   */
  getJsContainer() {
    if (!this.jsContainer) {
      this.jsContainer = $(`<div class="${this.ppfx}js-cont">`).get(0);
    }
    return this.jsContainer;
  },

  render() {
    this.wrapper = this.model.get('wrapper');

    if (this.wrapper && typeof this.wrapper.render == 'function') {
      this.model.get('frame').set('wrapper', this.wrapper);
      this.$el.append(this.frame.render().el);
      var frame = this.frame;
      if (this.config.scripts.length === 0) {
        frame.el.onload = this.renderBody;
      } else {
        this.renderScripts(); // will call renderBody later
      }
    }
    var ppfx = this.ppfx;
    this.$el.append(`

    `);
    const el = this.el;
    const toolsEl = el.querySelector(`#${ppfx}tools`);
    this.hlEl = el.querySelector(`.${ppfx}highlighter`);
    this.badgeEl = el.querySelector(`.${ppfx}badge`);
    this.placerEl = el.querySelector(`.${ppfx}placeholder`);
    this.ghostEl = el.querySelector(`.${ppfx}ghost`);
    this.toolbarEl = el.querySelector(`.${ppfx}toolbar`);
    this.resizerEl = el.querySelector(`.${ppfx}resizer`);
    this.offsetEl = el.querySelector(`.${ppfx}offset-v`);
    this.fixedOffsetEl = el.querySelector(`.${ppfx}offset-fixed-v`);
    this.toolsEl = toolsEl;
    this.el.className = this.className;
    return this;
  }
});
<commit_msg>Propagate wheel event<commit_after>import Backbone from 'backbone';
import { on, off, getElement } from 'utils/mixins';
const FrameView = require('./FrameView');
const $ = Backbone.$;

module.exports = Backbone.View.extend({
  events: {
    wheel: 'onWheel'
  },

  initialize(o) {
    _.bindAll(this, 'renderBody', 'onFrameScroll', 'clearOff');
    on(window, 'scroll resize', this.clearOff);
    this.config = o.config || {};
    this.em = this.config.em || {};
    this.ppfx = this.config.pStylePrefix || '';
    this.className = this.config.stylePrefix + 'canvas';
    this.listenTo(this.em, 'change:canvasOffset', this.clearOff);
    this.listenTo(this.em, 'change:zoom', this.onZoomChange);
    this.frame = new FrameView({
      model: this.model.get('frame'),
      config: this.config
    });
  },

  onWheel(ev) {
    if (ev.ctrlKey || ev.metaKey) {
      ev.preventDefault();
      ev._parentEvent && ev._parentEvent.preventDefault();
      const { em } = this;
      const delta = Math.max(-1, Math.min(1, ev.wheelDelta || -ev.detail));
      const zoom = em.get('zoom');
      em.set('zoom', zoom + delta * 2);
    }
  },

  onZoomChange() {
    this.frame.el.style.transform = `scale(${this.getZoom()})`;
    this.clearOff();
    this.onFrameScroll();
  },

  getZoom() {
    return this.em.get('zoom') / 100;
  },

  /**
   * Checks if the element is visible in the canvas's viewport
   * @param  {HTMLElement}  el
   * @return {Boolean}
   */
  isElInViewport(el) {
    const rect = getElement(el).getBoundingClientRect();
    const frameRect = this.getFrameOffset();
    const rTop = rect.top;
    const rLeft = rect.left;
    return (
      rTop >= 0 &&
      rLeft >= 0 &&
      rTop <= frameRect.height &&
      rLeft <= frameRect.width
    );
  },

  /**
   * Update tools position
   * @private
   */
  onFrameScroll() {
    var u = 'px';
    var body = this.frame.el.contentDocument.body;
    const zoom = this.getZoom();
    this.toolsEl.style.top = '-' + body.scrollTop * zoom + u;
    this.toolsEl.style.left = '-' + body.scrollLeft * zoom + u;
    this.em.trigger('canvasScroll');
  },

  /**
   * Insert scripts into head, it will call renderBody after all scripts loaded or failed
   * @private
   */
  renderScripts() {
    var frame = this.frame;
    var that = this;

    frame.el.onload = () => {
      var scripts = that.config.scripts.slice(0), // clone
        counter = 0;

      function appendScript(scripts) {
        if (scripts.length > 0) {
          var script = document.createElement('script');
          script.type = 'text/javascript';
          script.src = scripts.shift();
          script.onerror = script.onload = appendScript.bind(null, scripts);
          frame.el.contentDocument.head.appendChild(script);
        } else {
          that.renderBody();
        }
      }
      appendScript(scripts);
    };
  },

  /**
   * Render inside frame's body
   * @private
   */
  renderBody() {
    const { config, model } = this;
    const wrap = this.model.get('frame').get('wrapper');
    const em = config.em;

    if (wrap) {
      const Canvas = em.get('Canvas');
      const ppfx = this.ppfx;
      const body = $(Canvas.getBody());
      const head = $(Canvas.getDocument().head);
      const cssc = em.get('CssComposer');
      const conf = em.get('Config');
      let externalStyles = '';

      config.styles.forEach(style => {
        externalStyles += `<link rel="stylesheet" href="${style}"/>`;
      });

      const colorWarn = '#ffca6f';

      // I need all this styles to make the editor work properly
      // Remove `html { height: 100%;}` from the baseCss as it gives jumpings
      // effects (on ENTER) with RTE like CKEditor (maybe some bug there?!?)
      // With `body {height: auto;}` jumps in CKEditor are removed but in
      // Firefox is impossible to drag stuff in empty canvas, so bring back
      // `body {height: 100%;}`.
      // For the moment I give the priority to Firefox as it might be
      // CKEditor's issue
      var frameCss = `
        ${em.config.baseCss || ''}

        .${ppfx}dashed *[data-highlightable] {
          outline: 1px dashed rgba(170,170,170,0.7);
          outline-offset: -2px;
        }

        .${ppfx}comp-selected {
          outline: 3px solid #3b97e3 !important;
          outline-offset: -3px;
        }

        .${ppfx}comp-selected-parent {
          outline: 2px solid ${colorWarn} !important
        }

        .${ppfx}no-select {
          user-select: none;
          -webkit-user-select:none;
          -moz-user-select: none;
        }

        .${ppfx}freezed {
          opacity: 0.5;
          pointer-events: none;
        }

        .${ppfx}no-pointer {
          pointer-events: none;
        }

        .${ppfx}plh-image {
          background: #f5f5f5;
          border: none;
          height: 50px;
          width: 50px;
          display: block;
          outline: 3px solid #ffca6f;
          cursor: pointer;
          outline-offset: -2px
        }

        .${ppfx}grabbing {
          cursor: grabbing;
          cursor: -webkit-grabbing;
        }

        ${conf.canvasCss || ''}
        ${conf.protectedCss || ''}
      `;

      if (externalStyles) {
        head.append(externalStyles);
      }

      body.append('');
      body.append(wrap.render()).append(cssc.render());
      body.append(this.getJsContainer());
      em.trigger('loaded');
      this.frame.el.contentWindow.onscroll = this.onFrameScroll;
      this.frame.udpateOffset();

      // When the iframe is focused the event dispatcher is not the same so
      // I need to delegate all events to the parent document
      const doc = document;
      const fdoc = this.frame.el.contentDocument;

      // Unfortunately just creating `KeyboardEvent(e.type, e)` is not enough,
      // the keyCode/which will be always `0`. Even if it's an old/deprecated
      // property keymaster (and many others) still use it... using `defineProperty`
      // hack seems the only way
      const createCustomEvent = (e, cls) => {
        let oEvent;
        try {
          oEvent = new window[cls](e.type, e);
        } catch (e) {
          oEvent = document.createEvent(cls);
          oEvent.initEvent(e.type, true, true);
        }
        oEvent.keyCodeVal = e.keyCode;
        oEvent._parentEvent = e;
        ['keyCode', 'which'].forEach(prop => {
          Object.defineProperty(oEvent, prop, {
            get() {
              return this.keyCodeVal;
            }
          });
        });
        return oEvent;
      };

      [
        { event: 'keydown keyup', class: 'KeyboardEvent' },
        { event: 'wheel', class: 'WheelEvent' }
      ].forEach(obj =>
        obj.event.split(' ').forEach(event => {
          fdoc.addEventListener(event, e =>
            this.el.dispatchEvent(createCustomEvent(e, obj.class))
          );
        })
      );
    }
  },

  /**
   * Get the offset of the element
   * @param  {HTMLElement} el
   * @return {Object}
   */
  offset(el) {
    var rect = el.getBoundingClientRect();
    var docBody = el.ownerDocument.body;
    return {
      top: rect.top + docBody.scrollTop,
      left: rect.left + docBody.scrollLeft,
      width: rect.width,
      height: rect.height
    };
  },

  /**
   * Cleare cached offsets
   * @private
   */
  clearOff() {
    this.frmOff = null;
    this.cvsOff = null;
  },

  /**
   * Return frame offset
   * @return {Object}
   * @private
   */
  getFrameOffset(force = 0) {
    if (!this.frmOff || force) this.frmOff = this.offset(this.frame.el);
    return this.frmOff;
  },

  /**
   * Return canvas offset
   * @return {Object}
   * @private
   */
  getCanvasOffset() {
    if (!this.cvsOff) this.cvsOff = this.offset(this.el);
    return this.cvsOff;
  },

  /**
   * Returns element's data info
   * @param {HTMLElement} el
   * @return {Object}
   * @private
   */
  getElementPos(el, opts) {
    const zoom = this.getZoom();
    var opt = opts || {};
    var frmOff = this.getFrameOffset();
    var cvsOff = this.getCanvasOffset();
    var eo = this.offset(el);

    var frmTop = opt.avoidFrameOffset ? 0 : frmOff.top;
    var frmLeft = opt.avoidFrameOffset ? 0 : frmOff.left;

    const top = eo.top * zoom + frmTop - cvsOff.top;
    const left = eo.left * zoom + frmLeft - cvsOff.left;
    const height = eo.height * zoom;
    const width = eo.width * zoom;

    return { top, left, height, width };
  },

  /**
   * Returns position data of the canvas element
   * @return {Object} obj Position object
   * @private
   */
  getPosition() {
    const doc = this.frame.el.contentDocument;
    if (!doc) return;
    const bEl = doc.body;
    const fo = this.getFrameOffset();
    const co = this.getCanvasOffset();
    return {
      top: fo.top + bEl.scrollTop - co.top,
      left: fo.left + bEl.scrollLeft - co.left
    };
  },

  /**
   * Update javascript of a specific component passed by its View
   * @param {View} view Component's View
   * @private
   */
  updateScript(view) {
    if (!view.scriptContainer) {
      view.scriptContainer = $('
');
      this.getJsContainer().appendChild(view.scriptContainer.get(0));
    }

    const model = view.model;
    const id = model.getId();
    view.el.id = id;
    view.scriptContainer.html('');
    // In editor, I make use of setTimeout as during the append process of elements
    // those will not be available immediately, therefore 'item' variable
    const script = document.createElement('script');
    script.innerHTML = `
        setTimeout(function() {
          var item = document.getElementById('${id}');
          if (!item) return;
          (function(){
            ${model.getScriptString()};
          }.bind(item))()
        }, 1);`;
    // #873
    // Adding setTimeout will make js components work on init of the editor
    setTimeout(() => view.scriptContainer.get(0).appendChild(script), 0);
  },

  /**
   * Get javascript container
   * @private
   */
  getJsContainer() {
    if (!this.jsContainer) {
      this.jsContainer = $(`<div class="${this.ppfx}js-cont">`).get(0);
    }
    return this.jsContainer;
  },

  render() {
    this.wrapper = this.model.get('wrapper');

    if (this.wrapper && typeof this.wrapper.render == 'function') {
      this.model.get('frame').set('wrapper', this.wrapper);
      this.$el.append(this.frame.render().el);
      var frame = this.frame;
      if (this.config.scripts.length === 0) {
        frame.el.onload = this.renderBody;
      } else {
        this.renderScripts(); // will call renderBody later
      }
    }
    var ppfx = this.ppfx;
    this.$el.append(`

    `);
    const el = this.el;
    const toolsEl = el.querySelector(`#${ppfx}tools`);
    this.hlEl = el.querySelector(`.${ppfx}highlighter`);
    this.badgeEl = el.querySelector(`.${ppfx}badge`);
    this.placerEl = el.querySelector(`.${ppfx}placeholder`);
    this.ghostEl = el.querySelector(`.${ppfx}ghost`);
    this.toolbarEl = el.querySelector(`.${ppfx}toolbar`);
    this.resizerEl = el.querySelector(`.${ppfx}resizer`);
    this.offsetEl = el.querySelector(`.${ppfx}offset-v`);
    this.fixedOffsetEl = el.querySelector(`.${ppfx}offset-fixed-v`);
    this.toolsEl = toolsEl;
    this.el.className = this.className;
    return this;
  }
});
<|endoftext|>


<commit_before>import React from 'react'
import {
  StyleSheet,
  TouchableHighlight,
  View,
  Text,
  Image
} from 'react-native'

export default ({ setInterest, interest, chosenInterests }) => {

  const ActiveClass = chosenInterests.indexOf(interest.title) > -1 ?
  { opacity: 0.8 } :
  { opacity: 0.4 }

  console.log(chosenInterests)
  return (
    <TouchableHighlight
      style={styles.row}
      onPress={() => {
        setInterest(interest.title)
      }}
    >

      <View>
        <Image
          style={[ styles.tileImage, ActiveClass ]}
          source={{ uri: interest.picUrl }}
        />
        <Text style={styles.subTitle}>{interest.title}</Text>
      </View>

    </TouchableHighlight>
  )
}

const styles = StyleSheet.create({
  tileImage: {
    height: 150
  },
  subTitle: {
    color: '#fff',
    position: 'absolute',
    bottom: 10,
    left: 10,
    backgroundColor: 'transparent'
  },
  row: {
    width: 180,
    margin: 5,
    height: 150,
    backgroundColor: '#257AC4'
  }
})
<commit_msg>Dimensions module gets the width and height of screen, can use for tile width<commit_after>import React from 'react'
import {
  StyleSheet,
  TouchableHighlight,
  View,
  Text,
  Image
} from 'react-native'
import Dimensions from 'Dimensions'
const { width } = Dimensions.get('window')

export default ({ setInterest, interest, chosenInterests }) => {

  const ActiveClass = chosenInterests.indexOf(interest.title) > -1 ?
  { opacity: 0.8 } :
  { opacity: 0.4 }

  console.log(chosenInterests)
  return (
    <TouchableHighlight
      style={styles.row}
      onPress={() => {
        setInterest(interest.title)
      }}
    >

      <View>
        <Image
          style={[ styles.tileImage, ActiveClass ]}
          source={{ uri: interest.picUrl }}
        />
        <Text style={styles.subTitle}>{interest.title}</Text>
      </View>

    </TouchableHighlight>
  )
}

const styles = StyleSheet.create({
  tileImage: {
    height: 150
  },
  subTitle: {
    color: '#fff',
    position: 'absolute',
    bottom: 10,
    left: 10,
    backgroundColor: 'transparent'
  },
  row: {
    width: width / 2.2,
    margin: 5,
    height: 150,
    backgroundColor: '#257AC4'
  }
})
<|endoftext|>


<commit_before>/* eslint no-console: 0 */

"use strict";

var colors = require("colors");
var getBrowsers = require("get-saucelabs-browsers");
var http = require("https");
var url = require("url");

var username = process.env.SAUCE_USERNAME;
var accessKey = process.env.SAUCE_ACCESS_KEY;
var tunnelId = process.env.SAUCE_TUNNEL || process.env.TRAVIS_JOB_NUMBER;
var build = process.env.TRAVIS_BUILD_NUMBER || null;
var testUrl = process.argv[2];
if (!username || !accessKey) {
  console.log("Missing username and access key for SauceLabs. Please provide ".red +
              "the %s and %s environment variables.".red,
              "SAUCE_USERNAME".underline,
              "SAUCE_ACCESS_KEY".underline);
  process.exit(1);
}

if (!tunnelId) {
  console.log("Missing tunnel identifier. Please start Sauce Connect and provide ".red +
              "the %s (or %s) environment variable.".red,
              "SAUCE_TUNNEL".underline,
              "TRAVIS_JOB_NUMBER".underline);
  process.exit(1);
}

if (!testUrl) {
  console.log("Missing test URL. Please provide it as the first argument, such as:\n".red +
              "    $ node bin/sauce-jasmine.js %s",
              "http://localhost:9999/test/SpecRunner.html".underline);
  process.exit(1);
}

function handleError(err) {
  if (!err) return;
  console.log("Unexpected error occured:".red);
  console.log.apply(console, arguments);
  process.exit(1);
}

function request(options, callback) {
  var req = http.request(options, function (res) {
    if (res.statusCode !== 200) {
      handleError("Unexpected status code %s when requesting %s",
                  colors.underline(res.statusCode),
                  options.path.underline);
    }

    var body = "";
    res.on("data", function (chunk) {
      body += chunk.toString();
    });

    res.on("end", function () {
      callback(JSON.parse(body));
    });
  });

  req.on("error", handleError);
  req.write(options.body);
  req.end();
}

var browserFilter = [
  "internet explorer/9..latest",
  "microsoftedge/13..latest",
  "firefox/31..latest/linux",
  "chrome/31..latest/linux",
  "safari/5..latest",
  "opera/11..latest",
  "android/4.0..latest",
  "iphone/5.1..latest"
];

getBrowsers(browserFilter, function (err, result) {
  handleError(err);

  startBrowsers(result);
});

function startBrowsers(browsers) {
  var sauceBrowsers = formatBrowsers(browsers);

  var body = {
    platforms: sauceBrowsers,
    url: testUrl,
    framework: "jasmine",
    tunnelIdentifier: tunnelId,
    build: build,
    captureHtml: true
  };

  console.log("Requesting %s browser tests…".yellow, sauceBrowsers.length);

  var options = url.parse("https://saucelabs.com/rest/v1/" + username + "/js-tests");
  options.method = "POST";
  options.auth = username + ":" + accessKey;
  options.body = JSON.stringify(body);
  request(options, function (res) {
    var testIds = res["js tests"];
    startedTests = testIds.length;
    console.log("Queued %s browser tests…".yellow, startedTests);

    pollTestStatus(testIds);
  });
}

function formatBrowsers(browsers) {
  return browsers.filter(function (browser) {
    // One entry seems to always be undefined, so we filter it out.
    return browser.browserName !== undefined;
  }).map(function (browser) {
    return [
      browser.platform,
      browser.browserName,
      browser.version
    ];
  });
}

var startedTests = 0;
var failedTests = 0;
var passedTests = 0;
function pollTestStatus(testIds) {
  var body = {
    "js tests": testIds
  };

  var options = url.parse("https://saucelabs.com/rest/v1/" + username + "/js-tests/status");
  options.method = "POST";
  options.auth = username + ":" + accessKey;
  options.body = JSON.stringify(body);
  request(options, function (res) {
    var test = res["js tests"];
    var remainingTestIds = [];

    test.forEach(function (test) {
      if (!("result" in test)) {
        // No results are available yet, so we still need to wait for it.
        remainingTestIds.push(test.id);
        return;
      }

      if (test.result.passed) {
        // Test passed succesfully. No need to worry about it any more.
        console.log("Browser %s passed!".green, test.platform.join(" "));
        passedTests++;
        return;
      }

      console.log("Browser %s failed!".red, test.platform.join(" "));
      failedTests++;
      printFailedSuites(test.result.suites, "");
    });

    if (remainingTestIds.length === 0) {
      console.log("Started: %s Passed: %s Failed: %s".yellow,
                  startedTests,
                  passedTests,
                  failedTests);

      process.exit(failedTests > 0 ? 1 : 0);
    } else {
      console.log("%s browser remaining…".gray, remainingTestIds.length);
    }

    setTimeout(pollTestStatus.bind({}, remainingTestIds), 3000);
  });
}

function printFailedSuites(suites, prefix) {
  // We do not always get a proper result back, e.g. when the browser crashes
  if (!suites) return;

  suites.forEach(function (suite) {
    var pref = prefix + suite.description;

    suite.specs.forEach(function (spec) {
      if (spec.passed) return;

      printFailedSpec(spec, pref);
    });

    printFailedSuites(suite.suites, pref);
  });
}

function printFailedSpec(spec, prefix) {
  console.log("  "+"%s %s:".red.underline, prefix, spec.description);

  spec.failures.forEach(function (failure, index) {
    console.log("  %s) %s", index+1, failure.message.bold);
    console.log("    %s", failure.trace.stack.gray);
  });
}
/*
printFailedSuites([
          {
            "specs": [],
            "duration": 33,
            "passed": false,
            "failedExpectations": [],
            "durationSec": 0.033,
            "description": "tus",
            "suites": [
              {
                "specs": [
                  {
                    "passedCount": 1,
                    "failures": [],
                    "skipped": false,
                    "description": "should throw if no error handler is available",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.006,
                    "totalCount": 1,
                    "passed": true,
                    "duration": 6
                  },
                  {
                    "passedCount": 17,
                    "failures": [
                      {
                        "type": "expect",
                        "message": "Expected '/uploads' to be '/uplods'.",
                        "expected": "/uplods",
                        "passed": false,
                        "matcherName": "toBe",
                        "trace": {
                          "stack": "Error: Expected '/uploads' to be '/uplods'.\n    at stack (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1577:17)\n    at buildExpectationResult (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1547:14)\n    at Spec.Env.expectationResultFactory (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:638:18)\n    at Spec.addExpectationResult (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:330:34)\n    at Expectation.addExpectationResult (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:588:21)\n    at Expectation.toBe (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1501:12)\n    at Object.<anonymous> (http://localhost:9999/test/spec/upload.js:83:23)\n    at attemptAsync (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1916:24)\n    at QueueRunner.run (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1871:9)\n    at QueueRunner.execute (http://localhost:9999/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1859:10)"
                        }
                      }
                    ],
                    "skipped": false,
                    "description": "should upload a file",
                    "failedCount": 1,
                    "pendingReason": "",
                    "durationSec": 0.016,
                    "totalCount": 18,
                    "passed": false,
                    "duration": 16
                  },
                  {
                    "passedCount": 12,
                    "failures": [],
                    "skipped": false,
                    "description": "should resume an upload",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.002,
                    "totalCount": 12,
                    "passed": true,
                    "duration": 2
                  },
                  {
                    "passedCount": 9,
                    "failures": [],
                    "skipped": false,
                    "description": "should create an upload if resuming fails",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.001,
                    "totalCount": 9,
                    "passed": true,
                    "duration": 1
                  },
                  {
                    "passedCount": 21,
                    "failures": [],
                    "skipped": false,
                    "description": "should upload a file in chunks",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.002,
                    "totalCount": 21,
                    "passed": true,
                    "duration": 2
                  },
                  {
                    "passedCount": 6,
                    "failures": [],
                    "skipped": false,
                    "description": "should add the original request to errors",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.001,
                    "totalCount": 6,
                    "passed": true,
                    "duration": 1
                  },
                  {
                    "passedCount": 6,
                    "failures": [],
                    "skipped": false,
                    "description": "should not resume a finished upload",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.001,
                    "totalCount": 6,
                    "passed": true,
                    "duration": 1
                  },
                  {
                    "passedCount": 12,
                    "failures": [],
                    "skipped": false,
                    "description": "should resume an upload from a specified url",
                    "failedCount": 0,
                    "pendingReason": "",
                    "durationSec": 0.001,
                    "totalCount": 12,
                    "passed": true,
                    "duration": 1
                  }
                ],
                "duration": 33,
                "passed": false,
                "failedExpectations": [],
                "durationSec": 0.033,
                "description": "#Upload",
                "suites": [],
                "status": "finished"
              }
            ],
            "status": "finished"
          }
        ]
,"")*/
<commit_msg>Add names to tests<commit_after>/* eslint no-console: 0 */

"use strict";

var colors = require("colors");
var getBrowsers = require("get-saucelabs-browsers");
var http = require("https");
var url = require("url");

var username = process.env.SAUCE_USERNAME;
var accessKey = process.env.SAUCE_ACCESS_KEY;
var tunnelId = process.env.SAUCE_TUNNEL || process.env.TRAVIS_JOB_NUMBER;
var build = process.env.TRAVIS_BUILD_NUMBER || null;
var testUrl = process.argv[2];
if (!username || !accessKey) {
  console.log("Missing username and access key for SauceLabs. Please provide ".red +
              "the %s and %s environment variables.".red,
              "SAUCE_USERNAME".underline,
              "SAUCE_ACCESS_KEY".underline);
  process.exit(1);
}

if (!tunnelId) {
  console.log("Missing tunnel identifier. Please start Sauce Connect and provide ".red +
              "the %s (or %s) environment variable.".red,
              "SAUCE_TUNNEL".underline,
              "TRAVIS_JOB_NUMBER".underline);
  process.exit(1);
}

if (!testUrl) {
  console.log("Missing test URL. Please provide it as the first argument, such as:\n".red +
              "    $ node bin/sauce-jasmine.js %s",
              "http://localhost:9999/test/SpecRunner.html".underline);
  process.exit(1);
}

function handleError(err) {
  if (!err) return;
  console.log("Unexpected error occured:".red);
  console.log.apply(console, arguments);
  process.exit(1);
}

function request(options, callback) {
  var req = http.request(options, function (res) {
    if (res.statusCode !== 200) {
      handleError("Unexpected status code %s when requesting %s",
                  colors.underline(res.statusCode),
                  options.path.underline);
    }

    var body = "";
    res.on("data", function (chunk) {
      body += chunk.toString();
    });

    res.on("end", function () {
      callback(JSON.parse(body));
    });
  });

  req.on("error", handleError);
  req.write(options.body);
  req.end();
}

var browserFilter = [
  "internet explorer/9..latest",
  "microsoftedge/13..latest",
  "firefox/31..latest/linux",
  "chrome/31..latest/linux",
  "safari/5..latest",
  "opera/11..latest",
  "android/4.0..latest",
  "iphone/5.1..latest"
];

getBrowsers(browserFilter, function (err, result) {
  handleError(err);

  startBrowsers(result);
});

function startBrowsers(browsers) {
  var sauceBrowsers = formatBrowsers(browsers);

  var body = {
    platforms: sauceBrowsers,
    url: testUrl,
    framework: "jasmine",
    tunnelIdentifier: tunnelId,
    build: build,
    name: "tus-js-client – Jasmine"
  };

  console.log("Requesting %s browser tests…".yellow, sauceBrowsers.length);

  var options = url.parse("https://saucelabs.com/rest/v1/" + username + "/js-tests");
  options.method = "POST";
  options.auth = username + ":" + accessKey;
  options.body = JSON.stringify(body);
  request(options, function (res) {
    var testIds = res["js tests"];
    startedTests = testIds.length;
    console.log("Queued %s browser tests…".yellow, startedTests);

    pollTestStatus(testIds);
  });
}

function formatBrowsers(browsers) {
  return browsers.filter(function (browser) {
    // One entry seems to always be undefined, so we filter it out.
    return browser.browserName !== undefined;
  }).map(function (browser) {
    return [
      browser.platform,
      browser.browserName,
      browser.version
    ];
  });
}

var startedTests = 0;
var failedTests = 0;
var passedTests = 0;
function pollTestStatus(testIds) {
  var body = {
    "js tests": testIds
  };

  var options = url.parse("https://saucelabs.com/rest/v1/" + username + "/js-tests/status");
  options.method = "POST";
  options.auth = username + ":" + accessKey;
  options.body = JSON.stringify(body);
  request(options, function (res) {
    var test = res["js tests"];
    var remainingTestIds = [];

    test.forEach(function (test) {
      if (!("result" in test)) {
        // No results are available yet, so we still need to wait for it.
        remainingTestIds.push(test.id);
        return;
      }

      if (test.result.passed) {
        // Test passed succesfully. No need to worry about it any more.
        console.log("Browser %s passed!".green, test.platform.join(" "));
        passedTests++;
        return;
      }

      console.log("Browser %s failed!".red, test.platform.join(" "));
      failedTests++;
      printFailedSuites(test.result.suites, "");
    });

    if (remainingTestIds.length === 0) {
      console.log("Started: %s Passed: %s Failed: %s".yellow,
                  startedTests,
                  passedTests,
                  failedTests);

      process.exit(failedTests > 0 ? 1 : 0);
    } else {
      console.log("%s browser remaining…".gray, remainingTestIds.length);
    }

    setTimeout(pollTestStatus.bind({}, remainingTestIds), 3000);
  });
}

function printFailedSuites(suites, prefix) {
  // We do not always get a proper result back, e.g. when the browser crashes
  if (!suites) return;

  suites.forEach(function (suite) {
    var pref = prefix + suite.description;

    suite.specs.forEach(function (spec) {
      if (spec.passed) return;

      printFailedSpec(spec, pref);
    });

    printFailedSuites(suite.suites, pref);
  });
}

function printFailedSpec(spec, prefix) {
  console.log("  "+"%s %s:".red.underline, prefix, spec.description);

  spec.failures.forEach(function (failure, index) {
    console.log("  %s) %s", index+1, failure.message.bold);
    console.log("    %s", failure.trace.stack.gray);
  });
}
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter
var inherits     = require('util').inherits
var ranges       = require('string-range')
var fixRange     = require('level-fix-range')

inherits(SubDB, EventEmitter)

function SubDB (db, prefix, sep) {
  if(!(this instanceof SubDB)) return new SubDB(db, prefix, sep)
  if(!db)     throw new Error('must provide db')
  if(!prefix) throw new Error('must provide prefix')

  this._parent = db
  this._sep = sep || '\xff'
  this._prefix = prefix
  this._root = root(this)
  db.sublevels[prefix] = this
  this.sublevels = {}
  this.methods = {}
  var self = this
  this.hooks = {
    pre: function () {
      return self.pre.apply(self, arguments)
    },
    post: function () {
      return self.post.apply(self, arguments)
    }
  }
}

var SDB = SubDB.prototype

SDB._key = function (key) {
  return this._sep
    + this._prefix
    + this._sep
    + key
}

SDB.sublevel = function (prefix) {
  if(this.sublevels[prefix])
    return this.sublevels[prefix]
  return new SubDB(this, prefix, this._sep)
}

SDB.put = function (key, value, opts, cb) {
  this._root.put(this.prefix(key), value, opts, cb)
//  this._parent.put(this._key(key), value, opts, cb)
}

SDB.get = function (key, opts, cb) {
  this._root.get(this.prefix(key), opts, cb)
//  this._parent.get(this._key(key), opts, cb)
}

SDB.del = function (key, opts, cb) {
  this._root.del(this.prefix(key), opts, cb)
//  this._parent.del(this._key(key), opts, cb)
}

SDB.batch = function (changes, opts, cb) {
  var self = this
  changes.forEach(function (ch) {
    //OH YEAH, WE NEED TO VALIDATE THAT UPDATING THIS KEY/PREFIX IS ALLOWED
    if('string' === typeof ch.prefix) {
      ch.key = ch.prefix + ch.key
    } else
    ch.key = (ch.prefix || self).prefix(ch.key)
    if(ch.prefix) ch.prefix = null
  })
  this._root.batch(changes, opts, cb)
}

SDB.prefix = function (key) {
  return this._parent.prefix() + this._sep + this._prefix + this._sep + (key || '')
}

SDB.keyStream =
SDB.createKeyStream = function (opts) {
  opts = opts || {}
  opts.keys = true
  return this.createReadStream(opts)
}

SDB.valueStream =
SDB.createValueStream = function (opts) {
  opts = opts || {}
  opts.values = true
  return this.createReadStream(opts)
}

SDB.readStream =
SDB.createReadStream = function (opts) {
  opts = opts || {}
  var r = root(this)
  var p = this.prefix()
  //opts.start = p + (opts.start || '')
  //opts.end = p + (opts.end || this._sep)
  opts = ranges.prefix(opts, p)

  return r.createReadStream(opts)
    .on('data', function (d) {
      //mutate the prefix!
      //this doesn't work for createKeyStream admittedly.
      if(d.key)
        d.key = d.key.substring(p.length)
    })
}

SDB.writeStream =
SDB.createWriteStream = function () {
  var r = root(this)
  var p = this.prefix()
  var ws = r.createWriteStream.apply(r, arguments)
  var write = ws.write
  ws.write = function (data) {
    data.key = p + data.key
    return write.call(ws, data)
  }
  return ws
}

SDB.approximateSize = function () {
  var r = root(db)
  return r.approximateSize.apply(r, arguments)
}

function root(db) {
  if(!db._parent) return db
  return root(db._parent)
}

SDB.pre = function (range, hook) {
  if(!hook) hook = range, range = null
  range = ranges.prefix(range, this.prefix(), this._sep)
  var r = root(this._parent)
  var p = this.prefix()
  return r.hooks.pre(fixRange(range), function (ch, add) {
    hook({
      key: ch.key.substring(p.length),
      value: ch.value,
      type: ch.type
    }, function (ch, _p) {
      add(ch, _p || p)
    })
  })
}

SDB.post = function (range, hook) {
  if(!hook) hook = range, range = null
  var r = root(this._parent)
  var p = this.prefix()
  range = ranges.prefix(range, p, this._sep)
  return r.hooks.post(fixRange(range), function (data) {
    hook({key: data.key.substring(p.length), value: data.value, type: data.type})
  })
}

var exports = module.exports = SubDB

<commit_msg>probably remove this in v5<commit_after>var EventEmitter = require('events').EventEmitter
var inherits     = require('util').inherits
var ranges       = require('string-range')
var fixRange     = require('level-fix-range')

inherits(SubDB, EventEmitter)

function SubDB (db, prefix, sep) {
  if(!(this instanceof SubDB)) return new SubDB(db, prefix, sep)
  if(!db)     throw new Error('must provide db')
  if(!prefix) throw new Error('must provide prefix')

  this._parent = db
  this._sep = sep || '\xff'
  this._prefix = prefix
  this._root = root(this)
  db.sublevels[prefix] = this
  this.sublevels = {}
  this.methods = {}
  var self = this
  this.hooks = {
    pre: function () {
      return self.pre.apply(self, arguments)
    },
    post: function () {
      return self.post.apply(self, arguments)
    }
  }
}

var SDB = SubDB.prototype

SDB._key = function (key) {
  return this._sep
    + this._prefix
    + this._sep
    + key
}

SDB.sublevel = function (prefix) {
  if(this.sublevels[prefix])
    return this.sublevels[prefix]
  return new SubDB(this, prefix, this._sep)
}

SDB.put = function (key, value, opts, cb) {
  this._root.put(this.prefix(key), value, opts, cb)
//  this._parent.put(this._key(key), value, opts, cb)
}

SDB.get = function (key, opts, cb) {
  this._root.get(this.prefix(key), opts, cb)
//  this._parent.get(this._key(key), opts, cb)
}

SDB.del = function (key, opts, cb) {
  this._root.del(this.prefix(key), opts, cb)
//  this._parent.del(this._key(key), opts, cb)
}

SDB.batch = function (changes, opts, cb) {
  var self = this
  changes.forEach(function (ch) {
    //OH YEAH, WE NEED TO VALIDATE THAT UPDATING THIS KEY/PREFIX IS ALLOWED
    if('string' === typeof ch.prefix) {
      ch.key = ch.prefix + ch.key
    } else
    ch.key = (ch.prefix || self).prefix(ch.key)
    if(ch.prefix) ch.prefix = null
  })
  this._root.batch(changes, opts, cb)
}

SDB.prefix = function (key) {
  return this._parent.prefix() + this._sep + this._prefix + this._sep + (key || '')
}

SDB.keyStream =
SDB.createKeyStream = function (opts) {
  opts = opts || {}
  opts.keys = true
  return this.createReadStream(opts)
}

SDB.valueStream =
SDB.createValueStream = function (opts) {
  opts = opts || {}
  opts.values = true
  return this.createReadStream(opts)
}

SDB.readStream =
SDB.createReadStream = function (opts) {
  opts = opts || {}
  var r = root(this)
  var p = this.prefix()
  //opts.start = p + (opts.start || '')
  //opts.end = p + (opts.end || this._sep)
  opts = ranges.prefix(opts, p)

  return r.createReadStream(opts)
    .on('data', function (d) {
      //mutate the prefix!
      //this doesn't work for createKeyStream admittedly.
      if(d.key)
        d.key = d.key.substring(p.length)
    })
}

SDB.writeStream =
SDB.createWriteStream = function () {
  var r = root(this)
  var p = this.prefix()
  var ws = r.createWriteStream.apply(r, arguments)
  var write = ws.write
  ws.write = function (data) {
    data.key = p + data.key
    return write.call(ws, data)
  }
  return ws
}

SDB.approximateSize = function () {
  var r = root(db)
  return r.approximateSize.apply(r, arguments)
}

function root(db) {
  if(!db._parent) return db
  return root(db._parent)
}

SDB.pre = function (range, hook) {
  if(!hook) hook = range, range = null
  range = ranges.prefix(range, this.prefix(), this._sep)
  var r = root(this._parent)
  var p = this.prefix()
  return r.hooks.pre(fixRange(range), function (ch, add) {
    hook({
      key: ch.key.substring(p.length),
      value: ch.value,
      type: ch.type
    }, function (ch, _p) {
      //maybe remove the second add arg now
      //that op can have prefix?
      add(ch, ch.prefix ? _p : (_p || p))
    })
  })
}

SDB.post = function (range, hook) {
  if(!hook) hook = range, range = null
  var r = root(this._parent)
  var p = this.prefix()
  range = ranges.prefix(range, p, this._sep)
  return r.hooks.post(fixRange(range), function (data) {
    hook({key: data.key.substring(p.length), value: data.value, type: data.type})
  })
}

var exports = module.exports = SubDB

<|endoftext|>


<commit_before><commit_msg>Periods don't have a route<commit_after><|endoftext|>


<commit_before>"use strict";

// declare public exports
module.exports = {
  createTable: createTable,
  getTables: getTables,
  upsertTable: upsertTable,
  updateTable: updateTable
}

var sfutil = require('./sfutil.js');
var jsforce = require('jsforce');
var fs = require('fs');
var _ = require('underscore');
var s3 = require('./s3.js');
var diff = require('./diff.js');
var Promise = require("bluebird");
var rp = require('request-promise');
var request = require('request');

var baseurl = 'http://54.186.202.81:8080';

function appendData (tableId, objectName, callback) {

    console.log('append data: '+tableId+ ' loc: '+objectName);

    var options = {
        method: 'POST',
        url: baseurl+'/table/appendData?tableId='+tableId+'&objectName='+objectName
    };

    console.log(options.url);

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log(body);
        callback('send data to Schemata: '+tableId+'  '+body);
    });
}

function tableIdForName(tableName, callback) {

    getTables( function (currentTables) {
        var existingTableId = -1;
        for (var i = 0; i < currentTables.length; i++) {
            //console.log('test current tables: '+currentTables[i].id+ ' '+currentTables[i].name);
            if (currentTables[i].name === tableName) {
                existingTableId = currentTables[i].id;
                callback(existingTableId);
                break;
            }
        }
        callback(existingTableId);
    });
}

function upsertTable(tableData, callback) {

    console.log('upserting data');
    console.log(JSON.stringify(tableData, null, 4));

    tableIdForName( tableData.name, function(existingTableId) {

        if (existingTableId > 0) {
            // update existing
            updateTable(existingTableId, tableData, function(response) {
                console.log('callback for existing');
                callback(existingTableId, response);
            });

        } else {
            // create new
            //console.log('create new table from: '+JSON.stringify(tableData, null, 4));
            createTable(tableData, function(response) {
                console.log('callback for new');
                console.log(response);

                var table = JSON.parse(response);
                callback(table.id, response);
            });
        }
    });

}

function tableHeaders (tableName, tableId, callback) {

    var options = { method: 'GET',
    url: 'http://54.186.202.81:8080/table/show/1282'
}

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log(body);
    });
}

// function allQueryForTable (tableId, tableName, callback) {
//
//     getTables( function (currentTables) {
//         var existingTableId = -1;
//         for (var i = 0; i < currentTables.length; i++) {
//             //console.log('test current tables: '+currentTables[i].id+ ' '+currentTables[i].name);
//             if (currentTables[i].name === tableData.name) {
//                 existingTableId = currentTables[i].id;
//                 break;
//             }
//         }
//
//
//     var options = { method: 'POST',
//         url: baseurl+'/table/create',
//         body: JSON.stringify(tableData)
//     };
//
//     request(options, function (error, response, body) {
//         if (error) throw new Error(error);
//
//         console.log('Created a new table w/ Schemata: '+tableData.name);
//         // console.log(response);
//         // console.log(body);
//         callback('new table created: '+body);
//     });
// }

function createTable (tableData, callback) {

    var options = { method: 'POST',
        url: baseurl+'/table/create',
        body: JSON.stringify(tableData)
    };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log('Created a new table w/ Schemata: '+tableData.name);
        // console.log(response);
        // console.log(body);
        callback('new table created: '+body);
    });
}

function updateTable (tableId, tableData, callback) {

    var options = { method: 'POST',
        url: baseurl+'/table/show/tableId',
        body: JSON.stringify(tableData)
    };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log(body);
        callback(tableId+' updated');
    });
}

function getTables( callback) {

    var options = { method: 'GET',
      url: baseurl+'/table'
  };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        //  console.log('Retruend existing tables');
        //  console.log(response);
        //  console.log(body);
        callback(JSON.parse(body));
    });
}

// getTables( function (tables) {
//
//     for (var i = 0; i < tables.length; i++) {
//         console.log('id: '+tables[i].id);
//     }
//
// });
//
//
// function makeHeader(num) {
//     var h1 = {}
//     h1.dataType = "string";
//     h1.label = "test"+num;
//     h1.databaseName = "test"+num;
//     return h1;
// }
//
// var test = {};
// test.name = "test";
// test.headers = [makeHeader(1), makeHeader(2)];
//
// var test2 = {};
// test.name = "test2";
// test.headers = [makeHeader(3), makeHeader(4)];
//
//
// upsertTable(test, function(result) {
//     console.log("TeST 1: "+result);
// });
//
// upsertTable(test, function(result) {
//     console.log("TeST 1 REDO: "+result);
// });
//
// upsertTable(test2, function(result) {
//     console.log("TeST 2: "+result);
// });
//
<commit_msg>remove dead code<commit_after>"use strict";

// declare public exports
module.exports = {
  createTable: createTable,
  getTables: getTables,
  upsertTable: upsertTable,
  updateTable: updateTable
}

var sfutil = require('./sfutil.js');
var jsforce = require('jsforce');
var fs = require('fs');
var _ = require('underscore');
var s3 = require('./s3.js');
var diff = require('./diff.js');
var Promise = require("bluebird");
var rp = require('request-promise');
var request = require('request');

var baseurl = 'http://54.186.202.81:8080';

function appendData (tableId, objectName, callback) {

    console.log('append data: '+tableId+ ' loc: '+objectName);

    var options = {
        method: 'POST',
        url: baseurl+'/table/appendData?tableId='+tableId+'&objectName='+objectName
    };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log(body);
        callback('send data to Schemata: '+tableId+'  '+body);
    });
}

function upsertTable(tableData, callback) {

    console.log('upserting data');

    getTables( function (currentTables) {
        var existingTableId = -1;
        for (var i = 0; i < currentTables.length; i++) {
            //console.log('test current tables: '+currentTables[i].id+ ' '+currentTables[i].name);
            if (currentTables[i].name === tableData.name) {
                existingTableId = currentTables[i].id;
                break;
            }
        }
        console.log('current table found: '+existingTableId);

        console.log('test current tables: '+currentTables[i].id+ ' '+currentTables[i].name);

        if (existingTableId > 0) {
            // update existing
            updateTable(existingTableId, tableData, function(response) {
                console.log('callback for existing');
                callback(existingTableId, response);
            });

        } else {
            // create new
            //console.log('create new table from: '+JSON.stringify(tableData, null, 4));
            createTable(tableData, function(response) {
                console.log('callback for new');

                var table = JSON.parse(response);
                callback(table.id, response);
            });
        }
    });

}

function createTable (tableData, callback) {

    var options = { method: 'POST',
        url: baseurl+'/table/create',
        body: JSON.stringify(tableData)
    };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log('Created a new table w/ Schemata: '+tableData.name);
        // console.log(response);
        // console.log(body);
        callback('new table created: '+body);
    });
}

function updateTable (tableId, tableData, callback) {

    var options = { method: 'POST',
        url: baseurl+'/table/show/tableId',
        body: JSON.stringify(tableData)
    };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        console.log(body);
        callback(tableId+' updated');
    });
}

function getTables( callback) {

    var options = { method: 'GET',
      url: baseurl+'/table'
  };

    request(options, function (error, response, body) {
        if (error) throw new Error(error);

        //  console.log('Retruend existing tables');
        //  console.log(response);
        //  console.log(body);
        callback(JSON.parse(body));
    });
}

// getTables( function (tables) {
//
//     for (var i = 0; i < tables.length; i++) {
//         console.log('id: '+tables[i].id);
//     }
//
// });
//
//
// function makeHeader(num) {
//     var h1 = {}
//     h1.dataType = "string";
//     h1.label = "test"+num;
//     h1.databaseName = "test"+num;
//     return h1;
// }
//
// var test = {};
// test.name = "test";
// test.headers = [makeHeader(1), makeHeader(2)];
//
// var test2 = {};
// test.name = "test2";
// test.headers = [makeHeader(3), makeHeader(4)];
//
//
// upsertTable(test, function(result) {
//     console.log("TeST 1: "+result);
// });
//
// upsertTable(test, function(result) {
//     console.log("TeST 1 REDO: "+result);
// });
//
// upsertTable(test2, function(result) {
//     console.log("TeST 2: "+result);
// });
//
<|endoftext|>