<commit_before>const ejs = require('ejs'),
  fs = require('fs'),
  path = require('path'),
  chalk = require('chalk'),

  project = require('../project').getInstance(),
  StringUtils = require('../utilities/string.utils'),
  ModuleUtils = require('../utilities/module.utils'),
  DynamicPathParser = require('../utilities/dynamic-path-parser'),
  logger = require('../../vendors/logger');

class Blueprints {

  constructor (blueprint, entityName, options, subFolder = false) {
    this.project = project;
    this.entityName = entityName;
    this.options = options;

    this.files = [];
    this.filesPath = path.join(__dirname, blueprint, 'files');
    this.parsedPath = DynamicPathParser.parse(this.project, this.entityName, subFolder);
    this.templateData = {
      entityName    : this.entityName,
      fileName      : this.parsedPath.name,
      classifiedName: StringUtils.classify(this.parsedPath.name),
      camelizedName : StringUtils.camelize(this.parsedPath.name, true)
    };

    this.pathToAppModule = ModuleUtils.findAppModule(this.project, this.parsedPath.dir);
    this.pathToModule = ModuleUtils.findParentModule(this.project, this.parsedPath.dir);
  }

  /**
   * Get entry files
   *
   * @returns {Array<String>}
   */
  getFiles () {
    if (fs.existsSync(this.filesPath)) {
      return this.files.map((file) => `__path__/${file}`);
    }

    return [];
  }

  beforeInstall () {
    return new Promise((resolve) => resolve());
  }

  /**
   * Install an entity
   *
   * 1) Create the output folder
   *
   * For each entity file:
   * 2) Retrieve it's content
   * 3) Render it's content with EJS
   * 4) Write all files into the output folder
   *
   * @returns {Promise}
   */
  install () {
    return new Promise((resolve) => {
      logger.pop(`installing ${this.type}`);

      if (!fs.existsSync(this.parsedPath.entityPath)) {
        fs.mkdirSync(this.parsedPath.entityPath);
      }

      this.getFiles().forEach((file) => {
        let templateString = fs.readFileSync(file.replace('__path__', this.filesPath), 'utf-8');
        let renderedString = ejs.render(templateString, this.templateData);

        let filePath = file.replace('__path__', this.parsedPath.entityPath).replace('__name__', this.parsedPath.name);
        let exists = fs.existsSync(filePath);

        if (!exists) {
          fs.writeFileSync(filePath, renderedString);
        }

        logger.pop(`  ${exists ? chalk.yellow('identical') : chalk.green('create')} ${file.replace('__path__', this.parsedPath.entityDir).replace('__name__', this.parsedPath.name)}`);
      });

      resolve();
    });
  }

  afterInstall () {
    return new Promise((resolve) => resolve());
  }

  /**
   * Register application module and parent module information in template data
   *
   * @param   {boolean} [appOnly=false] We just want to register the app module and not the closest parent module
   * @returns {Promise}
   */
  registerModuleTemplateData (appOnly = false) {
    return new Promise((resolve) => {
      let { modulePath: appModulePath, moduleName: appModuleName } = this._moduleInfo(this.pathToAppModule);
      let  {modulePath, moduleName } = this._moduleInfo(this.pathToModule);

      if (!appOnly) {
        this.templateData = Object.assign(this.templateData, {
          appModulePath: (this.pathToAppModule === this.pathToModule) ? null : appModulePath,
          appModuleName: (this.pathToAppModule === this.pathToModule) ? null : appModuleName,
          modulePath   : modulePath,
          moduleName   : moduleName
        });
      } else {
        this.templateData = Object.assign(this.templateData, {
          appModulePath: appModulePath,
          appModuleName: appModuleName,
        });
      }

      resolve();
    });
  }

  /**
   * Export for "class likes" afterInstall process (service, component, directive, ...).
   * It's added kind of the same way inside the parent module.
   *
   * @param   {{entityName?: string, type?: string}}  data  Override some of the default options
   * @returns {Promise}
   */
  classStyleAfterInstall (data = {}) {
    return new Promise((resolve) => {
      let type = data.type || this.type,
        module = fs.readFileSync(this.pathToModule, 'utf8'),
        fullName = `${this.templateData.classifiedName}${StringUtils.classify(type)}`,
        fileName = `${this.parsedPath.name}.${type}`,
        entityName = data.entityName || this.parsedPath.name,
        componentDir = DynamicPathParser.relative(path.dirname(this.pathToModule), this.parsedPath.entityPath),
        importPath = componentDir ? `./${componentDir}/${fileName}` : `./${fileName}`;

      // Complete the module
      module = ModuleUtils.addImportToModule(module, fullName, importPath, true);
      module = ModuleUtils.addDeclarationToModule(module, fullName, entityName, type);

      ModuleUtils.writeModuleFile(this.pathToModule, module);

      logger.pop(`  ${chalk.yellow('update')} ${DynamicPathParser.relative(this.project.root, this.pathToModule)}`);

      resolve();
    });
  }

  _moduleInfo (pathToModule) {
    let moduleFileName = path.basename(pathToModule, '.ts'),
      moduleDir = DynamicPathParser.relative(this.parsedPath.entityPath, path.dirname(pathToModule)),
      modulePath = moduleDir ? `${moduleDir}/${moduleFileName}` : `./${moduleFileName}`;

    return {
      modulePath: modulePath,
      moduleName: ModuleUtils.getModuleName(pathToModule)
    };
  }

}

Blueprints.types = [ 'component', 'directive', 'filter', 'service', 'module' ];

module.exports = Blueprints;
<commit_msg>chore(blueprint): add a quiet option for testing purpose<commit_after>const ejs = require('ejs'),
  fs = require('fs'),
  path = require('path'),
  chalk = require('chalk'),

  project = require('../project').getInstance(),
  StringUtils = require('../utilities/string.utils'),
  ModuleUtils = require('../utilities/module.utils'),
  DynamicPathParser = require('../utilities/dynamic-path-parser'),
  logger = require('../../vendors/logger');

class Blueprints {

  constructor (blueprint, entityName, options, subFolder = false) {
    this.project = project;
    this.entityName = entityName;
    this.options = options;

    this.files = [];
    this.filesPath = path.join(__dirname, blueprint, 'files');
    this.parsedPath = DynamicPathParser.parse(this.project, this.entityName, subFolder);
    this.templateData = {
      entityName    : this.entityName,
      fileName      : this.parsedPath.name,
      classifiedName: StringUtils.classify(this.parsedPath.name),
      camelizedName : StringUtils.camelize(this.parsedPath.name, true)
    };

    this.pathToAppModule = ModuleUtils.findAppModule(this.project, this.parsedPath.dir);
    this.pathToModule = ModuleUtils.findParentModule(this.project, this.parsedPath.dir);
  }

  /**
   * Get entry files
   *
   * @returns {Array<String>}
   */
  getFiles () {
    if (fs.existsSync(this.filesPath)) {
      return this.files.map((file) => `__path__/${file}`);
    }

    return [];
  }

  beforeInstall () {
    return new Promise((resolve) => resolve());
  }

  /**
   * Install an entity
   *
   * 1) Create the output folder
   *
   * For each entity file:
   * 2) Retrieve it's content
   * 3) Render it's content with EJS
   * 4) Write all files into the output folder
   *
   * @returns {Promise}
   */
  install () {
    return new Promise((resolve) => {
      this._log(`installing ${this.type}`);

      if (!fs.existsSync(this.parsedPath.entityPath)) {
        fs.mkdirSync(this.parsedPath.entityPath);
      }

      this.getFiles().forEach((file) => {
        let templateString = fs.readFileSync(file.replace('__path__', this.filesPath), 'utf-8');
        let renderedString = ejs.render(templateString, this.templateData);

        let filePath = file.replace('__path__', this.parsedPath.entityPath).replace('__name__', this.parsedPath.name);
        let exists = fs.existsSync(filePath);

        if (!exists) {
          fs.writeFileSync(filePath, renderedString);
        }

        this._log(`  ${exists ? chalk.yellow('identical') : chalk.green('create')} ${file.replace('__path__', this.parsedPath.entityDir).replace('__name__', this.parsedPath.name)}`);
      });

      resolve();
    });
  }

  afterInstall () {
    return new Promise((resolve) => resolve());
  }

  /**
   * Register application module and parent module information in template data
   *
   * @param   {boolean} [appOnly=false] We just want to register the app module and not the closest parent module
   * @returns {Promise}
   */
  registerModuleTemplateData (appOnly = false) {
    return new Promise((resolve) => {
      let { modulePath: appModulePath, moduleName: appModuleName } = this._moduleInfo(this.pathToAppModule);
      let { modulePath, moduleName } = this._moduleInfo(this.pathToModule);

      if (appOnly) {
        this.templateData = Object.assign(this.templateData, {
          appModulePath: appModulePath,
          appModuleName: appModuleName,
        });
      } else {
        this.templateData = Object.assign(this.templateData, {
          appModulePath: (this.pathToAppModule === this.pathToModule) ? null : appModulePath,
          appModuleName: (this.pathToAppModule === this.pathToModule) ? null : appModuleName,
          modulePath   : modulePath,
          moduleName   : moduleName
        });
      }

      resolve();
    });
  }

  /**
   * Export for "class likes" afterInstall process (service, component, directive, ...).
   * It's added kind of the same way inside the parent module.
   *
   * @param   {{entityName?: string, type?: string}}  data  Override some of the default options
   * @returns {Promise}
   */
  classStyleAfterInstall (data = {}) {
    return new Promise((resolve) => {
      let type = data.type || this.type,
        module = fs.readFileSync(this.pathToModule, 'utf8'),
        fullName = `${this.templateData.classifiedName}${StringUtils.classify(type)}`,
        fileName = `${this.parsedPath.name}.${type}`,
        entityName = data.entityName || this.parsedPath.name,
        componentDir = DynamicPathParser.relative(path.dirname(this.pathToModule), this.parsedPath.entityPath),
        importPath = componentDir ? `./${componentDir}/${fileName}` : `./${fileName}`;

      // Complete the module
      module = ModuleUtils.addImportToModule(module, fullName, importPath, true);
      module = ModuleUtils.addDeclarationToModule(module, fullName, entityName, type);

      ModuleUtils.writeModuleFile(this.pathToModule, module);

      this._log(`  ${chalk.yellow('update')} ${DynamicPathParser.relative(this.project.root, this.pathToModule)}`);

      resolve();
    });
  }

  _moduleInfo (pathToModule) {
    let moduleFileName = path.basename(pathToModule, '.ts'),
      moduleDir = DynamicPathParser.relative(this.parsedPath.entityPath, path.dirname(pathToModule)),
      modulePath = moduleDir ? `${moduleDir}/${moduleFileName}` : `./${moduleFileName}`;

    return {
      modulePath: modulePath,
      moduleName: ModuleUtils.getModuleName(pathToModule)
    };
  }

  _log (message, type = 'pop') {
    if (!this.options.quiet) {
      switch (type) {
        case 'info':
          logger.info(message);
          break;

        case 'pop':
        default:
          logger.pop(message);
          break;
      }
    }
  }

}

Blueprints.types = [ 'component', 'directive', 'filter', 'service', 'module' ];

module.exports = Blueprints;
<|endoftext|>


<commit_before>//= require_tree .

// Simply a promise wrapper around setTimeout
function wait(millis)
{
  return function waitInner() {
    var deferred = new $.Deferred();
    setTimeout(deferred.resolve, millis);
    return deferred;
  };
}

function initHeartAnimation()
{
  var heroClassEls = $(".hero");
  var unitClassEls = $(".unit");
  var outerHeartEl = $("#outer-heart");
  var innerHeartEl = $("#inner-heart");
  var redAndBlackHeartEl = $("#red-black-heart");

  // hide the elements when document is ready so
  // it does not need to be done on the css elements
  heroClassEls.hide();
  unitClassEls.hide();

  // To keep it clean, kick off the chain with a deferred
  var deferred = new $.Deferred();
  deferred.resolve();

  deferred
  .then(wait(600))
  .then(function() { outerHeartEl.show(); })
  .then(function() { animateSVG(outerHeartEl[0]); })
  .then(wait(1200))
  .then(function() { innerHeartEl.fadeIn(800); })
  .then(wait(2000))
  .then(function() { redAndBlackHeartEl.fadeOut(1400); })
  .then(function() { heroClassEls.fadeIn(1000); })
  .then(function() { unitClassEls.fadeIn(1000); });
}

function animateSVG(path)
{
  var length = path.getTotalLength();

  path.style.transition = path.style.WebkitTransition = 'none';
  path.style.strokeDasharray = length + ' ' + length;
  path.style.strokeDashoffset = length;
  path.getBoundingClientRect();
  path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 2s ease-in-out';
  path.style.strokeDashoffset = '0';
}

function initSubscribeForm()
{
  var subscribeFormEl = $("#subscribe-form");
  var subscribeFormSuccessEl = $("#subscribe-form-success");
  var subscribeFormFailureEl = $("#subscribe-form-failure");

  subscribeFormEl.submit(function(evt) {
    // Must make sure the failure is hidden if it is on the page
    subscribeFormFailureEl.fadeOut("fast").addClass("hidden");

    var data = $(this).serialize();
    var xhr = $.post("/subscribers", data);
    xhr.done(function(response) {
      console.log("Subscribed!", response);
      subscribeFormEl.fadeOut("slow", function() {
        $(this).hide();
        subscribeFormSuccessEl.fadeIn("slow");
      });
    });
    xhr.fail(function(response) {
      subscribeFormFailureEl.fadeIn("slow");
    });

    evt.preventDefault();
  });
}

$(function() {
  initHeartAnimation();
  initSubscribeForm();
});<commit_msg>Don't try to execute the animation if the heart doesn't exist.<commit_after>//= require_tree .

// Simply a promise wrapper around setTimeout
function wait(millis)
{
  return function waitInner() {
    var deferred = new $.Deferred();
    setTimeout(deferred.resolve, millis);
    return deferred;
  };
}

function initHeartAnimation()
{
  var heroClassEls = $(".hero");
  var unitClassEls = $(".unit");
  var outerHeartEl = $("#outer-heart");
  var innerHeartEl = $("#inner-heart");
  var redAndBlackHeartEl = $("#red-black-heart");

  // Nothing to do if the heart doesn't exist
  if (outerHeartEl.length <= 0) { return; }

  // hide the elements when document is ready so
  // it does not need to be done on the css elements
  heroClassEls.hide();
  unitClassEls.hide();

  // To keep it clean, kick off the chain with a deferred
  var deferred = new $.Deferred();
  deferred.resolve();

  deferred
  .then(wait(600))
  .then(function() { outerHeartEl.show(); })
  .then(function() { animateSVG(outerHeartEl[0]); })
  .then(wait(1200))
  .then(function() { innerHeartEl.fadeIn(800); })
  .then(wait(2000))
  .then(function() { redAndBlackHeartEl.fadeOut(1400); })
  .then(function() { heroClassEls.fadeIn(1000); })
  .then(function() { unitClassEls.fadeIn(1000); });
}

function animateSVG(path)
{
  var length = path.getTotalLength();

  path.style.transition = path.style.WebkitTransition = 'none';
  path.style.strokeDasharray = length + ' ' + length;
  path.style.strokeDashoffset = length;
  path.getBoundingClientRect();
  path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 2s ease-in-out';
  path.style.strokeDashoffset = '0';
}

function initSubscribeForm()
{
  var subscribeFormEl = $("#subscribe-form");
  var subscribeFormSuccessEl = $("#subscribe-form-success");
  var subscribeFormFailureEl = $("#subscribe-form-failure");

  subscribeFormEl.submit(function(evt) {
    // Must make sure the failure is hidden if it is on the page
    subscribeFormFailureEl.fadeOut("fast").addClass("hidden");

    var data = $(this).serialize();
    var xhr = $.post("/subscribers", data);
    xhr.done(function(response) {
      console.log("Subscribed!", response);
      subscribeFormEl.fadeOut("slow", function() {
        $(this).hide();
        subscribeFormSuccessEl.fadeIn("slow");
      });
    });
    xhr.fail(function(response) {
      subscribeFormFailureEl.fadeIn("slow");
    });

    evt.preventDefault();
  });
}

$(function() {
  initHeartAnimation();
  initSubscribeForm();
});<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

sap.ui.define([], function () {
	'use strict';

	/**
	 * NotificationListItem renderer.
	 * @namespace
	 */
	var NotificationListItemRenderer = {};

	var classNameItem = 'sapMNLI';
	var classNameBase = 'sapMNLB';
	var classNameTextWrapper = 'sapMNLI-TextWrapper';
	var classNameListBaseItem = 'sapMLIB';
	var classNameAuthor = 'sapMNLB-AuthorPicture';
	var classNamePriority = 'sapMNLB-Priority';
	var classNameBaseHeader = 'sapMNLB-Header';
	var classNameHeader = 'sapMNLI-Header';
	var classNameBody = 'sapMNLI-Body';
	var classNameDescription = 'sapMNLI-Description';
	var classNameDetails = 'sapMNLI-Details';
	var classNameBullet = 'sapMNLB-Bullet';
	var classNameBaseFooter = 'sapMNLB-Footer';
	var classNameFooter = 'sapMNLI-Footer';
	var classNameCloseButton = 'sapMNLB-CloseButton';
	var classNameCollapseButton = 'sapMNLI-CollapseButton';
	var classNameInitialOverwriteTitle = 'sapMNLI-TitleWrapper--initial-overwrite';
	var classNameInitialOverwriteText = 'sapMNLI-TextWrapper--initial-overwrite';

	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.render = function (oRm, oControl) {
		var id = oControl.getId();

		oRm.write('
');

		this.renderPriorityArea(oRm, oControl);
		this.renderHeader(oRm, oControl);
		this.renderBody(oRm, oControl);
		this.renderFooter(oRm, oControl);

		oRm.write('
');
	};

	//================================================================================
	// Priority and picture rendering methods
	//================================================================================

	/**
	 * Renders the visual representation of the priority of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderPriorityArea = function(oRm, oControl) {
		oRm.write('
');
		oRm.write('
');
	};

	/**
	 * Renders the picture of the author of the Notification.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderAuthorPicture = function(oRm, oControl) {
		if (!oControl.getAuthorPicture()) {
		    return;
		}

		oRm.write('
');
		oRm.renderControl(oControl._getAuthorImage());
		oRm.write('
');
	};

	/**
	 * Renders the close button of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderCloseButton = function (oRm, oControl) {
		if (oControl.getShowCloseButton()) {
			oRm.renderControl(oControl._closeButton.addStyleClass(classNameCloseButton));
		}
	};

	/**
	 * Renders the close button of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderCollapseButton = function (oRm, oControl) {
		oRm.renderControl(oControl._collapseButton.addStyleClass(classNameCollapseButton));
	};

	//================================================================================
	// Header rendering methods
	//================================================================================

	/**
	 * Renders the header content of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderHeader = function (oRm, oControl) {
		for (var index = 0; index < 10000; index++) {
			1 + index;

			for (var j = 0; j < 10000; j++) {
				1 + j + index;
			}
		}
		oRm.write('
');

		this.renderCloseButton(oRm, oControl);
		this.renderTitle(oRm, oControl);
		oRm.write('
');
	};

	/**
	 * Renders the title of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderTitle = function (oRm, oControl) {
		oRm.renderControl(oControl._getHeaderTitle());
	};

	//================================================================================
	// Body rendering methods
	//================================================================================

	/**
	 * Renders the body content of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderBody = function (oRm, oControl) {
		oRm.write('
');

		this.renderAuthorPicture(oRm, oControl);
		oRm.write('
');
		this.renderDescription(oRm, oControl);
		this.renderDetails(oRm, oControl);
		oRm.write('
');
		this.renderAriaText(oRm, oControl);

		oRm.write('
');
	};

	/**
	 * Renders the description text inside the body of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderDescription = function (oRm, oControl) {
		oRm.write('
');

		oRm.renderControl(oControl._getDescriptionText());
		oRm.write('
');
	};

	/**
	 * Renders the details, such as author name and timestamp of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderDetails = function(oRm, oControl) {
		oRm.write('
');
		this.renderAuthorName(oRm, oControl);

		if (oControl.getAuthorName()) {
			oRm.write('&#x00B7');
		}
		this.renderDatetime(oRm, oControl);
		oRm.write('
');
	};

	/**
	 * Renders the timestamp of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderDatetime = function (oRm, oControl) {
		oRm.renderControl(oControl._getDateTimeText());
	};

	/**
	 * Renders the name of the author of the notification.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderAuthorName = function (oRm, oControl) {
		oRm.renderControl(oControl._getAuthorName());
	};

	/**
	 * Provides ARIA support for the additional control information information, such as, read status, due date, and priority.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.m.NotificationListItem} oControl An object representation of the Notification List Item that should be rendered
	 */
	NotificationListItemRenderer.renderAriaText = function (oRm, oControl) {
		oRm.renderControl(oControl._ariaDetailsText);
	};

	//================================================================================
	// Footer rendering methods
	//================================================================================

	/**
	 * Renders the footer content of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderFooter = function (oRm, oControl) {
		var aButtons = oControl.getButtons();

		//oRm.write('
');

		oRm.write('
');

		this.renderCollapseButton(oRm, oControl);

		if (aButtons && aButtons.length && oControl.getShowButtons()) {
			oRm.renderControl(oControl.getAggregation('_overflowToolbar'));
		}
		oRm.write('
');
	};

	return NotificationListItemRenderer;

}, /* bExport= */ true);
<commit_msg>[INTERNAL] sap.m.NotificationListItem: Code cleanup.<commit_after>/*!
 * ${copyright}
 */

sap.ui.define([], function () {
	'use strict';

	/**
	 * NotificationListItem renderer.
	 * @namespace
	 */
	var NotificationListItemRenderer = {};

	var classNameItem = 'sapMNLI';
	var classNameBase = 'sapMNLB';
	var classNameTextWrapper = 'sapMNLI-TextWrapper';
	var classNameListBaseItem = 'sapMLIB';
	var classNameAuthor = 'sapMNLB-AuthorPicture';
	var classNamePriority = 'sapMNLB-Priority';
	var classNameBaseHeader = 'sapMNLB-Header';
	var classNameHeader = 'sapMNLI-Header';
	var classNameBody = 'sapMNLI-Body';
	var classNameDescription = 'sapMNLI-Description';
	var classNameDetails = 'sapMNLI-Details';
	var classNameBullet = 'sapMNLB-Bullet';
	var classNameBaseFooter = 'sapMNLB-Footer';
	var classNameFooter = 'sapMNLI-Footer';
	var classNameCloseButton = 'sapMNLB-CloseButton';
	var classNameCollapseButton = 'sapMNLI-CollapseButton';
	var classNameInitialOverwriteTitle = 'sapMNLI-TitleWrapper--initial-overwrite';
	var classNameInitialOverwriteText = 'sapMNLI-TextWrapper--initial-overwrite';

	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.render = function (oRm, oControl) {
		var id = oControl.getId();

		oRm.write('
');

		this.renderPriorityArea(oRm, oControl);
		this.renderHeader(oRm, oControl);
		this.renderBody(oRm, oControl);
		this.renderFooter(oRm, oControl);

		oRm.write('
');
	};

	//================================================================================
	// Priority and picture rendering methods
	//================================================================================

	/**
	 * Renders the visual representation of the priority of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderPriorityArea = function(oRm, oControl) {
		oRm.write('
');
		oRm.write('
');
	};

	/**
	 * Renders the picture of the author of the Notification.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderAuthorPicture = function(oRm, oControl) {
		if (!oControl.getAuthorPicture()) {
		    return;
		}

		oRm.write('
');
		oRm.renderControl(oControl._getAuthorImage());
		oRm.write('
');
	};

	/**
	 * Renders the close button of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderCloseButton = function (oRm, oControl) {
		if (oControl.getShowCloseButton()) {
			oRm.renderControl(oControl._closeButton.addStyleClass(classNameCloseButton));
		}
	};

	/**
	 * Renders the close button of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderCollapseButton = function (oRm, oControl) {
		oRm.renderControl(oControl._collapseButton.addStyleClass(classNameCollapseButton));
	};

	//================================================================================
	// Header rendering methods
	//================================================================================

	/**
	 * Renders the header content of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderHeader = function (oRm, oControl) {
		oRm.write('
');

		this.renderCloseButton(oRm, oControl);
		this.renderTitle(oRm, oControl);
		oRm.write('
');
	};

	/**
	 * Renders the title of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderTitle = function (oRm, oControl) {
		oRm.renderControl(oControl._getHeaderTitle());
	};

	//================================================================================
	// Body rendering methods
	//================================================================================

	/**
	 * Renders the body content of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderBody = function (oRm, oControl) {
		oRm.write('
');

		this.renderAuthorPicture(oRm, oControl);
		oRm.write('
');
		this.renderDescription(oRm, oControl);
		this.renderDetails(oRm, oControl);
		oRm.write('
');
		this.renderAriaText(oRm, oControl);

		oRm.write('
');
	};

	/**
	 * Renders the description text inside the body of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderDescription = function (oRm, oControl) {
		oRm.write('
');

		oRm.renderControl(oControl._getDescriptionText());
		oRm.write('
');
	};

	/**
	 * Renders the details, such as author name and timestamp of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderDetails = function(oRm, oControl) {
		oRm.write('
');
		this.renderAuthorName(oRm, oControl);

		if (oControl.getAuthorName()) {
			oRm.write('&#x00B7');
		}
		this.renderDatetime(oRm, oControl);
		oRm.write('
');
	};

	/**
	 * Renders the timestamp of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderDatetime = function (oRm, oControl) {
		oRm.renderControl(oControl._getDateTimeText());
	};

	/**
	 * Renders the name of the author of the notification.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderAuthorName = function (oRm, oControl) {
		oRm.renderControl(oControl._getAuthorName());
	};

	/**
	 * Provides ARIA support for the additional control information information, such as, read status, due date, and priority.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.m.NotificationListItem} oControl An object representation of the Notification List Item that should be rendered
	 */
	NotificationListItemRenderer.renderAriaText = function (oRm, oControl) {
		oRm.renderControl(oControl._ariaDetailsText);
	};

	//================================================================================
	// Footer rendering methods
	//================================================================================

	/**
	 * Renders the footer content of the NotificationListItem.
	 *
	 * @param {sap.ui.core.RenderManager} oRm The RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl An object representation of the control that should be rendered
	 */
	NotificationListItemRenderer.renderFooter = function (oRm, oControl) {
		var aButtons = oControl.getButtons();

		//oRm.write('
');

		oRm.write('
');

		this.renderCollapseButton(oRm, oControl);

		if (aButtons && aButtons.length && oControl.getShowButtons()) {
			oRm.renderControl(oControl.getAggregation('_overflowToolbar'));
		}
		oRm.write('
');
	};

	return NotificationListItemRenderer;

}, /* bExport= */ true);
<|endoftext|>


<commit_before>var Component = new Brick.Component();
Component.requires = {
    mod: [
        {name: 'sys', files: ['editor.js']},
        {name: '{C#MODNAME}', files: ['lib.js', 'employeesList.js']}
    ]
};
Component.entryPoint = function(NS){

	var Y = Brick.YUI,
        COMPONENT = this,
        SYS = Brick.mod.sys;

    NS.AddSelectValueModalWidget = Y.Base.create('addSelectValueModalWidget', SYS.AppWidget, [], {
        onInitAppWidget: function(err, appInstance){

        },
        showModal: function(valueid, attrid, numrow, relationid){
        	var tp = this.template;

          	this.set('attrid', attrid);
        	this.set('valueid', valueid);
        	this.set('relationid', relationid);
        	this.set('numrow', numrow);

	        	tp.setHTML('modal', tp.replace('modalForm', {
	        		none: 'block'
	        	}));

        	this.employees = new NS.EmployeesListWidget({
                srcNode: tp.gel('modalForm.form'),
                select: true,
                relationid: relationid
    		});

        },
        destroy: function(){
        	if(this.employees){
        		this.employees.destroy();
        	}
        },
        unSetSuccess: function(tr){
        	var collect = tr.parentNode.childNodes;

        	collect.forEach(function(item){
        		item.classList.remove('success');
        	});
        },
        selectValueAct: function(callback){
        	var data = {
        		valueid: this.get('valueid'),
        		attrid: this.get('attrid'),
        		relationid: this.get('relationid'),
        		numrow: this.get('numrow')
        	};

        	this.set('waiting', true);
	        	this.get('appInstance').selectValueAct(data, function(err, result){
	        		this.set('waiting', false);
		        		if(!err){
		        			this.template.setHTML('modal', '');
		        				callback(result.selectValueAct);
		        		}
	        	}, this);
        }
    }, {
        ATTRS: {
        	component: {value: COMPONENT},
            templateBlockName: {value: 'widget, modalForm'},
            valueid: {value: 0},
            attrid: {value: 0},
            relationid: {value: 0},
            numrow: {value: 0}
        },
        CLICKS: {
        	'addValue-cancel': {
        		event: function(){
        			this.template.setHTML('modal', '');
        		}
        	},
        	pickRow: {
        		event: function(e){
        			var targ = e.target,
        				tr = e.target.getDOMNode().parentNode;

        			if(tr.tagName != 'TR' || tr.id == ''){
        				return;
        			}

        			this.unSetSuccess(tr);
        			tr.classList.add('success');

        			this.set('relationid', tr.id.match(/-(\d+)/)[1]);
        		}
        	}
        }
    });
};<commit_msg>refactoring: unSet select value<commit_after>var Component = new Brick.Component();
Component.requires = {
    mod: [
        {name: 'sys', files: ['editor.js']},
        {name: '{C#MODNAME}', files: ['lib.js', 'employeesList.js']}
    ]
};
Component.entryPoint = function(NS){

	var Y = Brick.YUI,
        COMPONENT = this,
        SYS = Brick.mod.sys;

    NS.AddSelectValueModalWidget = Y.Base.create('addSelectValueModalWidget', SYS.AppWidget, [], {
        onInitAppWidget: function(err, appInstance){

        },
        showModal: function(valueid, attrid, numrow, relationid){
        	var tp = this.template;

          	this.set('attrid', attrid);
        	this.set('valueid', valueid);
        	this.set('relationid', relationid);
        	this.set('numrow', numrow);

	        	tp.setHTML('modal', tp.replace('modalForm', {
	        		none: 'block'
	        	}));

        	this.employees = new NS.EmployeesListWidget({
                srcNode: tp.gel('modalForm.form'),
                select: true,
                relationid: relationid
    		});

        },
        destroy: function(){
        	if(this.employees){
        		this.employees.destroy();
        	}
        },
        unSetSuccess: function(tr){
        	var collect = tr.parentNode.childNodes,
        		len = collect.length;

        		for(var i = 0; i < len; i++){
        			collect[i].classList.remove('success');
        		}
        },
        selectValueAct: function(callback){
        	var data = {
        		valueid: this.get('valueid'),
        		attrid: this.get('attrid'),
        		relationid: this.get('relationid'),
        		numrow: this.get('numrow')
        	};

        	this.set('waiting', true);
	        	this.get('appInstance').selectValueAct(data, function(err, result){
	        		this.set('waiting', false);
		        		if(!err){
		        			this.template.setHTML('modal', '');
		        				callback(result.selectValueAct);
		        		}
	        	}, this);
        }
    }, {
        ATTRS: {
        	component: {value: COMPONENT},
            templateBlockName: {value: 'widget, modalForm'},
            valueid: {value: 0},
            attrid: {value: 0},
            relationid: {value: 0},
            numrow: {value: 0}
        },
        CLICKS: {
        	'addValue-cancel': {
        		event: function(){
        			this.template.setHTML('modal', '');
        		}
        	},
        	pickRow: {
        		event: function(e){
        			var targ = e.target,
        				tr = e.target.getDOMNode().parentNode;

        			if(tr.tagName != 'TR' || tr.id == ''){
        				return;
        			}

        			this.unSetSuccess(tr);
        			tr.classList.add('success');

        			this.set('relationid', tr.id.match(/-(\d+)/)[1]);
        		}
        	}
        }
    });
};<|endoftext|>


<commit_before>import { addClass, elt, rmClass } from "../util/dom"
import { on } from "../util/event"
import { scrollGap, paddingVert } from "../measurement/position_measurement"
import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser"
import { updateHeightsInViewport } from "./update_lines"
import { Delayed } from "../util/misc"

import { setScrollLeft, setScrollTop } from "./scroll_events"

// SCROLLBARS

// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
export function measureForScrollbars(cm) {
  let d = cm.display, gutterW = d.gutters.offsetWidth
  let docH = Math.round(cm.doc.height + paddingVert(cm.display))
  return {
    clientHeight: d.scroller.clientHeight,
    viewHeight: d.wrapper.clientHeight,
    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
    viewWidth: d.wrapper.clientWidth,
    barLeft: cm.options.fixedGutter ? gutterW : 0,
    docHeight: docH,
    scrollHeight: docH + scrollGap(cm) + d.barHeight,
    nativeBarWidth: d.nativeBarWidth,
    gutterWidth: gutterW
  }
}

class NativeScrollbars {
  constructor(place, scroll, cm) {
    this.cm = cm
    let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
    let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
    place(vert); place(horiz)

    on(vert, "scroll", () => {
      if (vert.clientHeight) scroll(vert.scrollTop, "vertical")
    })
    on(horiz, "scroll", () => {
      if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal")
    })

    this.checkedZeroWidth = false
    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"
  }

  update(measure) {
    let needsH = measure.scrollWidth > measure.clientWidth + 1
    let needsV = measure.scrollHeight > measure.clientHeight + 1
    let sWidth = measure.nativeBarWidth

    if (needsV) {
      this.vert.style.display = "block"
      this.vert.style.bottom = needsH ? sWidth + "px" : "0"
      let totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
      // A bug in IE8 can cause this value to be negative, so guard it.
      this.vert.firstChild.style.height =
        Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
    } else {
      this.vert.style.display = ""
      this.vert.firstChild.style.height = "0"
    }

    if (needsH) {
      this.horiz.style.display = "block"
      this.horiz.style.right = needsV ? sWidth + "px" : "0"
      this.horiz.style.left = measure.barLeft + "px"
      let totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
      this.horiz.firstChild.style.width =
        (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
    } else {
      this.horiz.style.display = ""
      this.horiz.firstChild.style.width = "0"
    }

    if (!this.checkedZeroWidth && measure.clientHeight > 0) {
      if (sWidth == 0) this.zeroWidthHack()
      this.checkedZeroWidth = true
    }

    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
  }

  setScrollLeft(pos) {
    if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos
    if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz)
  }

  setScrollTop(pos) {
    if (this.vert.scrollTop != pos) this.vert.scrollTop = pos
    if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert)
  }

  zeroWidthHack() {
    let w = mac && !mac_geMountainLion ? "12px" : "18px"
    this.horiz.style.height = this.vert.style.width = w
    this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
    this.disableHoriz = new Delayed
    this.disableVert = new Delayed
  }

  enableZeroWidthBar(bar, delay) {
    bar.style.pointerEvents = "auto"
    function maybeDisable() {
      // To find out whether the scrollbar is still visible, we
      // check whether the element under the pixel in the bottom
      // left corner of the scrollbar box is the scrollbar box
      // itself (when the bar is still visible) or its filler child
      // (when the bar is hidden). If it is still visible, we keep
      // it enabled, if it's hidden, we disable pointer events.
      let box = bar.getBoundingClientRect()
      let elt = document.elementFromPoint(box.left + 1, box.bottom - 1)
      if (elt != bar) bar.style.pointerEvents = "none"
      else delay.set(1000, maybeDisable)
    }
    delay.set(1000, maybeDisable)
  }

  clear() {
    let parent = this.horiz.parentNode
    parent.removeChild(this.horiz)
    parent.removeChild(this.vert)
  }
}

class NullScrollbars {
  update() { return {bottom: 0, right: 0} }
  setScrollLeft() {}
  setScrollTop() {}
  clear() {}
}

export function updateScrollbars(cm, measure) {
  if (!measure) measure = measureForScrollbars(cm)
  let startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
  updateScrollbarsInner(cm, measure)
  for (let i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
      updateHeightsInViewport(cm)
    updateScrollbarsInner(cm, measureForScrollbars(cm))
    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
  }
}

// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner(cm, measure) {
  let d = cm.display
  let sizes = d.scrollbars.update(measure)

  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
  d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"

  if (sizes.right && sizes.bottom) {
    d.scrollbarFiller.style.display = "block"
    d.scrollbarFiller.style.height = sizes.bottom + "px"
    d.scrollbarFiller.style.width = sizes.right + "px"
  } else d.scrollbarFiller.style.display = ""
  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
    d.gutterFiller.style.display = "block"
    d.gutterFiller.style.height = sizes.bottom + "px"
    d.gutterFiller.style.width = measure.gutterWidth + "px"
  } else d.gutterFiller.style.display = ""
}

export let scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}

export function initScrollbars(cm) {
  if (cm.display.scrollbars) {
    cm.display.scrollbars.clear()
    if (cm.display.scrollbars.addClass)
      rmClass(cm.display.wrapper, cm.display.scrollbars.addClass)
  }

  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](node => {
    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
    // Prevent clicks in the scrollbars from killing focus
    on(node, "mousedown", () => {
      if (cm.state.focused) setTimeout(() => cm.display.input.focus(), 0)
    })
    node.setAttribute("cm-not-content", "true")
  }, (pos, axis) => {
    if (axis == "horizontal") setScrollLeft(cm, pos)
    else setScrollTop(cm, pos)
  }, cm)
  if (cm.display.scrollbars.addClass)
    addClass(cm.display.wrapper, cm.display.scrollbars.addClass)
}
<commit_msg>Avoid setting a negative width style<commit_after>import { addClass, elt, rmClass } from "../util/dom"
import { on } from "../util/event"
import { scrollGap, paddingVert } from "../measurement/position_measurement"
import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser"
import { updateHeightsInViewport } from "./update_lines"
import { Delayed } from "../util/misc"

import { setScrollLeft, setScrollTop } from "./scroll_events"

// SCROLLBARS

// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
export function measureForScrollbars(cm) {
  let d = cm.display, gutterW = d.gutters.offsetWidth
  let docH = Math.round(cm.doc.height + paddingVert(cm.display))
  return {
    clientHeight: d.scroller.clientHeight,
    viewHeight: d.wrapper.clientHeight,
    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
    viewWidth: d.wrapper.clientWidth,
    barLeft: cm.options.fixedGutter ? gutterW : 0,
    docHeight: docH,
    scrollHeight: docH + scrollGap(cm) + d.barHeight,
    nativeBarWidth: d.nativeBarWidth,
    gutterWidth: gutterW
  }
}

class NativeScrollbars {
  constructor(place, scroll, cm) {
    this.cm = cm
    let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
    let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
    place(vert); place(horiz)

    on(vert, "scroll", () => {
      if (vert.clientHeight) scroll(vert.scrollTop, "vertical")
    })
    on(horiz, "scroll", () => {
      if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal")
    })

    this.checkedZeroWidth = false
    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"
  }

  update(measure) {
    let needsH = measure.scrollWidth > measure.clientWidth + 1
    let needsV = measure.scrollHeight > measure.clientHeight + 1
    let sWidth = measure.nativeBarWidth

    if (needsV) {
      this.vert.style.display = "block"
      this.vert.style.bottom = needsH ? sWidth + "px" : "0"
      let totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
      // A bug in IE8 can cause this value to be negative, so guard it.
      this.vert.firstChild.style.height =
        Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
    } else {
      this.vert.style.display = ""
      this.vert.firstChild.style.height = "0"
    }

    if (needsH) {
      this.horiz.style.display = "block"
      this.horiz.style.right = needsV ? sWidth + "px" : "0"
      this.horiz.style.left = measure.barLeft + "px"
      let totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
      this.horiz.firstChild.style.width =
        Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
    } else {
      this.horiz.style.display = ""
      this.horiz.firstChild.style.width = "0"
    }

    if (!this.checkedZeroWidth && measure.clientHeight > 0) {
      if (sWidth == 0) this.zeroWidthHack()
      this.checkedZeroWidth = true
    }

    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
  }

  setScrollLeft(pos) {
    if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos
    if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz)
  }

  setScrollTop(pos) {
    if (this.vert.scrollTop != pos) this.vert.scrollTop = pos
    if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert)
  }

  zeroWidthHack() {
    let w = mac && !mac_geMountainLion ? "12px" : "18px"
    this.horiz.style.height = this.vert.style.width = w
    this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
    this.disableHoriz = new Delayed
    this.disableVert = new Delayed
  }

  enableZeroWidthBar(bar, delay) {
    bar.style.pointerEvents = "auto"
    function maybeDisable() {
      // To find out whether the scrollbar is still visible, we
      // check whether the element under the pixel in the bottom
      // left corner of the scrollbar box is the scrollbar box
      // itself (when the bar is still visible) or its filler child
      // (when the bar is hidden). If it is still visible, we keep
      // it enabled, if it's hidden, we disable pointer events.
      let box = bar.getBoundingClientRect()
      let elt = document.elementFromPoint(box.left + 1, box.bottom - 1)
      if (elt != bar) bar.style.pointerEvents = "none"
      else delay.set(1000, maybeDisable)
    }
    delay.set(1000, maybeDisable)
  }

  clear() {
    let parent = this.horiz.parentNode
    parent.removeChild(this.horiz)
    parent.removeChild(this.vert)
  }
}

class NullScrollbars {
  update() { return {bottom: 0, right: 0} }
  setScrollLeft() {}
  setScrollTop() {}
  clear() {}
}

export function updateScrollbars(cm, measure) {
  if (!measure) measure = measureForScrollbars(cm)
  let startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
  updateScrollbarsInner(cm, measure)
  for (let i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
      updateHeightsInViewport(cm)
    updateScrollbarsInner(cm, measureForScrollbars(cm))
    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
  }
}

// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner(cm, measure) {
  let d = cm.display
  let sizes = d.scrollbars.update(measure)

  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
  d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"

  if (sizes.right && sizes.bottom) {
    d.scrollbarFiller.style.display = "block"
    d.scrollbarFiller.style.height = sizes.bottom + "px"
    d.scrollbarFiller.style.width = sizes.right + "px"
  } else d.scrollbarFiller.style.display = ""
  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
    d.gutterFiller.style.display = "block"
    d.gutterFiller.style.height = sizes.bottom + "px"
    d.gutterFiller.style.width = measure.gutterWidth + "px"
  } else d.gutterFiller.style.display = ""
}

export let scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}

export function initScrollbars(cm) {
  if (cm.display.scrollbars) {
    cm.display.scrollbars.clear()
    if (cm.display.scrollbars.addClass)
      rmClass(cm.display.wrapper, cm.display.scrollbars.addClass)
  }

  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](node => {
    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
    // Prevent clicks in the scrollbars from killing focus
    on(node, "mousedown", () => {
      if (cm.state.focused) setTimeout(() => cm.display.input.focus(), 0)
    })
    node.setAttribute("cm-not-content", "true")
  }, (pos, axis) => {
    if (axis == "horizontal") setScrollLeft(cm, pos)
    else setScrollTop(cm, pos)
  }, cm)
  if (cm.display.scrollbars.addClass)
    addClass(cm.display.wrapper, cm.display.scrollbars.addClass)
}
<|endoftext|>


<commit_before>/** ****************************************************************************
 * Select
 *
 * @author       Isaac Suttell <isaac_suttell@playstation.sony.com>
 * @file         Render a <select>
 * @flow
 ******************************************************************************/
'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import classNames from 'classnames';

import SelectOption from './SelectOption';
import OutsideClick from 'ship-components-outsideclick';
import HighlightClick from 'ship-components-highlight-click';

import dispatch from './lib/dispatch';
import scrollIntoView from './lib/scrollIntoView';

import cssClassNames from './select.css';

export default class Select extends React.Component {
  /**
   * Setup
   */
  constructor(props) {
    super(props);

    this.state = {
      active: false,
      fixedDropdownStyle: {
        top: 'inherit',
        width: 'inherit',
        position: 'fixed'
      }
    };

    this.handleClose = this.handleClose.bind(this);
    this.handleToggleActive = this.handleToggleActive.bind(this);
  }

  componentDidMount() {
    if (typeof this.props.scrollParentClass === 'string') {
      this.registerScrollParent(this.props.scrollParentClass);
      window.addEventListener('resize', this.handleClose);
    }
  }

  /**
   * Performance Check
   */
  shouldComponentUpdate(nextProps, nextState) {
    const props = ['value', 'label', 'disabled'];
    return nextProps.forceUpdate || props.some(
      key => this.props[key] !== nextProps[key]) ||
      this.state.active !== nextState.active ||
      this.fixedDropdownStyleChanged(nextState.fixedDropdownStyle) ||
      this.props.options.length !== nextProps.options.length ||
      this.props.options.some((opt, i) => {
        if (typeof opt === 'object') {
          return !!opt.render || opt.value !== nextProps.options[i].value;
        } else {
          return opt !== nextProps.options[i];
        }
      });
  }

  /**
   * Try to keep the selected comp in view
   */
  componentDidUpdate(prevProps, prevState) {
    if (this.shouldScrollToOption(prevState)) {
      scrollIntoView(ReactDOM.findDOMNode(this.refs.selected));
    }

    // when showing drop down, update the positioning styles
    if (this.props.scrollParentClass && !prevState.active && this.state.active) {
      // Disables the eslint warning (no-did-update-set-state)
      // Since we have an IF clause to prevents react from infinite loop
      // More info: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md
      this.setState(this.getDropdownStyle()); // eslint-disable-line
    }
  }

  componentWillUnmount() {
    if (this.scrollParent) {
      this.scrollParent.removeEventListener('scroll', this.handleClose);
      window.removeEventListener('resize', this.handleClose);
    }
  }

  shouldScrollToOption(prevState) {
    return this.props.options.length > 5 && this.refs.selected && prevState.active === false && this.state.active === true;
  }

  registerScrollParent(parentClass) {
    let ancestor = ReactDOM.findDOMNode(this.refs.list).parentNode;
    while (ancestor && ancestor !== document) {
      if (ancestor.classList.contains(parentClass)) {
        ancestor.addEventListener('scroll', this.handleClose);
        this.scrollParent = ancestor;
        return;
      }
      ancestor = ancestor.parentNode;
    }
  }

  getDropdownStyle() {
    if (!this.scrollParent) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn('<Select /> must have scrollParent to use getDropdownStyle()');
      }
      return;
    }
    // <select> component
    let parent = ReactDOM.findDOMNode(this.refs.parent);
    // Dropdown

    let dropdownList = this.refs.list;
    // Browser window height
    let windowHeight = window.innerHeight;

    let source = parent;
    let offsetTop = 0;
    let scrollParentTop = this.scrollParent.scrollTop;

    while (source) {
      offsetTop += source.offsetTop;
      source = source.offsetParent;
    }
    // re-adjust the offset value if dropdown options are not visible inside the window
    if (dropdownList.clientHeight + offsetTop > windowHeight) {
      let offsetFromBottom = (dropdownList.clientHeight + offsetTop) - windowHeight;
      offsetTop -= offsetFromBottom;
    }

    return {
      fixedDropdownStyle: {
        width: `${parent.offsetWidth}px`,
        position: 'fixed',
        top: `${(offsetTop - scrollParentTop)}px`
      }
    };
  }

  fixedDropdownStyleChanged(nextStyle) {
    for (let key in this.state.fixedDropdownStyle) {
      if (this.state.fixedDropdownStyle.hasOwnProperty(key)) {
        if (this.state.fixedDropdownStyle[key] !== nextStyle[key]) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Update the state and parent data
   *
   * @param     {Event}    event
   */
  handleChange(event) {
    this.updateState(event.target.value);
  }

  /**
   * Handle clicking a item in the list
   *
   * @param     {String}    value
   */
  handleClickItem(value) {
    this.updateState(value);
  }

  /**
   * Update the state and call our parent onChange event
   *
   * @param     {String}    value
   */
  updateState(value) {
    this.setState({
      active: false
    }, () => {
      if (this.props.disabled === true) {
        return;
      }
      this.refs.input.value = value;
      dispatch(this.refs.input, this.props.onChange);
    });
  }

  /**
   * Toggle open
   */
  handleToggleActive() {
    if (!this.props.disabled) {
      this.setState({active: !this.state.active});
    }
  }

  handleClose() {
    // Calling setState on an unmounted component will
    // trigger a React warning....
    // Checking the refs to make sure the component is mounted first
    if (this.refs.input) {
      this.setState({
        active: false
      });
    }
    return;
  }

  getOptions() {
    let opts = this.props.options;

    // Ensure we always deal with an array of objects
    if (typeof this.props.options[0] === 'string') {
      opts = this.props.options.map(opt => ({
        label: opt,
        value: opt
      }));
    }

    return opts;
  }

  getCurrentValue(opts) {
    return opts.find((option) => {
      if (typeof this.props.value === 'object') {
        return option.value === this.props.value.value;
      } else {
        return option.value === this.props.value;
      }
    });
  }

  renderLabel() {
    return this.props.label.length > 0 ?

        {this.props.label}

      : null;
  }
  /**
   * Render
   *
   * @return    {React}
   */
  render() {
    // Ensure it's an array of objects
    const opts = this.getOptions();

    // Grab the current value from the list of options
    const currentValue = this.getCurrentValue(opts) || {};

    // css class names
    const containerClasses = classNames(
      'select',
      this.props.className,
      cssClassNames.container,
      {
        [cssClassNames.disabled]: this.props.disabled,
        [cssClassNames.active]: this.state.active
      }
    );

    const listStyle = this.props.scrollParentClass && this.state.active ? this.state.fixedDropdownStyle : {};

    return (
      <OutsideClick
        ref='parent'
        className={containerClasses}
        onClick={this.handleClose}
      >
        {this.renderLabel()}
        <HighlightClick
          className={'select--control ' + cssClassNames.control}
          onClick={this.handleToggleActive}
          disabled={this.props.disabled}
        >

{currentValue.render || currentValue.label}

          {this.props.icon !== null ?
            React.cloneElement(this.props.icon, {
              className: this.props.icon.props.className + ' select--value-icon ' + cssClassNames.icon
            })
            :

          }
        </HighlightClick>

          {(this.state.active ? opts : []).map(option => (
            <SelectOption
              {...option}
              tag='li'
              ref={option.value === currentValue.value ? 'selected' : void 0}
              selected={option.value === currentValue.value}
              onClick={this.handleClickItem.bind(this, option.value)} //eslint-disable-line
              key={option.key || option.value}
            />
          ))}

        <select
          ref='input'
          readOnly
          value={this.props.value}
          style={{display : 'none'}}
        >
          {opts.map(option => (
            <SelectOption
              {...option}
              selected={option.value === currentValue.value}
              key={option.key || option.value}
            />
          ))}
        </select>
      </OutsideClick>
    );
  }
}

/**
 * Defaults
 * @type {Object}
 */
Select.defaultProps = {
  iconClass: 'icon-keyboard_arrow_down',
  className: '',
  icon: null,
  label: '',
  disabled: false,
  value: '',
  options: [],
  scrollParentClass: '',
  onChange: void 0
};

/**
 * Type checking
 * @type {Object}
 */
Select.propTypes = {
  className: PropTypes.string,
  iconClass: PropTypes.string,
  icon: PropTypes.element,
  label: PropTypes.string,
  disabled: PropTypes.bool,
  scrollParentClass: PropTypes.string,
  value: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ]),
  options: PropTypes.array.isRequired,
  onChange: PropTypes.func
};
<commit_msg>Adds the prop validation for select.js<commit_after>/** ****************************************************************************
 * Select
 *
 * @author       Isaac Suttell <isaac_suttell@playstation.sony.com>
 * @file         Render a <select>
 * @flow
 ******************************************************************************/
'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import classNames from 'classnames';

import SelectOption from './SelectOption';
import OutsideClick from 'ship-components-outsideclick';
import HighlightClick from 'ship-components-highlight-click';

import dispatch from './lib/dispatch';
import scrollIntoView from './lib/scrollIntoView';

import cssClassNames from './select.css';

export default class Select extends React.Component {
  /**
   * Setup
   */
  constructor(props) {
    super(props);

    this.state = {
      active: false,
      fixedDropdownStyle: {
        top: 'inherit',
        width: 'inherit',
        position: 'fixed'
      }
    };

    this.handleClose = this.handleClose.bind(this);
    this.handleToggleActive = this.handleToggleActive.bind(this);
  }

  componentDidMount() {
    if (typeof this.props.scrollParentClass === 'string') {
      this.registerScrollParent(this.props.scrollParentClass);
      window.addEventListener('resize', this.handleClose);
    }
  }

  /**
   * Performance Check
   */
  shouldComponentUpdate(nextProps, nextState) {
    const propsToCheck = ['value', 'label', 'disabled'];
    return nextProps.forceUpdate || propsToCheck.some(
      key => this.props[key] !== nextProps[key]) ||
      this.state.active !== nextState.active ||
      this.fixedDropdownStyleChanged(nextState.fixedDropdownStyle) ||
      this.props.options.length !== nextProps.options.length ||
      this.props.options.some((opt, i) => {
        if (typeof opt === 'object') {
          return !!opt.render || opt.value !== nextProps.options[i].value;
        } else {
          return opt !== nextProps.options[i];
        }
      });
  }

  /**
   * Try to keep the selected comp in view
   */
  componentDidUpdate(prevProps, prevState) {
    if (this.shouldScrollToOption(prevState)) {
      scrollIntoView(ReactDOM.findDOMNode(this.refs.selected));
    }

    // when showing drop down, update the positioning styles
    if (this.props.scrollParentClass && !prevState.active && this.state.active) {
      // Disables the eslint warning (no-did-update-set-state)
      // Since we have an IF clause to prevents react from infinite loop
      // More info: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md
      this.setState(this.getDropdownStyle()); // eslint-disable-line
    }
  }

  componentWillUnmount() {
    if (this.scrollParent) {
      this.scrollParent.removeEventListener('scroll', this.handleClose);
      window.removeEventListener('resize', this.handleClose);
    }
  }

  shouldScrollToOption(prevState) {
    return this.props.options.length > 5 && this.refs.selected && prevState.active === false && this.state.active === true;
  }

  registerScrollParent(parentClass) {
    let ancestor = ReactDOM.findDOMNode(this.refs.list).parentNode;
    while (ancestor && ancestor !== document) {
      if (ancestor.classList.contains(parentClass)) {
        ancestor.addEventListener('scroll', this.handleClose);
        this.scrollParent = ancestor;
        return;
      }
      ancestor = ancestor.parentNode;
    }
  }

  getDropdownStyle() {
    if (!this.scrollParent) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn('<Select /> must have scrollParent to use getDropdownStyle()');
      }
      return;
    }
    // <select> component
    let parent = ReactDOM.findDOMNode(this.refs.parent);
    // Dropdown

    let dropdownList = this.refs.list;
    // Browser window height
    let windowHeight = window.innerHeight;

    let source = parent;
    let offsetTop = 0;
    let scrollParentTop = this.scrollParent.scrollTop;

    while (source) {
      offsetTop += source.offsetTop;
      source = source.offsetParent;
    }
    // re-adjust the offset value if dropdown options are not visible inside the window
    if (dropdownList.clientHeight + offsetTop > windowHeight) {
      let offsetFromBottom = (dropdownList.clientHeight + offsetTop) - windowHeight;
      offsetTop -= offsetFromBottom;
    }

    return {
      fixedDropdownStyle: {
        width: `${parent.offsetWidth}px`,
        position: 'fixed',
        top: `${(offsetTop - scrollParentTop)}px`
      }
    };
  }

  fixedDropdownStyleChanged(nextStyle) {
    for (let key in this.state.fixedDropdownStyle) {
      if (this.state.fixedDropdownStyle.hasOwnProperty(key)) {
        if (this.state.fixedDropdownStyle[key] !== nextStyle[key]) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Update the state and parent data
   *
   * @param     {Event}    event
   */
  handleChange(event) {
    this.updateState(event.target.value);
  }

  /**
   * Handle clicking a item in the list
   *
   * @param     {String}    value
   */
  handleClickItem(value) {
    this.updateState(value);
  }

  /**
   * Update the state and call our parent onChange event
   *
   * @param     {String}    value
   */
  updateState(value) {
    this.setState({
      active: false
    }, () => {
      if (this.props.disabled === true) {
        return;
      }
      this.refs.input.value = value;
      dispatch(this.refs.input, this.props.onChange);
    });
  }

  /**
   * Toggle open
   */
  handleToggleActive() {
    if (!this.props.disabled) {
      this.setState({active: !this.state.active});
    }
  }

  handleClose() {
    // Calling setState on an unmounted component will
    // trigger a React warning....
    // Checking the refs to make sure the component is mounted first
    if (this.refs.input) {
      this.setState({
        active: false
      });
    }
    return;
  }

  getOptions() {
    let opts = this.props.options;

    // Ensure we always deal with an array of objects
    if (typeof this.props.options[0] === 'string') {
      opts = this.props.options.map(opt => ({
        label: opt,
        value: opt
      }));
    }

    return opts;
  }

  getCurrentValue(opts) {
    return opts.find((option) => {
      if (typeof this.props.value === 'object') {
        return option.value === this.props.value.value;
      } else {
        return option.value === this.props.value;
      }
    });
  }

  renderLabel() {
    return this.props.label.length > 0 ?

        {this.props.label}

      : null;
  }
  /**
   * Render
   *
   * @return    {React}
   */
  render() {
    // Ensure it's an array of objects
    const opts = this.getOptions();

    // Grab the current value from the list of options
    const currentValue = this.getCurrentValue(opts) || {};

    // css class names
    const containerClasses = classNames(
      'select',
      this.props.className,
      cssClassNames.container,
      {
        [cssClassNames.disabled]: this.props.disabled,
        [cssClassNames.active]: this.state.active
      }
    );

    const listStyle = this.props.scrollParentClass && this.state.active ? this.state.fixedDropdownStyle : {};

    return (
      <OutsideClick
        ref='parent'
        className={containerClasses}
        onClick={this.handleClose}
      >
        {this.renderLabel()}
        <HighlightClick
          className={'select--control ' + cssClassNames.control}
          onClick={this.handleToggleActive}
          disabled={this.props.disabled}
        >

{currentValue.render || currentValue.label}

          {this.props.icon !== null ?
            React.cloneElement(this.props.icon, {
              className: this.props.icon.props.className + ' select--value-icon ' + cssClassNames.icon
            })
            :

          }
        </HighlightClick>

          {(this.state.active ? opts : []).map(option => (
            <SelectOption
              {...option}
              tag='li'
              ref={option.value === currentValue.value ? 'selected' : void 0}
              selected={option.value === currentValue.value}
              onClick={this.handleClickItem.bind(this, option.value)} //eslint-disable-line
              key={option.key || option.value}
            />
          ))}

        <select
          ref='input'
          readOnly
          value={this.props.value}
          style={{display : 'none'}}
        >
          {opts.map(option => (
            <SelectOption
              {...option}
              selected={option.value === currentValue.value}
              key={option.key || option.value}
            />
          ))}
        </select>
      </OutsideClick>
    );
  }
}

/**
 * Defaults
 * @type {Object}
 */
Select.defaultProps = {
  iconClass: 'icon-keyboard_arrow_down',
  className: '',
  icon: null,
  label: '',
  disabled: false,
  forceUpdate: false,
  value: '',
  options: [],
  scrollParentClass: '',
  onChange: void 0
};

/**
 * Type checking
 * @type {Object}
 */
Select.propTypes = {
  className: PropTypes.string,
  iconClass: PropTypes.string,
  icon: PropTypes.element,
  label: PropTypes.string,
  disabled: PropTypes.bool,
  forceUpdate: PropTypes.bool,
  scrollParentClass: PropTypes.string,
  value: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ]),
  options: PropTypes.array.isRequired,
  onChange: PropTypes.func
};
<|endoftext|>


<commit_before>'use strict';

var forEach = require('foreach');
var has = Object.prototype.hasOwnProperty;
var assign = require('object.assign');
var define = require('define-properties');
var entries = require('object.entries');

var testResults = function (t, iterator, expectedResults) {
	forEach(expectedResults, function (expected) {
		var result = iterator.next();
		t.equal(result.done, expected.done, 'result is ' + (expected.done ? '' : 'not ') + 'done');
		if (result.done) {
			t.equal(result.value, null, 'result value is null');
		} else {
			t.equal(Array.isArray(result.value), true, 'result value is an array');
			t.deepEqual(entries(result.value || {}), entries(expected.value || {}), 'result has the same entries');
			t.deepEqual(result.value, expected.value, 'result value is expected value');
		}
	});
};

module.exports = function (matchAll, regexMatchAll, t) {
	t.test('non-regexes', function (st) {
		var notRegexes = [null, undefined, NaN, 42, new Date(), {}, []];
		var str = 'abc';
		forEach(notRegexes, function (notRegex) {
			testResults(st, matchAll(str, notRegex), matchAll(str, String(notRegex)));
		});
		st.end();
	});

	t.test('passing a string instead of a regex', function (st) {
		var str = 'aabcaba';
		var regex = /a/;
		testResults(st, matchAll(str, regex), matchAll(str, regex.source));
		st.end();
	});

	t.test('ToString-able objects', function (st) {
		var str = 'aabc';
		var strObj = { toString: function () { return str; } };
		var regex = /[ac]/g;
		var expectedResults = [
			{ value: assign(['a'], { index: 0, input: str }), done: false },
			{ value: assign(['a'], { index: 1, input: str }), done: false },
			{ value: assign(['c'], { index: 3, input: str }), done: false },
			{ value: null, done: true }
		];
		testResults(st, matchAll(strObj, regex), expectedResults);
		st.end();
	});

	t.test('#flags', function (st) {
		st.test('without a flags property', function (s2t) {
			var str = 'aabc';
			var regex = /[ac]/g;
			if (define.supportsDescriptors) {
				Object.defineProperty(regex, 'flags', { value: undefined });
			}
			s2t.equal(regex.flags, undefined, 'regex has an undefined "flags" property');
			var expectedResults = [
				{ value: assign(['a'], { index: 0, input: str }), done: false },
				{ value: assign(['a'], { index: 1, input: str }), done: false },
				{ value: assign(['c'], { index: 3, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});

		st.test('with a static flags property', function (s2t) {
			var str = 'AaBC';
			var regex = /[ac]/;
			define(regex, { flags: 'ig' }, { flags: function () { return true; } });
			s2t.equal(regex.flags, 'ig');
			var expectedResults = [
				{ value: assign(['A'], { index: 0, input: str }), done: false },
				{ value: assign(['a'], { index: 1, input: str }), done: false },
				{ value: assign(['C'], { index: 3, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});

		st.test('respects flags', function (s2t) {
			var str = 'A\na\nb\nC';
			var regex = /^[ac]/img;
			var expectedResults = [
				{ value: assign(['A'], { index: 0, input: str }), done: false },
				{ value: assign(['a'], { index: 2, input: str }), done: false },
				{ value: assign(['C'], { index: 6, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});

		st.test('works with a non-global non-sticky regex', function (s2t) {
			var str = 'AaBbCc';
			var regex = /[bc]/i;
			var expectedResults = [
				{ value: assign(['B'], { index: 2, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});
	});

	t.test('returns an iterator', function (st) {
		var str = 'aabc';
		var iterator = matchAll(str, /[ac]/g);
		st.ok(iterator, 'iterator is truthy');
		st.equal(has.call(iterator, 'next'), false, 'iterator does not have own property "next"');
		for (var key in iterator) {
			st.fail('iterator has enumerable properties: ' + key);
		}
		var expectedResults = [
			{ value: assign(['a'], { index: 0, input: str }), done: false },
			{ value: assign(['a'], { index: 1, input: str }), done: false },
			{ value: assign(['c'], { index: 3, input: str }), done: false },
			{ value: null, done: true }
		];
		testResults(st, iterator, expectedResults);
		st.end();
	});
};
<commit_msg>[Tests] improve `testResults` function:<commit_after>'use strict';

var forEach = require('foreach');
var has = Object.prototype.hasOwnProperty;
var assign = require('object.assign');
var define = require('define-properties');
var entries = require('object.entries');

var testResults = function (t, iterator, expectedResults) {
	forEach(expectedResults, function (expected, index) {
		var result = iterator.next();
		t.equal(result.done, expected.done, 'result ' + (index + 1) + ' is ' + (expected.done ? '' : 'not ') + 'done');
		if (expected.done) {
			t.equal(result.value, null, 'result ' + (index + 1) + ' value is null');
		} else {
			t.equal(Array.isArray(result.value), true, 'result ' + (index + 1) + ' value is an array');
			t.deepEqual(entries(result.value || {}), entries(expected.value || {}), 'result ' + (index + 1) + ' has the same entries');
			t.deepEqual(result.value, expected.value, 'result ' + (index + 1) + ' value is expected value');
		}
	});
};

module.exports = function (matchAll, regexMatchAll, t) {
	t.test('non-regexes', function (st) {
		var notRegexes = [null, undefined, NaN, 42, new Date(), {}, []];
		var str = 'abc';
		forEach(notRegexes, function (notRegex) {
			testResults(st, matchAll(str, notRegex), matchAll(str, String(notRegex)));
		});
		st.end();
	});

	t.test('passing a string instead of a regex', function (st) {
		var str = 'aabcaba';
		var regex = /a/;
		testResults(st, matchAll(str, regex), matchAll(str, regex.source));
		st.end();
	});

	t.test('ToString-able objects', function (st) {
		var str = 'aabc';
		var strObj = { toString: function () { return str; } };
		var regex = /[ac]/g;
		var expectedResults = [
			{ value: assign(['a'], { index: 0, input: str }), done: false },
			{ value: assign(['a'], { index: 1, input: str }), done: false },
			{ value: assign(['c'], { index: 3, input: str }), done: false },
			{ value: null, done: true }
		];
		testResults(st, matchAll(strObj, regex), expectedResults);
		st.end();
	});

	t.test('#flags', function (st) {
		st.test('without a flags property', function (s2t) {
			var str = 'aabc';
			var regex = /[ac]/g;
			if (define.supportsDescriptors) {
				Object.defineProperty(regex, 'flags', { value: undefined });
			}
			s2t.equal(regex.flags, undefined, 'regex has an undefined "flags" property');
			var expectedResults = [
				{ value: assign(['a'], { index: 0, input: str }), done: false },
				{ value: assign(['a'], { index: 1, input: str }), done: false },
				{ value: assign(['c'], { index: 3, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});

		st.test('with a static flags property', function (s2t) {
			var str = 'AaBC';
			var regex = /[ac]/;
			define(regex, { flags: 'ig' }, { flags: function () { return true; } });
			s2t.equal(regex.flags, 'ig');
			var expectedResults = [
				{ value: assign(['A'], { index: 0, input: str }), done: false },
				{ value: assign(['a'], { index: 1, input: str }), done: false },
				{ value: assign(['C'], { index: 3, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});

		st.test('respects flags', function (s2t) {
			var str = 'A\na\nb\nC';
			var regex = /^[ac]/img;
			var expectedResults = [
				{ value: assign(['A'], { index: 0, input: str }), done: false },
				{ value: assign(['a'], { index: 2, input: str }), done: false },
				{ value: assign(['C'], { index: 6, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});

		st.test('works with a non-global non-sticky regex', function (s2t) {
			var str = 'AaBbCc';
			var regex = /[bc]/i;
			var expectedResults = [
				{ value: assign(['B'], { index: 2, input: str }), done: false },
				{ value: null, done: true }
			];
			testResults(s2t, matchAll(str, regex), expectedResults);
			s2t.end();
		});
	});

	t.test('returns an iterator', function (st) {
		var str = 'aabc';
		var iterator = matchAll(str, /[ac]/g);
		st.ok(iterator, 'iterator is truthy');
		st.equal(has.call(iterator, 'next'), false, 'iterator does not have own property "next"');
		for (var key in iterator) {
			st.fail('iterator has enumerable properties: ' + key);
		}
		var expectedResults = [
			{ value: assign(['a'], { index: 0, input: str }), done: false },
			{ value: assign(['a'], { index: 1, input: str }), done: false },
			{ value: assign(['c'], { index: 3, input: str }), done: false },
			{ value: null, done: true }
		];
		testResults(st, iterator, expectedResults);
		st.end();
	});
};
<|endoftext|>


<commit_before>// This file handles the management of the state for the image viewer.
// The image viewer is controlled via the OpenSeaDragon js lib.
import openseadragon from 'openseadragon'
import Vue from 'vue'

const state = {
  OSDviewer: null,
  OSDworld: null,
  images: [],
  activeChannel: 0,
  view: {
    viewSize: [null, null],
    imageSize: [null, null],
    imageCenter: [null, null],
    imageZoom: null
  }
}

const getters = {
  getMaxZoom: state => {
    if (state.OSDviewer) {
      return Math.round(state.OSDviewer.viewport.getMaxZoom())
    } else {
      return 10
    }
  },

  getZoom: state => {
    if (state.OSDviewer) {
      let zoom = state.OSDviewer.viewport.getZoom()

      if (zoom < 100) {
        return Math.round(zoom * 10) / 10
      } else {
        return Math.round(zoom)
      }
    } else {
      return 'na'
    }
  },

  getImageWidth: state => {
    if (state.OSDviewer) {
      if (state.OSDviewer.world.getItemCount() > 0) {
        return state.OSDviewer.world.getItemAt(0).getContentSize.x
      } else {
        return 0
      }
    }
  },

  getChannels: (state, getters, rootState) => {
    let channels = []

    if (state.OSDviewer) {
      let numChannels = state.OSDviewer.world.getItemCount()

      for (let i = 0; i < numChannels; i++) {
        channels.push({
          channel: state.OSDviewer.world.getItemAt(i),
          id: i,
          opacity: state.OSDviewer.world.getItemAt(i).getOpacity(),
          name: state.images[i].name,
          visible: state.OSDviewer.world.getItemAt(i).getOpacity() > 0,
          opacityCache: 0
        })
      }
    }
    return channels
  }
}

const actions = {
  resetImageState: ({
    commit,
    rootState
  }) => {
    commit('resetImageState', rootState)
  },

  setupOSDCanvas: ({
    commit
  }, payload) => {
    commit('setupOSDCanvas', payload)
  },

  // Load the images into the state and then add them to the appropriate OSDviewer
  loadImages: ({
    state,
    dispatch
  }, images) => {
    // Add the new images to the state and the OSD
    dispatch('addImagesToState', images).then(() => {
      // Add each image to the OSD viewer
      for (let i in images) {
        dispatch('addOSDImage', images[i])
      }
    })
  },

  addImagesToState: ({
    commit
  }, images) => {
    commit('addImagesToState', images)
  },

  addOSDImage: ({
    commit
  }, image) => {
    commit('addOSDImage', image)
  },

  setActiveChannel: ({
    commit
  }, payload) => {
    commit('setActiveChannel', payload)
  },

  toggleChannelOpacity: ({
    commit
  }, payload) => {
    commit('toggleChannelOpacity', payload)
  },

  setChannelOpacity: ({
    commit,
    rootState
  }, payload) => {
    commit('setChannelOpacity', {
      input: payload,
      activeChannel: rootState.editor.activeChannel,
      rootState: rootState
    })
  },

  setChannelName: ({
    commit,
    rootState
  }, payload) => {
    commit('setChannelName', payload)
  },

  setZoom: ({
    commit
  }, payload) => {
    commit('setZoom', payload)
  }
}

const mutations = {
  resetImageState: (state) => {
    // Destroy the openseadragon viewer
    state.OSDviewer.destroy()

    state = {
      OSDviewer: null,
      OSDworld: null,
      images: [],
      activeChannel: 0,
      view: {
        viewSize: [null, null],
        imageSize: [null, null],
        imageCenter: [null, null],
        imageZoom: null
      }
    }
  },

  // Setup an OpenSeaDragon OSDviewer.
  setupOSDCanvas: (state, payload) => {
    // Create and OSD viewer
    state.OSDviewer = new openseadragon.Viewer({
      id: payload,
      showNavigationControl: false,
      showNavigator: true,
      navigatorId: 'navigator'
    })

    // Add handlers to update the state when certain events are triggered on the
    // viewer. These state changes can be propagated through to the annotation
    // data to keep the two parts in sync.

    // At the moment not in use, would like to move towards this but
    // implementation was causing strange jitters in zoom and pan. Instead using
    // the viewport-updated handler in common.js

    // Resize
    // state.OSDviewer.addHandler('resize', function (e) {
    //   state.view.viewSize = [e.newContainerSize.x, e.newContainerSize.y]
    //   let centerPoint = state.OSDviewer.viewport.viewportToImageCoordinates(
    //     state.OSDviewer.viewport.getCenter(true)
    //   )
    //   state.view.imageCenter = [centerPoint.x, centerPoint.y]
    // })

    // // Zoom
    // state.OSDviewer.addHandler('zoom', function (e) {
    //   state.view.imageZoom = state.OSDviewer.viewport.viewportToImageZoom(
    //     state.OSDviewer.viewport.getZoom(true)
    //   )

    //   let centerPoint = state.OSDviewer.viewport.viewportToImageCoordinates(
    //     state.OSDviewer.viewport.getCenter(true)
    //   )
    //   state.view.imageCenter = [centerPoint.x, centerPoint.y]
    // })

    // // Pan
    // state.OSDviewer.addHandler('pan', function (e) {
    //   let centerPoint = state.OSDviewer.viewport.viewportToImageCoordinates(
    //     state.OSDviewer.viewport.getCenter(true)
    //   )
    //   state.view.imageCenter = [centerPoint.x, centerPoint.y]
    // })
  },

  // Add images to the state
  addImagesToState: (state, images) => {
    state.images = []
    for (let i in images) {
      state.images.push(images[i])
    }
  },

  // Add dzi images to OpenSeaDragon OSDviewer
  addOSDImage: (state, image) => {
    if (image.type === 'dzi') {
      state.OSDviewer.addTiledImage({
        tileSource: image.source,
        x: 0,
        y: 0,
        opacity: 1.0
      })
    } else if (image.type === 'simple') {
      state.OSDviewer.addSimpleImage({
        url: image.source,
        x: 0,
        y: 0,
        opacity: 1.0
      })
    }
  },

  setActiveChannel: (state, payload) => {
    state.activeChannel = payload
  },

  // Toggle the visibility of a channel.
  // TODO: build in some kind of cache of opacity so that when it is toggled
  // from not-visible to visible it can easily return to the state it was.
  toggleChannelOpacity: (state, payload) => {
    // Payload should be a Channel object as defined by getChannels().
    if (payload.opacity > 0) {
      payload.channel.setOpacity(0)
    } else {
      payload.channel.setOpacity(0.7)
    }
  },

  // Set channel visibility
  setChannelOpacity: (state, payload) => {
    let input = payload.input
    let newOpacity = 1 // Default

    // There are multiple ways to edit the opacity.
    // Handle each of the different inputs.
    // If passed an integer
    if (typeof input === 'string' || typeof input === 'number') {
      input = Number(input)
      if (input > 1) {
        newOpacity = input / 100
      } else {
        newOpacity = input
      }

      // If passed a keyboard event. (most likely enter key from a text edit.)
    } else if (input instanceof KeyboardEvent) {
      newOpacity = input.target.value / 100
    }

    // Set the new opacity level
    state.OSDviewer.world.getItemAt(state.activeChannel).setOpacity(newOpacity)
  },

  // Set the channel name
  setChannelName: (state, payload) => {
    let newName
    // Check if keyboard event. This happens in the case that the user types
    // the opacity value in the text box and hits enter
    if (payload instanceof KeyboardEvent) {
      newName = payload.target.value
    } else {
      newName = payload
    }

    // Save changes to Vuex state
    Vue.set(state.images[state.activeChannel], 'name', newName)
  },

  // Set the zoom level
  setZoom: (state, payload) => {
    let newZoom
    // Check if keyboard event. This happens in the case that the user types
    // the zoom value in the text box and hits enter
    if (payload instanceof KeyboardEvent) {
      newZoom = Number(payload.target.value)
    } else {
      newZoom = Number(payload)
    }

    if (typeof newZoom === 'number' && newZoom > 0) {
      state.OSDviewer.viewport.zoomTo(newZoom)
    }
  }

}

// Export all of the relevant logic so that it can be combined with the complete
// store and all other module logic.
export default {
  state,
  getters,
  actions,
  mutations
}
<commit_msg>Re-instate sync functionality for annotation and image<commit_after>// This file handles the management of the state for the image viewer.
// The image viewer is controlled via the OpenSeaDragon js lib.
import openseadragon from 'openseadragon'
import Vue from 'vue'

const state = {
  OSDviewer: null,
  OSDworld: null,
  images: [],
  activeChannel: 0,
  view: {
    viewSize: [null, null],
    imageSize: [null, null],
    imageCenter: [null, null],
    imageZoom: null
  }
}

const getters = {
  getMaxZoom: state => {
    if (state.OSDviewer) {
      return Math.round(state.OSDviewer.viewport.getMaxZoom())
    } else {
      return 10
    }
  },

  getZoom: state => {
    if (state.OSDviewer) {
      let zoom = state.OSDviewer.viewport.getZoom()

      if (zoom < 100) {
        return Math.round(zoom * 10) / 10
      } else {
        return Math.round(zoom)
      }
    } else {
      return 'na'
    }
  },

  getImageWidth: state => {
    if (state.OSDviewer) {
      if (state.OSDviewer.world.getItemCount() > 0) {
        return state.OSDviewer.world.getItemAt(0).getContentSize.x
      } else {
        return 0
      }
    }
  },

  getChannels: (state, getters, rootState) => {
    let channels = []

    if (state.OSDviewer) {
      let numChannels = state.OSDviewer.world.getItemCount()

      for (let i = 0; i < numChannels; i++) {
        channels.push({
          channel: state.OSDviewer.world.getItemAt(i),
          id: i,
          opacity: state.OSDviewer.world.getItemAt(i).getOpacity(),
          name: state.images[i].name,
          visible: state.OSDviewer.world.getItemAt(i).getOpacity() > 0,
          opacityCache: 0
        })
      }
    }
    return channels
  }
}

const actions = {
  resetImageState: ({
    commit,
    rootState
  }) => {
    commit('resetImageState', rootState)
  },

  setupOSDCanvas: ({
    commit
  }, payload) => {
    commit('setupOSDCanvas', payload)
  },

  // Load the images into the state and then add them to the appropriate OSDviewer
  loadImages: ({
    state,
    dispatch
  }, images) => {
    // Add the new images to the state and the OSD
    dispatch('addImagesToState', images).then(() => {
      // Add each image to the OSD viewer
      for (let i in images) {
        dispatch('addOSDImage', images[i])
      }
    })
  },

  addImagesToState: ({
    commit
  }, images) => {
    commit('addImagesToState', images)
  },

  addOSDImage: ({
    commit
  }, image) => {
    commit('addOSDImage', image)
  },

  setActiveChannel: ({
    commit
  }, payload) => {
    commit('setActiveChannel', payload)
  },

  toggleChannelOpacity: ({
    commit
  }, payload) => {
    commit('toggleChannelOpacity', payload)
  },

  setChannelOpacity: ({
    commit,
    rootState
  }, payload) => {
    commit('setChannelOpacity', {
      input: payload,
      activeChannel: rootState.editor.activeChannel,
      rootState: rootState
    })
  },

  setChannelName: ({
    commit,
    rootState
  }, payload) => {
    commit('setChannelName', payload)
  },

  setZoom: ({
    commit
  }, payload) => {
    commit('setZoom', payload)
  }
}

const mutations = {
  resetImageState: (state) => {
    // Destroy the openseadragon viewer
    state.OSDviewer.destroy()

    state = {
      OSDviewer: null,
      OSDworld: null,
      images: [],
      activeChannel: 0,
      view: {
        viewSize: [null, null],
        imageSize: [null, null],
        imageCenter: [null, null],
        imageZoom: null
      }
    }
  },

  // Setup an OpenSeaDragon OSDviewer.
  setupOSDCanvas: (state, payload) => {
    // Create and OSD viewer
    state.OSDviewer = new openseadragon.Viewer({
      id: payload,
      showNavigationControl: false,
      showNavigator: true,
      navigatorId: 'navigator'
    })

    // Add handlers to update the state when certain events are triggered on the
    // viewer. These state changes can be propagated through to the annotation
    // data to keep the two parts in sync.

    // Resize
    state.OSDviewer.addHandler('resize', function (e) {
      state.view.viewSize = [e.newContainerSize.x, e.newContainerSize.y]
      let centerPoint = state.OSDviewer.viewport.viewportToImageCoordinates(
        state.OSDviewer.viewport.getCenter(true)
      )
      state.view.imageCenter = [centerPoint.x, centerPoint.y]
    })

    // Zoom
    state.OSDviewer.addHandler('zoom', function (e) {
      state.view.imageZoom = state.OSDviewer.viewport.viewportToImageZoom(
        state.OSDviewer.viewport.getZoom(true)
      )

      let centerPoint = state.OSDviewer.viewport.viewportToImageCoordinates(
        state.OSDviewer.viewport.getCenter(true)
      )
      state.view.imageCenter = [centerPoint.x, centerPoint.y]
    })

    // Pan
    state.OSDviewer.addHandler('pan', function (e) {
      let centerPoint = state.OSDviewer.viewport.viewportToImageCoordinates(
        state.OSDviewer.viewport.getCenter(true)
      )
      state.view.imageCenter = [centerPoint.x, centerPoint.y]
    })
  },

  // Add images to the state
  addImagesToState: (state, images) => {
    state.images = []
    for (let i in images) {
      state.images.push(images[i])
    }
  },

  // Add dzi images to OpenSeaDragon OSDviewer
  addOSDImage: (state, image) => {
    if (image.type === 'dzi') {
      state.OSDviewer.addTiledImage({
        tileSource: image.source,
        x: 0,
        y: 0,
        opacity: 1.0
      })
    } else if (image.type === 'simple') {
      state.OSDviewer.addSimpleImage({
        url: image.source,
        x: 0,
        y: 0,
        opacity: 1.0
      })
    }
  },

  setActiveChannel: (state, payload) => {
    state.activeChannel = payload
  },

  // Toggle the visibility of a channel.
  // TODO: build in some kind of cache of opacity so that when it is toggled
  // from not-visible to visible it can easily return to the state it was.
  toggleChannelOpacity: (state, payload) => {
    // Payload should be a Channel object as defined by getChannels().
    if (payload.opacity > 0) {
      payload.channel.setOpacity(0)
    } else {
      payload.channel.setOpacity(0.7)
    }
  },

  // Set channel visibility
  setChannelOpacity: (state, payload) => {
    let input = payload.input
    let newOpacity = 1 // Default

    // There are multiple ways to edit the opacity.
    // Handle each of the different inputs.
    // If passed an integer
    if (typeof input === 'string' || typeof input === 'number') {
      input = Number(input)
      if (input > 1) {
        newOpacity = input / 100
      } else {
        newOpacity = input
      }

      // If passed a keyboard event. (most likely enter key from a text edit.)
    } else if (input instanceof KeyboardEvent) {
      newOpacity = input.target.value / 100
    }

    // Set the new opacity level
    state.OSDviewer.world.getItemAt(state.activeChannel).setOpacity(newOpacity)
  },

  // Set the channel name
  setChannelName: (state, payload) => {
    let newName
    // Check if keyboard event. This happens in the case that the user types
    // the opacity value in the text box and hits enter
    if (payload instanceof KeyboardEvent) {
      newName = payload.target.value
    } else {
      newName = payload
    }

    // Save changes to Vuex state
    Vue.set(state.images[state.activeChannel], 'name', newName)
  },

  // Set the zoom level
  setZoom: (state, payload) => {
    let newZoom
    // Check if keyboard event. This happens in the case that the user types
    // the zoom value in the text box and hits enter
    if (payload instanceof KeyboardEvent) {
      newZoom = Number(payload.target.value)
    } else {
      newZoom = Number(payload)
    }

    if (typeof newZoom === 'number' && newZoom > 0) {
      state.OSDviewer.viewport.zoomTo(newZoom)
    }
  }

}

// Export all of the relevant logic so that it can be combined with the complete
// store and all other module logic.
export default {
  state,
  getters,
  actions,
  mutations
}
<|endoftext|>