<commit_before>/**
 * Copyright (C) 2019-2020  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

let origin, originBadgeUrl, originBrowseUrl;
let url, urlPrefix;
let cntSWHID, cntSWHIDWithContext;
let dirSWHID, dirSWHIDWithContext;
let relSWHID, relSWHIDWithContext;
let revSWHID, revSWHIDWithContext;
let snpSWHID, snpSWHIDWithContext;
let testsData;
const firstSelLine = 6;
const lastSelLine = 12;

describe('Persistent Identifiers Tests', function() {

  before(function() {
    origin = this.origin[1];
    url = `${this.Urls.browse_origin_content()}?origin_url=${origin.url}&path=${origin.content[0].path}`;
    url = `${url}&release=${origin.release.name}#L${firstSelLine}-L${lastSelLine}`;
    originBadgeUrl = this.Urls.swh_badge('origin', origin.url);
    originBrowseUrl = `${this.Urls.browse_origin()}?origin_url=${origin.url}`;
    cy.visit(url).window().then(win => {
      urlPrefix = `${win.location.protocol}//${win.location.hostname}`;
      if (win.location.port) {
        urlPrefix += `:${win.location.port}`;
      }
      const swhids = win.swh.webapp.getSwhIdsContext();
      cntSWHID = swhids.content.swhid;
      cntSWHIDWithContext = swhids.content.swhid_with_context;
      cntSWHIDWithContext += `;lines=${firstSelLine}-${lastSelLine}`;
      dirSWHID = swhids.directory.swhid;
      dirSWHIDWithContext = swhids.directory.swhid_with_context;
      revSWHID = swhids.revision.swhid;
      revSWHIDWithContext = swhids.revision.swhid_with_context;
      relSWHID = swhids.release.swhid;
      relSWHIDWithContext = swhids.release.swhid_with_context;
      snpSWHID = swhids.snapshot.swhid;
      snpSWHIDWithContext = swhids.snapshot.swhid_with_context;

      testsData = [
        {
          'objectType': 'content',
          'objectSWHIDs': [cntSWHIDWithContext, cntSWHID],
          'badgeUrl': this.Urls.swh_badge('content', swhids.content.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(cntSWHID),
          'browseUrl': this.Urls.browse_swhid(cntSWHIDWithContext)
        },
        {
          'objectType': 'directory',
          'objectSWHIDs': [dirSWHIDWithContext, dirSWHID],
          'badgeUrl': this.Urls.swh_badge('directory', swhids.directory.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(dirSWHID),
          'browseUrl': this.Urls.browse_swhid(dirSWHIDWithContext)
        },
        {
          'objectType': 'release',
          'objectSWHIDs': [relSWHIDWithContext, relSWHID],
          'badgeUrl': this.Urls.swh_badge('release', swhids.release.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(relSWHID),
          'browseUrl': this.Urls.browse_swhid(relSWHIDWithContext)
        },
        {
          'objectType': 'revision',
          'objectSWHIDs': [revSWHIDWithContext, revSWHID],
          'badgeUrl': this.Urls.swh_badge('revision', swhids.revision.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(revSWHID),
          'browseUrl': this.Urls.browse_swhid(revSWHIDWithContext)
        },
        {
          'objectType': 'snapshot',
          'objectSWHIDs': [snpSWHIDWithContext, snpSWHID],
          'badgeUrl': this.Urls.swh_badge('snapshot', swhids.snapshot.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(snpSWHID),
          'browseUrl': this.Urls.browse_swhid(snpSWHIDWithContext)
        }
      ];

    });
  });

  beforeEach(function() {
    cy.visit(url);
  });

  it('should open and close identifiers tab when clicking on handle', function() {
    cy.get('#swh-identifiers')
      .should('have.class', 'ui-slideouttab-ready');

    cy.get('.ui-slideouttab-handle')
      .click();

    cy.get('#swh-identifiers')
      .should('have.class', 'ui-slideouttab-open');

    cy.get('.ui-slideouttab-handle')
      .click();

    cy.get('#swh-identifiers')
      .should('not.have.class', 'ui-slideouttab-open');

  });

  it('should display identifiers with permalinks for browsed objects', function() {
    cy.get('.ui-slideouttab-handle')
      .click();

    for (const td of testsData) {
      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType}`)
        .should('be.visible');

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .should('have.text', td.objectSWHIDs[0].replace(/;/g, ';\n'))
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[0]));

    }

  });

  it('should update other object identifiers contextual info when toggling context checkbox', function() {
    cy.get('.ui-slideouttab-handle')
      .click();

    for (const td of testsData) {

      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .should('have.text', td.objectSWHIDs[0].replace(/;/g, ';\n'))
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[0]));

      cy.get(`#swhid-tab-${td.objectType} .swhid-option`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .contains(td.objectSWHIDs[1])
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[1]));

      cy.get(`#swhid-tab-${td.objectType} .swhid-option`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .should('have.text', td.objectSWHIDs[0].replace(/;/g, ';\n'))
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[0]));
    }

  });

  it('should display swh badges in identifiers tab for browsed objects', function() {
    cy.get('.ui-slideouttab-handle')
      .click();

    const originBadgeUrl = this.Urls.swh_badge('origin', origin.url);

    for (const td of testsData) {
      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-origin`)
        .should('have.attr', 'src', originBadgeUrl);

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-${td.objectType}`)
        .should('have.attr', 'src', td.badgeUrl);

    }

  });

  it('should display badge integration info when clicking on it', function() {

    cy.get('.ui-slideouttab-handle')
      .click();

    for (const td of testsData) {
      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-origin`)
        .click()
        .wait(500);

      for (const badgeType of ['html', 'md', 'rst']) {
        cy.get(`.modal .swh-badge-${badgeType}`)
          .should('contain.text', `${urlPrefix}${originBrowseUrl}`)
          .should('contain.text', `${urlPrefix}${originBadgeUrl}`);
      }

      cy.get('.modal.show .close')
        .click()
        .wait(500);

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-${td.objectType}`)
        .click()
        .wait(500);

      for (const badgeType of ['html', 'md', 'rst']) {
        cy.get(`.modal .swh-badge-${badgeType}`)
          .should('contain.text', `${urlPrefix}${td.browseUrl}`)
          .should('contain.text', `${urlPrefix}${td.badgeSWHIDUrl}`);
      }

      cy.get('.modal.show .close')
        .click()
        .wait(500);

    }
  });

  it('should be possible to retrieve SWHIDs context from JavaScript', function() {
    cy.window().then(win => {
      const swhIdsContext = win.swh.webapp.getSwhIdsContext();
      for (const testData of testsData) {
        assert.isTrue(swhIdsContext.hasOwnProperty(testData.objectType));
        assert.equal(swhIdsContext[testData.objectType].swhid,
                     testData.objectSWHIDs.slice(-1)[0]);
      }
    });
  });

});
<commit_msg>cypress/persistent-identifiers: Workaround tests hang issue<commit_after>/**
 * Copyright (C) 2019-2020  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

let origin, originBadgeUrl, originBrowseUrl;
let url, urlPrefix;
let cntSWHID, cntSWHIDWithContext;
let dirSWHID, dirSWHIDWithContext;
let relSWHID, relSWHIDWithContext;
let revSWHID, revSWHIDWithContext;
let snpSWHID, snpSWHIDWithContext;
let testsData;
const firstSelLine = 6;
const lastSelLine = 12;

describe('Persistent Identifiers Tests', function() {

  before(function() {
    origin = this.origin[1];
    url = `${this.Urls.browse_origin_content()}?origin_url=${origin.url}&path=${origin.content[0].path}`;
    url = `${url}&release=${origin.release.name}#L${firstSelLine}-L${lastSelLine}`;
    originBadgeUrl = this.Urls.swh_badge('origin', origin.url);
    originBrowseUrl = `${this.Urls.browse_origin()}?origin_url=${origin.url}`;
    cy.visit(url).window().then(win => {
      urlPrefix = `${win.location.protocol}//${win.location.hostname}`;
      if (win.location.port) {
        urlPrefix += `:${win.location.port}`;
      }
      // for some reasons, cypress hangs when visiting that URL in beforeEach callback
      // due to HTTP redirection, so get the redirected URL here to workaround that issue.
      url = win.location.href;
      const swhids = win.swh.webapp.getSwhIdsContext();
      cntSWHID = swhids.content.swhid;
      cntSWHIDWithContext = swhids.content.swhid_with_context;
      cntSWHIDWithContext += `;lines=${firstSelLine}-${lastSelLine}`;
      dirSWHID = swhids.directory.swhid;
      dirSWHIDWithContext = swhids.directory.swhid_with_context;
      revSWHID = swhids.revision.swhid;
      revSWHIDWithContext = swhids.revision.swhid_with_context;
      relSWHID = swhids.release.swhid;
      relSWHIDWithContext = swhids.release.swhid_with_context;
      snpSWHID = swhids.snapshot.swhid;
      snpSWHIDWithContext = swhids.snapshot.swhid_with_context;

      testsData = [
        {
          'objectType': 'content',
          'objectSWHIDs': [cntSWHIDWithContext, cntSWHID],
          'badgeUrl': this.Urls.swh_badge('content', swhids.content.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(cntSWHID),
          'browseUrl': this.Urls.browse_swhid(cntSWHIDWithContext)
        },
        {
          'objectType': 'directory',
          'objectSWHIDs': [dirSWHIDWithContext, dirSWHID],
          'badgeUrl': this.Urls.swh_badge('directory', swhids.directory.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(dirSWHID),
          'browseUrl': this.Urls.browse_swhid(dirSWHIDWithContext)
        },
        {
          'objectType': 'release',
          'objectSWHIDs': [relSWHIDWithContext, relSWHID],
          'badgeUrl': this.Urls.swh_badge('release', swhids.release.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(relSWHID),
          'browseUrl': this.Urls.browse_swhid(relSWHIDWithContext)
        },
        {
          'objectType': 'revision',
          'objectSWHIDs': [revSWHIDWithContext, revSWHID],
          'badgeUrl': this.Urls.swh_badge('revision', swhids.revision.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(revSWHID),
          'browseUrl': this.Urls.browse_swhid(revSWHIDWithContext)
        },
        {
          'objectType': 'snapshot',
          'objectSWHIDs': [snpSWHIDWithContext, snpSWHID],
          'badgeUrl': this.Urls.swh_badge('snapshot', swhids.snapshot.object_id),
          'badgeSWHIDUrl': this.Urls.swh_badge_swhid(snpSWHID),
          'browseUrl': this.Urls.browse_swhid(snpSWHIDWithContext)
        }
      ];

    });
  });

  beforeEach(function() {
    cy.visit(url);
  });

  it('should open and close identifiers tab when clicking on handle', function() {
    cy.get('#swh-identifiers')
      .should('have.class', 'ui-slideouttab-ready');

    cy.get('.ui-slideouttab-handle')
      .click();

    cy.get('#swh-identifiers')
      .should('have.class', 'ui-slideouttab-open');

    cy.get('.ui-slideouttab-handle')
      .click();

    cy.get('#swh-identifiers')
      .should('not.have.class', 'ui-slideouttab-open');

  });

  it('should display identifiers with permalinks for browsed objects', function() {
    cy.get('.ui-slideouttab-handle')
      .click();

    for (const td of testsData) {
      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType}`)
        .should('be.visible');

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .should('have.text', td.objectSWHIDs[0].replace(/;/g, ';\n'))
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[0]));

    }

  });

  it('should update other object identifiers contextual info when toggling context checkbox', function() {
    cy.get('.ui-slideouttab-handle')
      .click();

    for (const td of testsData) {

      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .should('have.text', td.objectSWHIDs[0].replace(/;/g, ';\n'))
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[0]));

      cy.get(`#swhid-tab-${td.objectType} .swhid-option`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .contains(td.objectSWHIDs[1])
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[1]));

      cy.get(`#swhid-tab-${td.objectType} .swhid-option`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swhid`)
        .should('have.text', td.objectSWHIDs[0].replace(/;/g, ';\n'))
        .should('have.attr', 'href', this.Urls.browse_swhid(td.objectSWHIDs[0]));
    }

  });

  it('should display swh badges in identifiers tab for browsed objects', function() {
    cy.get('.ui-slideouttab-handle')
      .click();

    const originBadgeUrl = this.Urls.swh_badge('origin', origin.url);

    for (const td of testsData) {
      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-origin`)
        .should('have.attr', 'src', originBadgeUrl);

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-${td.objectType}`)
        .should('have.attr', 'src', td.badgeUrl);

    }

  });

  it('should display badge integration info when clicking on it', function() {

    cy.get('.ui-slideouttab-handle')
      .click();

    for (const td of testsData) {
      cy.get(`a[href="#swhid-tab-${td.objectType}"]`)
        .click();

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-origin`)
        .click()
        .wait(500);

      for (const badgeType of ['html', 'md', 'rst']) {
        cy.get(`.modal .swh-badge-${badgeType}`)
          .should('contain.text', `${urlPrefix}${originBrowseUrl}`)
          .should('contain.text', `${urlPrefix}${originBadgeUrl}`);
      }

      cy.get('.modal.show .close')
        .click()
        .wait(500);

      cy.get(`#swhid-tab-${td.objectType} .swh-badge-${td.objectType}`)
        .click()
        .wait(500);

      for (const badgeType of ['html', 'md', 'rst']) {
        cy.get(`.modal .swh-badge-${badgeType}`)
          .should('contain.text', `${urlPrefix}${td.browseUrl}`)
          .should('contain.text', `${urlPrefix}${td.badgeSWHIDUrl}`);
      }

      cy.get('.modal.show .close')
        .click()
        .wait(500);

    }
  });

  it('should be possible to retrieve SWHIDs context from JavaScript', function() {
    cy.window().then(win => {
      const swhIdsContext = win.swh.webapp.getSwhIdsContext();
      for (const testData of testsData) {
        assert.isTrue(swhIdsContext.hasOwnProperty(testData.objectType));
        assert.equal(swhIdsContext[testData.objectType].swhid,
                     testData.objectSWHIDs.slice(-1)[0]);
      }
    });
  });

});
<|endoftext|>


<commit_before>goog.provide('ol.layer.Tile');

goog.require('goog.object');
goog.require('ol.layer.Layer');

/**
 * @enum {string}
 */
ol.layer.TileProperty = {
  PRELOAD: 'preload',
  USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'
};

/**
 * @classdesc
 * For layer sources that provide pre-rendered, tiled images in grids that are
 * organized by zoom levels for specific resolutions.
 * Note that any property set in the options is set as a {@link ol.Object}
 * property on the layer object; for example, setting `title: 'My Title'` in the
 * options means that `title` is observable, and has get/set accessors.
 *
 * @constructor
 * @extends {ol.layer.Layer}
 * @fires ol.render.Event
 * @param {olx.layer.TileOptions=} opt_options Tile layer options.
 * @api stable
 */
ol.layer.Tile = function(opt_options) {
  var options = goog.isDef(opt_options) ? opt_options : {};

  var baseOptions = goog.object.clone(options);

  delete baseOptions.preload;
  delete baseOptions.useInterimTilesOnError;
  goog.base(this,  /** @type {olx.layer.LayerOptions} */ (baseOptions));

  this.setPreload(goog.isDef(options.preload) ? options.preload : 0);
  this.setUseInterimTilesOnError(goog.isDef(options.useInterimTilesOnError) ?
      options.useInterimTilesOnError : true);
};
goog.inherits(ol.layer.Tile, ol.layer.Layer);

/**
 * @return {number} The level to preload tiles up to.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.getPreload = function() {
  return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD));
};

/**
 * @function
 * @return {ol.source.Tile} Source.
 * @api stable
 */
ol.layer.Tile.prototype.getSource;

/**
 * @param {number} preload The level to preload tiles up to.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.setPreload = function(preload) {
  this.set(ol.layer.TileProperty.PRELOAD, preload);
};

/**
 * @return {boolean} Use interim tiles on error.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.getUseInterimTilesOnError = function() {
  return /** @type {boolean} */ (
      this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR));
};

/**
 * @param {boolean} useInterimTilesOnError Use interim tiles on error.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.setUseInterimTilesOnError =
    function(useInterimTilesOnError) {
  this.set(
      ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
};
<commit_msg>Add basic docs for layer.Tile<commit_after>goog.provide('ol.layer.Tile');

goog.require('goog.object');
goog.require('ol.layer.Layer');

/**
 * @enum {string}
 */
ol.layer.TileProperty = {
  PRELOAD: 'preload',
  USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'
};

/**
 * @classdesc
 * For layer sources that provide pre-rendered, tiled images in grids that are
 * organized by zoom levels for specific resolutions.
 * Note that any property set in the options is set as a {@link ol.Object}
 * property on the layer object; for example, setting `title: 'My Title'` in the
 * options means that `title` is observable, and has get/set accessors.
 *
 * @constructor
 * @extends {ol.layer.Layer}
 * @fires ol.render.Event
 * @param {olx.layer.TileOptions=} opt_options Tile layer options.
 * @api stable
 */
ol.layer.Tile = function(opt_options) {
  var options = goog.isDef(opt_options) ? opt_options : {};

  var baseOptions = goog.object.clone(options);

  delete baseOptions.preload;
  delete baseOptions.useInterimTilesOnError;
  goog.base(this,  /** @type {olx.layer.LayerOptions} */ (baseOptions));

  this.setPreload(goog.isDef(options.preload) ? options.preload : 0);
  this.setUseInterimTilesOnError(goog.isDef(options.useInterimTilesOnError) ?
      options.useInterimTilesOnError : true);
};
goog.inherits(ol.layer.Tile, ol.layer.Layer);

/**
 * Return the level as number to which we will preload tiles up to.
 * @return {number} The level to preload tiles up to.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.getPreload = function() {
  return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD));
};

/**
 * Return the associated {@link ol.source.Tile tilesource} of the layer.
 * @function
 * @return {ol.source.Tile} Source.
 * @api stable
 */
ol.layer.Tile.prototype.getSource;

/**
 * Set the level as number to which we will preload tiles up to.
 * @param {number} preload The level to preload tiles up to.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.setPreload = function(preload) {
  this.set(ol.layer.TileProperty.PRELOAD, preload);
};

/**
 * Whether we use interim tiles on error.
 * @return {boolean} Use interim tiles on error.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.getUseInterimTilesOnError = function() {
  return /** @type {boolean} */ (
      this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR));
};

/**
 * Set whether we use interim tiles on error.
 * @param {boolean} useInterimTilesOnError Use interim tiles on error.
 * @observable
 * @api
 */
ol.layer.Tile.prototype.setUseInterimTilesOnError =
    function(useInterimTilesOnError) {
  this.set(
      ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
};
<|endoftext|>


<commit_before>/**
 * Resource contextualisation widget.
 *
 * Purpose of this widget is showing to the user, without any direct action by himself,
 * information of his interest related with the content that is being shown currently to him .
 * To achieve this, we collect in a Solr system information of different repositories
 * (Elixir Service Registry, Elixir Training Portal, and Elixir Events Portal, until now), so
 * we can search into this information which is related with content accesed by user.
 *
 */

/**
 * Resource contextualisation Constructor.
 *
 * @param {Object} options An object with the options for ContextDataList component.
 * @option {string} [target='YourOwnDivId']
 *    Identifier of the DIV tag where the component should be displayed.
 * @option {string} [displayStyle= ContextDataList.FULL_STYLE, ContextDataList.COMMON_STYLE]
 *    Type of rows visualisation.
 * @option {string} [userTextClassContainer=Your own class name ]
 *    Class name that contains user's text to search.
 * @option {string} [userTextTagContainer=One stablished tag name, for example h1. It's not used if userTextClassContainer is defined ]
 *    Tag name that contains user's text to search.
 * @option {int} [numberResults=number ]
 *    Integer that restricts the results number that should be shown.
 * @option {boolean} [includeSameSiteResults=If you want to see records of your present site. Temporary disabled. ]
 *    Boolean that avoids or not results from the same site you are seeing. */
function ContextDataList (options) {

	var default_options_values = {
	     displayStyle: ContextDataList.COMMON_STYLE,
	     includeSameSiteResults : true
	};
	for(var key in default_options_values){
	     this[key] = default_options_values[key];
	}
	for(var key in options){
	     this[key] = options[key];
	}
	this.contextDataServer = "http://176.58.119.235:8983/solr/contextData";
	this.dataManager = new DataManager();

	// global current status
	this.currentTotalResults= null;
	this.currentStartResult= null;
	this.currentNumberLoadedResults= null;
	this.currentStatus= ContextDataList.LOADING;
	this.currentFilters= null;
	this.currentURL = window.location.href;
	this.currentDomain = window.location.hostname;

	this._onLoadedFunctions= [];

}

/**
 * Resource contextualisation widget.
 *
 *
 * @class ContextDataList
 *
 */
ContextDataList.prototype = {
	constructor: ContextDataList,

	/**
	 * Shows the contextualised data into the widget, updating the whole internal status of the widget.
	 */
	totalDrawContextDataList : function (){
		this.updateGlobalStatus(ContextDataList.LOADING);
		this.drawContextDataList();
	},

	/**
	 * Returns User's text to contextualise, if it exists.
         * {String} - Text found into the client document that contains Contextualisation widget.
	 */
	getUserSearch : function() {
		var userText = '';
		var elementsContainer = null;
		if (this.userTextClassContainer != undefined && this.userTextClassContainer != null) {
			elementsContainer = document.getElementsByClassName(this.userTextClassContainer);
		}else{
			elementsContainer = document.getElementsByTagName(this.userTextTagContainer);
		}

		if (elementsContainer != null && elementsContainer.length > 0) {
			var myFirstElement = elementsContainer[0];
			userText = myFirstElement.innerText;
			if (userText == undefined || userText == null) {
				userText = myFirstElement.innerHTML;
			}
		}
		return userText;
	},

	/**
	 * Shows the contextualised data into the widget.
	 */
	drawContextDataList : function (){
		this.currentStatus = ContextDataList.LOADING;
		//this.updateGlobalStatus(this.LOADING);
		var userText = this.getUserSearch();
		var maxRows = this.getMaxRows();
		var newUrl = this._getNewUrl(userText, this.currentFilters, this.currentStartResult, maxRows);
		this.processDataFromUrl(newUrl);
	},

	/**
	 * Retrieves the maximum number of results that can be shown into the widget.
         * {Integer} - Maximum amount of results that can be shown at the same time.
	 */
	getMaxRows : function(){
		var maxRows = ContextDataList.MAX_ROWS;
		if (this.numberResults != "undefined" && !isNaN(this.numberResults) && typeof this.numberResults === 'number' && (this.numberResults % 1 === 0) ) {
			if (this.numberResults < ContextDataList.MAX_ROWS) {
				maxRows = this.numberResults;
			}
		}
		return maxRows;
	},

	/**
	 * Create a url to the SolR database with all parameters generated from these arguments.
	 * @param fieldText {string} Text to search.
	 * @param filters {Array} Array of filters - Only results with one of these resource types will be get.
	 * @param start {integer} Position of the first result to retrieve.
	 * @param rowsNumber {integer} Indicates the maximum number of results that will be shown on the screen;
	 */
	_getNewUrl : function(fieldText, filters, start, rowsNumber){
		//console.log('_getNewUrl, fieldText: '+fieldText+', filters: '+filters+', start: '+start+', rowsNumber: '+rowsNumber);
		var count = 0;
		var url = "";

		var words = fieldText.split(" ");
		var searchPhrase = "";
		while (count < words.length) {
			searchPhrase += words[count];
			count++;
			if(count < words.length){searchPhrase += '+'}
		}
		// we exclude all results from this domain: disabled until reindexing
		/*if (!this.includeSameSiteResults) {
			var excludingPhrase = "";
			//excludingPhrase = " NOT("+this.currentDomain+")";
			excludingPhrase = "-\"*tgac.ac.uk*\"";
			searchPhrase = "("+searchPhrase+excludingPhrase+")";
		// we exclude only the same record than user is
		}else{*/
			var excludingPhrase = "";
			excludingPhrase = " NOT("+this.currentURL+")";
			searchPhrase = "("+searchPhrase+") AND "+excludingPhrase;
		//}

		url = this.contextDataServer+"/select?defType=edismax&q="+searchPhrase;

		var fq = null;
		if (filters !== "undefined" && filters!=null ) {
			if (filters instanceof Array && filters.length>0) {
				fq = "";
				var filterCount = 0;
				var filterChain = "";
				while (filterCount < filters.length) {
					filterChain += "'"+filters[filterCount]+"'";
					filterCount++;
					if(filterCount < filters.length){filterChain += ' OR '}
				}
				fq="resource_type:("+filterChain+")";
			}else{
				fq = "resource_type:undefined";
			}

		}

		if (fq!=null) {
			url = url+"&fq="+fq;
		}

		// qf
		url = url+"&qf=title^10.0+field^10.0+description^1.0";

		// start row
		if (start !== "undefined" && start!=null && !isNaN(start) && typeof start === 'number' && (start % 1 === 0) ) {
			url = url+"&start="+start;
			this.currentStartResult = start;
		}else{
			this.currentStartResult = 0;
		}

		// num rows
		if (rowsNumber !== "undefined" && rowsNumber!=null && rowsNumber!=null && !isNaN(rowsNumber) && typeof rowsNumber === 'number' && (rowsNumber % 1 === 0) ) {
			url = url+"&rows="+rowsNumber;
		}

		// wt
		url = url+"&wt=json";

		// maybe we could also filter fields that we return
		// &fl=start,title,notes,link

		return url;
	},

	/**
	 * Makes an asynchronous request to the Contextualisation data server and process its reply.
	 * @param url {string} - Uniform Resource Locator
	 */
	processDataFromUrl: function(url){
		var myContextDataList = this;
		reqwest({
			url: url ,
			type: 'json' ,
			method: 'post' ,
			contentType: 'application/json' ,
			crossOrigin: true,
			timeout: 1000 * 5,
			withCredentials: true,  // We will have to include more security in our Solr server

			error: function (err) {
				myContextDataList.processError(err);
				myContextDataList.updateGlobalStatus(myContextDataList.ERROR);
			} ,
			success: function (resp) {
				var contextualisedData = myContextDataList.processContextualisedData(resp);
				myContextDataList.drawContextualisedData(contextualisedData);
			}
		});
	},

	/**
	 * Manages some errors and process each result to be get in a proper way.
	 * data {Object} - The full data list to be processed and shown
	 * @param {Array} - Array with objects converted from their original JSON status
	 */
	processContextualisedData : function(data) {
		var myContextDataList = this;
		var contextualisedData = [];
		if(data.response != undefined){
			if(data.response.docs != undefined){
				this.currentTotalResults = data.response.numFound;
				data.response.docs.forEach(function(entry) {
					var typedData = myContextDataList.dataManager.getDataEntity(entry);
					contextualisedData.push(typedData);
				});
			}
			else {
				myContextDataList.processError("data.response.docs undefined");
				myContextDataList.changeCurrentStatus(myContextDataList.ERROR);
			}
		} else {
			myContextDataList.processError("data.response undefined");
			myContextDataList.changeCurrentStatus(myContextDataList.ERROR);
		}

		return contextualisedData;
	},

	/**
	 * Draw a entire list of contextualised resources
	 * @param contextualisedData {object Object} - All the data to be drawn into the widget.
	 */
	drawContextualisedData : function(contextualisedData){
		var target = document.getElementById(this.targetId);
		if (target == undefined || target == null){
			return;
		}
		while (target.firstChild) {
			target.removeChild(target.firstChild);
		}

		var index = 0;
		var dataObject;
		var drawableObject;
		var oddRow = true;
		while(index < contextualisedData.length){
			if (index%2==0) {
				oddRow = false;
			}else{
				oddRow = true;
			}
			dataObject = contextualisedData[index];
			drawableObject = dataObject.getDrawableObjectByStyle(this.displayStyle);
			drawableObject.classList.add('views-row');
			if(oddRow == true){
				drawableObject.classList.add("views-row-odd");
			}else{
				drawableObject.classList.add("views-row-even");
			}
			target.appendChild(drawableObject);
			index++;
		}
		if (contextualisedData.length == 0) {
			target.appendChild(this.getEmptyRecord());
		}

		this.currentNumberLoadedResults = contextualisedData.length;
		this.updateGlobalStatus(ContextDataList.LOADED);
		/*
		console.log('currentTotalResults');
		console.log(this.currentTotalResults);
		console.log('currentStartResult');
		console.log(this.currentStartResult);
		console.log('currentNumberLoadedResults');
		console.log(this.currentNumberLoadedResults);
		console.log('currentFilters');
		console.log(this.currentFilters);
		*/

	},

	/**
	 * 	Returns one row explaining the absence of real results.
	 * 	{HTML Object} - Empty result.
	 */
	getEmptyRecord : function(){
		var mainContainer = document.createElement('div');
		mainContainer.classList.add("context_data_container");
		var trContainer = document.createElement('div');
		trContainer.classList.add("context_data_container_row");

		var spanText = document.createElement('span');
		var text = 'Cannot be found any related result';
		spanText.innerHTML = text;
		trContainer.appendChild(spanText);
		mainContainer.appendChild(trContainer);
		return mainContainer;
	},

	/**
	 * Updates, depending on the new status, internal variables of the component and, if
	 * new status is 'LOADED', executes the 'onLoaded' functions registered.
	 * @param newStatus {string} - ContextDataList.LOADING or ContextDataList.ERROR or ContextDataList.LOADED
	 */
	updateGlobalStatus : function(newStatus){
		// new status must be one of the posible status
		if (newStatus != ContextDataList.LOADING && newStatus != ContextDataList.ERROR && newStatus != ContextDataList.LOADED ){
			return;
		}
		this.currentStatus = newStatus;

		if (this.currentStatus == ContextDataList.LOADING){
			this.currentTotalResults = null;
			this.currentStartResult = null;
			this.currentNumberLoadedResults = null;
		}else if (this.currentStatus == ContextDataList.ERROR){
			this.currentTotalResults = null;
			this.currentStartResult = null;
			this.currentNumberLoadedResults = null;
			// if new status is LOADED, here we cannot know anything about all these internal variables.
		}/*else if (this.currentStatus == this.LOADED){
			this.currentTotalResults = null;
			this.currentStartResult = null;
			this.currentNumberLoadedResults = null;
		}*/

		// Finally we execute registered 'onLoaded' functions
		if (this.currentStatus == ContextDataList.LOADED || this.currentStatus == ContextDataList.ERROR ){
			this.executeOnLoadedFunctions();
		}
	},

	/**
	 * Register new functions to be executed when status component is updated to 'LOADED'
	 * myContext {Object} myContext - Context in which myFunction should be execute. Usually its own object container.
	 * myContext {Object} myFunction - Function to be executed.
	 */
	registerOnLoadedFunction : function(myContext, myFunction){
		var onLoadedObject = {
			'myContext'	: myContext,
			'myFunction'	: myFunction
		};
		this._onLoadedFunctions.push(onLoadedObject);
	},

	/**
	 * Execute all registered 'onLoaded' functions
	 */
	executeOnLoadedFunctions : function(){
		var onLoadedFunctionObject = null;
		var onLoadedFunctionContext = null;
		var onLoadedFunction = null;
		for(var i=0;i<this._onLoadedFunctions.length;i++){
			onLoadedFunctionObject = this._onLoadedFunctions[i];
			onLoadedFunctionContext = onLoadedFunctionObject.myContext;
			onLoadedFunction = onLoadedFunctionObject.myFunction;
			// we execute the onLoadedFunction with its own context
			onLoadedFunction.call(onLoadedFunctionContext);
		}
	},

	/**
	 * Prints as an error to the console the message received.
	 * error {string} error - String to be printed
	 */
	processError : function(error) {
	    console.log("ERROR:" + error);
	}

}

// STATIC ATTRIBUTES
var CONSTS = {
	//List of possible context data sources
	SOURCE_ELIXIR_REGISTRY:"ESR",
	SOURCE_ELIXIR_TESS:"TSS",
	SOURCE_ELIXIR_EVENTS:"EEV",
	//style of visualization
	FULL_STYLE:"FULL_STYLE",
	COMMON_STYLE:"COMMON_STYLE",
	//max number of rows to retrieve from the server, whatever 'numberResults' can be
	MAX_ROWS:100,
	//Events
	EVT_ON_RESULTS_LOADED: "onResultsLoaded",
	EVT_ON_REQUEST_ERROR: "onRequestError",
	//Different widget status
	LOADING: "LOADING",
	LOADED: "LOADED",
	ERROR: "ERROR"
};

for(var key in CONSTS){
     ContextDataList[key] = CONSTS[key];
}

<commit_msg>bug fix avoiding the same result<commit_after>/**
 * Resource contextualisation widget.
 *
 * Purpose of this widget is showing to the user, without any direct action by himself,
 * information of his interest related with the content that is being shown currently to him .
 * To achieve this, we collect in a Solr system information of different repositories
 * (Elixir Service Registry, Elixir Training Portal, and Elixir Events Portal, until now), so
 * we can search into this information which is related with content accesed by user.
 *
 */

/**
 * Resource contextualisation Constructor.
 *
 * @param {Object} options An object with the options for ContextDataList component.
 * @option {string} [target='YourOwnDivId']
 *    Identifier of the DIV tag where the component should be displayed.
 * @option {string} [displayStyle= ContextDataList.FULL_STYLE, ContextDataList.COMMON_STYLE]
 *    Type of rows visualisation.
 * @option {string} [userTextClassContainer=Your own class name ]
 *    Class name that contains user's text to search.
 * @option {string} [userTextTagContainer=One stablished tag name, for example h1. It's not used if userTextClassContainer is defined ]
 *    Tag name that contains user's text to search.
 * @option {int} [numberResults=number ]
 *    Integer that restricts the results number that should be shown.
 * @option {boolean} [includeSameSiteResults=If you want to see records of your present site. Temporary disabled. ]
 *    Boolean that avoids or not results from the same site you are seeing. */
function ContextDataList (options) {

	var default_options_values = {
	     displayStyle: ContextDataList.COMMON_STYLE,
	     includeSameSiteResults : true
	};
	for(var key in default_options_values){
	     this[key] = default_options_values[key];
	}
	for(var key in options){
	     this[key] = options[key];
	}
	this.contextDataServer = "http://176.58.119.235:8983/solr/contextData";
	this.dataManager = new DataManager();

	// global current status
	this.currentTotalResults= null;
	this.currentStartResult= null;
	this.currentNumberLoadedResults= null;
	this.currentStatus= ContextDataList.LOADING;
	this.currentFilters= null;
	this.currentURL = window.location.href;
	this.currentDomain = window.location.hostname;

	this._onLoadedFunctions= [];

}

/**
 * Resource contextualisation widget.
 *
 *
 * @class ContextDataList
 *
 */
ContextDataList.prototype = {
	constructor: ContextDataList,

	/**
	 * Shows the contextualised data into the widget, updating the whole internal status of the widget.
	 */
	totalDrawContextDataList : function (){
		this.updateGlobalStatus(ContextDataList.LOADING);
		this.drawContextDataList();
	},

	/**
	 * Returns User's text to contextualise, if it exists.
         * {String} - Text found into the client document that contains Contextualisation widget.
	 */
	getUserSearch : function() {
		var userText = '';
		var elementsContainer = null;
		if (this.userTextClassContainer != undefined && this.userTextClassContainer != null) {
			elementsContainer = document.getElementsByClassName(this.userTextClassContainer);
		}else{
			elementsContainer = document.getElementsByTagName(this.userTextTagContainer);
		}

		if (elementsContainer != null && elementsContainer.length > 0) {
			var myFirstElement = elementsContainer[0];
			userText = myFirstElement.innerText;
			if (userText == undefined || userText == null) {
				userText = myFirstElement.innerHTML;
			}
		}
		return userText;
	},

	/**
	 * Shows the contextualised data into the widget.
	 */
	drawContextDataList : function (){
		this.currentStatus = ContextDataList.LOADING;
		//this.updateGlobalStatus(this.LOADING);
		var userText = this.getUserSearch();
		var maxRows = this.getMaxRows();
		var newUrl = this._getNewUrl(userText, this.currentFilters, this.currentStartResult, maxRows);
		this.processDataFromUrl(newUrl);
	},

	/**
	 * Retrieves the maximum number of results that can be shown into the widget.
         * {Integer} - Maximum amount of results that can be shown at the same time.
	 */
	getMaxRows : function(){
		var maxRows = ContextDataList.MAX_ROWS;
		if (this.numberResults != "undefined" && !isNaN(this.numberResults) && typeof this.numberResults === 'number' && (this.numberResults % 1 === 0) ) {
			if (this.numberResults < ContextDataList.MAX_ROWS) {
				maxRows = this.numberResults;
			}
		}
		return maxRows;
	},

	/**
	 * Create a url to the SolR database with all parameters generated from these arguments.
	 * @param fieldText {string} Text to search.
	 * @param filters {Array} Array of filters - Only results with one of these resource types will be get.
	 * @param start {integer} Position of the first result to retrieve.
	 * @param rowsNumber {integer} Indicates the maximum number of results that will be shown on the screen;
	 */
	_getNewUrl : function(fieldText, filters, start, rowsNumber){
		//console.log('_getNewUrl, fieldText: '+fieldText+', filters: '+filters+', start: '+start+', rowsNumber: '+rowsNumber);
		var count = 0;
		var url = "";

		var words = fieldText.split(" ");
		var searchPhrase = "";
		while (count < words.length) {
			searchPhrase += words[count];
			count++;
			if(count < words.length){searchPhrase += '+'}
		}
		// we exclude all results from this domain: disabled until reindexing
		/*if (!this.includeSameSiteResults) {
			var excludingPhrase = "";
			//excludingPhrase = " NOT("+this.currentDomain+")";
			excludingPhrase = "-\"*tgac.ac.uk*\"";
			searchPhrase = "("+searchPhrase+excludingPhrase+")";
		// we exclude only the same record than user is
		}else{*/
			var excludingPhrase = "";
			excludingPhrase = " NOT(\""+this.currentURL+"\")";
			searchPhrase = "("+searchPhrase+") AND "+excludingPhrase;

		//}

		url = this.contextDataServer+"/select?defType=edismax&q="+searchPhrase;

		var fq = null;
		if (filters !== "undefined" && filters!=null ) {
			if (filters instanceof Array && filters.length>0) {
				fq = "";
				var filterCount = 0;
				var filterChain = "";
				while (filterCount < filters.length) {
					filterChain += "'"+filters[filterCount]+"'";
					filterCount++;
					if(filterCount < filters.length){filterChain += ' OR '}
				}
				fq="resource_type:("+filterChain+")";
			}else{
				fq = "resource_type:undefined";
			}

		}

		if (fq!=null) {
			url = url+"&fq="+fq;
		}

		// qf
		url = url+"&qf=title^10.0+field^10.0+description^1.0";

		// start row
		if (start !== "undefined" && start!=null && !isNaN(start) && typeof start === 'number' && (start % 1 === 0) ) {
			url = url+"&start="+start;
			this.currentStartResult = start;
		}else{
			this.currentStartResult = 0;
		}

		// num rows
		if (rowsNumber !== "undefined" && rowsNumber!=null && rowsNumber!=null && !isNaN(rowsNumber) && typeof rowsNumber === 'number' && (rowsNumber % 1 === 0) ) {
			url = url+"&rows="+rowsNumber;
		}

		// wt
		url = url+"&wt=json";

		// maybe we could also filter fields that we return
		// &fl=start,title,notes,link

		return url;
	},

	/**
	 * Makes an asynchronous request to the Contextualisation data server and process its reply.
	 * @param url {string} - Uniform Resource Locator
	 */
	processDataFromUrl: function(url){
		var myContextDataList = this;
		reqwest({
			url: url ,
			type: 'json' ,
			method: 'post' ,
			contentType: 'application/json' ,
			crossOrigin: true,
			timeout: 1000 * 5,
			withCredentials: true,  // We will have to include more security in our Solr server

			error: function (err) {
				myContextDataList.processError(err);
				myContextDataList.updateGlobalStatus(myContextDataList.ERROR);
			} ,
			success: function (resp) {
				var contextualisedData = myContextDataList.processContextualisedData(resp);
				myContextDataList.drawContextualisedData(contextualisedData);
			}
		});
	},

	/**
	 * Manages some errors and process each result to be get in a proper way.
	 * data {Object} - The full data list to be processed and shown
	 * @param {Array} - Array with objects converted from their original JSON status
	 */
	processContextualisedData : function(data) {
		var myContextDataList = this;
		var contextualisedData = [];
		if(data.response != undefined){
			if(data.response.docs != undefined){
				this.currentTotalResults = data.response.numFound;
				data.response.docs.forEach(function(entry) {
					var typedData = myContextDataList.dataManager.getDataEntity(entry);
					contextualisedData.push(typedData);
				});
			}
			else {
				myContextDataList.processError("data.response.docs undefined");
				myContextDataList.changeCurrentStatus(myContextDataList.ERROR);
			}
		} else {
			myContextDataList.processError("data.response undefined");
			myContextDataList.changeCurrentStatus(myContextDataList.ERROR);
		}

		return contextualisedData;
	},

	/**
	 * Draw a entire list of contextualised resources
	 * @param contextualisedData {object Object} - All the data to be drawn into the widget.
	 */
	drawContextualisedData : function(contextualisedData){
		var target = document.getElementById(this.targetId);
		if (target == undefined || target == null){
			return;
		}
		while (target.firstChild) {
			target.removeChild(target.firstChild);
		}

		var index = 0;
		var dataObject;
		var drawableObject;
		var oddRow = true;
		while(index < contextualisedData.length){
			if (index%2==0) {
				oddRow = false;
			}else{
				oddRow = true;
			}
			dataObject = contextualisedData[index];
			drawableObject = dataObject.getDrawableObjectByStyle(this.displayStyle);
			drawableObject.classList.add('views-row');
			if(oddRow == true){
				drawableObject.classList.add("views-row-odd");
			}else{
				drawableObject.classList.add("views-row-even");
			}
			target.appendChild(drawableObject);
			index++;
		}
		if (contextualisedData.length == 0) {
			target.appendChild(this.getEmptyRecord());
		}

		this.currentNumberLoadedResults = contextualisedData.length;
		this.updateGlobalStatus(ContextDataList.LOADED);
		/*
		console.log('currentTotalResults');
		console.log(this.currentTotalResults);
		console.log('currentStartResult');
		console.log(this.currentStartResult);
		console.log('currentNumberLoadedResults');
		console.log(this.currentNumberLoadedResults);
		console.log('currentFilters');
		console.log(this.currentFilters);
		*/

	},

	/**
	 * 	Returns one row explaining the absence of real results.
	 * 	{HTML Object} - Empty result.
	 */
	getEmptyRecord : function(){
		var mainContainer = document.createElement('div');
		mainContainer.classList.add("context_data_container");
		var trContainer = document.createElement('div');
		trContainer.classList.add("context_data_container_row");

		var spanText = document.createElement('span');
		var text = 'Cannot be found any related result';
		spanText.innerHTML = text;
		trContainer.appendChild(spanText);
		mainContainer.appendChild(trContainer);
		return mainContainer;
	},

	/**
	 * Updates, depending on the new status, internal variables of the component and, if
	 * new status is 'LOADED', executes the 'onLoaded' functions registered.
	 * @param newStatus {string} - ContextDataList.LOADING or ContextDataList.ERROR or ContextDataList.LOADED
	 */
	updateGlobalStatus : function(newStatus){
		// new status must be one of the posible status
		if (newStatus != ContextDataList.LOADING && newStatus != ContextDataList.ERROR && newStatus != ContextDataList.LOADED ){
			return;
		}
		this.currentStatus = newStatus;

		if (this.currentStatus == ContextDataList.LOADING){
			this.currentTotalResults = null;
			this.currentStartResult = null;
			this.currentNumberLoadedResults = null;
		}else if (this.currentStatus == ContextDataList.ERROR){
			this.currentTotalResults = null;
			this.currentStartResult = null;
			this.currentNumberLoadedResults = null;
			// if new status is LOADED, here we cannot know anything about all these internal variables.
		}/*else if (this.currentStatus == this.LOADED){
			this.currentTotalResults = null;
			this.currentStartResult = null;
			this.currentNumberLoadedResults = null;
		}*/

		// Finally we execute registered 'onLoaded' functions
		if (this.currentStatus == ContextDataList.LOADED || this.currentStatus == ContextDataList.ERROR ){
			this.executeOnLoadedFunctions();
		}
	},

	/**
	 * Register new functions to be executed when status component is updated to 'LOADED'
	 * myContext {Object} myContext - Context in which myFunction should be execute. Usually its own object container.
	 * myContext {Object} myFunction - Function to be executed.
	 */
	registerOnLoadedFunction : function(myContext, myFunction){
		var onLoadedObject = {
			'myContext'	: myContext,
			'myFunction'	: myFunction
		};
		this._onLoadedFunctions.push(onLoadedObject);
	},

	/**
	 * Execute all registered 'onLoaded' functions
	 */
	executeOnLoadedFunctions : function(){
		var onLoadedFunctionObject = null;
		var onLoadedFunctionContext = null;
		var onLoadedFunction = null;
		for(var i=0;i<this._onLoadedFunctions.length;i++){
			onLoadedFunctionObject = this._onLoadedFunctions[i];
			onLoadedFunctionContext = onLoadedFunctionObject.myContext;
			onLoadedFunction = onLoadedFunctionObject.myFunction;
			// we execute the onLoadedFunction with its own context
			onLoadedFunction.call(onLoadedFunctionContext);
		}
	},

	/**
	 * Prints as an error to the console the message received.
	 * error {string} error - String to be printed
	 */
	processError : function(error) {
	    console.log("ERROR:" + error);
	}

}

// STATIC ATTRIBUTES
var CONSTS = {
	//List of possible context data sources
	SOURCE_ELIXIR_REGISTRY:"ESR",
	SOURCE_ELIXIR_TESS:"TSS",
	SOURCE_ELIXIR_EVENTS:"EEV",
	//style of visualization
	FULL_STYLE:"FULL_STYLE",
	COMMON_STYLE:"COMMON_STYLE",
	//max number of rows to retrieve from the server, whatever 'numberResults' can be
	MAX_ROWS:100,
	//Events
	EVT_ON_RESULTS_LOADED: "onResultsLoaded",
	EVT_ON_REQUEST_ERROR: "onRequestError",
	//Different widget status
	LOADING: "LOADING",
	LOADED: "LOADED",
	ERROR: "ERROR"
};

for(var key in CONSTS){
     ContextDataList[key] = CONSTS[key];
}

<|endoftext|>


<commit_before>// Copyright 2013-2016, University of Colorado Boulder

/**
 * A DerivedProperty is computed based on other Properties.  This implementation inherits from Property to (a) simplify
 * implementation and (b) ensure it remains consistent. Note that the setters should not be called directly, so the
 * setters (set, reset and es5 setter) throw an error if used directly.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

define( function( require ) {
  'use strict';

  // modules
  var axon = require( 'AXON/axon' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );
  var Tandem = require( 'TANDEM/Tandem' );

  /**
   * @param {Property[]} dependencies - Properties that this Property's value is derived from
   * @param {function} derivation - function that derives this Property's value, expects args in the same order as dependencies
   * @param {Object} [options] - see Property
   * @constructor
   */
  function DerivedProperty( dependencies, derivation, options ) {

    options = _.extend( {
      tandem: Tandem.optional,
      phetioState: false, // derived properties don't need to be loaded to load the state
      phetioType: null, // must be supplied by instantiations and must be of type DerivedPropertyIO
      phetioReadOnly: true // derived properties can be read but not set by PhET-iO
    }, options );

    if ( window.phet && window.phet.phetio ) {
      assert && assert( options.phetioType === null || options.phetioType.typeName.indexOf( 'DerivedPropertyIO' ) === 0, 'phetioType should be DerivedPropertyIO' );
    }

    this.dependencies = dependencies; // @private

    var initialValue = derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) );

    // We must pass supertype tandem to parent class so addInstance is called only once in the subclassiest constructor.
    Property.call( this, initialValue, options );

    var self = this;

    // @private Keep track of listeners so they can be detached
    this.dependencyListeners = [];

    for ( var i = 0; i < dependencies.length; i++ ) {
      var dependency = dependencies[ i ];
      (function( dependency ) {
        var listener = function() {
          Property.prototype.set.call( self, derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) ) );
        };
        self.dependencyListeners.push( listener );
        dependency.lazyLink( listener );
      })( dependency, i );
    }
  }

  axon.register( 'DerivedProperty', DerivedProperty );

  function equalsFunction( a, b ) {
    return a === b;
  }

  function andFunction( value, property ) {
    assert && assert( typeof property.value === 'boolean', 'boolean value required' );
    return value && property.value;
  }

  function orFunction( value, property ) {
    assert && assert( typeof property.value === 'boolean', 'boolean value required' );
    return value || property.value;
  }

  return inherit( Property, DerivedProperty, {

    // @public
    dispose: function() {

      // Unlink from dependent Properties
      for ( var i = 0; i < this.dependencies.length; i++ ) {
        var dependency = this.dependencies[ i ];
        dependency.unlink( this.dependencyListeners[ i ] );
      }
      this.dependencies = null;
      this.dependencyListeners = null;

      Property.prototype.dispose.call( this );
    },

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @param value
     * @override
     * @public
     */
    set: function( value ) { throw new Error( 'Cannot set values directly to a DerivedProperty, tried to set: ' + value ); },

    /**
     * Override the mutators to provide an error message.  These should not be called directly, the value should only be modified
     * when the dependencies change. Keep the newValue output in the string so the argument won't be stripped by minifier
     * (which would cause crashes like https://github.com/phetsims/axon/issues/15)
     * @param newValue
     * @override
     * @public
     */
    set value( newValue ) { throw new Error( 'Cannot es5-set values directly to a DerivedProperty, tried to set: ' + newValue ); },

    /**
     * Override get value as well to satisfy the linter which wants get/set pairs (even though it just uses the same code as the superclass).
     * @returns {*}
     * @override
     * @public
     */
    get value() {return Property.prototype.get.call( this );},

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @override
     * @public
     */
    reset: function() { throw new Error( 'Cannot reset a DerivedProperty directly' ); }
  }, {

    /**
     * Creates a derived boolean Property whose value is true iff firstProperty's value is equal to secondProperty's
     * value.
     * @public
     *
     * @param {Property.<*>} firstProperty
     * @param {Property.<*>} secondProperty
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    valueEquals: function( firstProperty, secondProperty, options ) {
      return new DerivedProperty( [ firstProperty, secondProperty ], equalsFunction, options );
    },

    /**
     * Creates a derived boolean Property whose value is true iff every input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    and: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, andFunction, true ), options );
    },

    /**
     * Creates a derived boolean Property whose value is true iff any input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    or: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, orFunction, false ), options );
    }
  } );
} );<commit_msg>Removed unnessary override, see https://github.com/phetsims/axon/issues/171<commit_after>// Copyright 2013-2016, University of Colorado Boulder

/**
 * A DerivedProperty is computed based on other Properties.  This implementation inherits from Property to (a) simplify
 * implementation and (b) ensure it remains consistent. Note that the setters should not be called directly, so the
 * setters (set, reset and es5 setter) throw an error if used directly.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

define( function( require ) {
  'use strict';

  // modules
  var axon = require( 'AXON/axon' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );
  var Tandem = require( 'TANDEM/Tandem' );

  /**
   * @param {Property[]} dependencies - Properties that this Property's value is derived from
   * @param {function} derivation - function that derives this Property's value, expects args in the same order as dependencies
   * @param {Object} [options] - see Property
   * @constructor
   */
  function DerivedProperty( dependencies, derivation, options ) {

    options = _.extend( {
      tandem: Tandem.optional,
      phetioState: false, // derived properties don't need to be loaded to load the state
      phetioType: null, // must be supplied by instantiations and must be of type DerivedPropertyIO
      phetioReadOnly: true // derived properties can be read but not set by PhET-iO
    }, options );

    if ( window.phet && window.phet.phetio ) {
      assert && assert( options.phetioType === null || options.phetioType.typeName.indexOf( 'DerivedPropertyIO' ) === 0, 'phetioType should be DerivedPropertyIO' );
    }

    this.dependencies = dependencies; // @private

    var initialValue = derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) );

    // We must pass supertype tandem to parent class so addInstance is called only once in the subclassiest constructor.
    Property.call( this, initialValue, options );

    var self = this;

    // @private Keep track of listeners so they can be detached
    this.dependencyListeners = [];

    for ( var i = 0; i < dependencies.length; i++ ) {
      var dependency = dependencies[ i ];
      (function( dependency ) {
        var listener = function() {
          Property.prototype.set.call( self, derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) ) );
        };
        self.dependencyListeners.push( listener );
        dependency.lazyLink( listener );
      })( dependency, i );
    }
  }

  axon.register( 'DerivedProperty', DerivedProperty );

  function equalsFunction( a, b ) {
    return a === b;
  }

  function andFunction( value, property ) {
    assert && assert( typeof property.value === 'boolean', 'boolean value required' );
    return value && property.value;
  }

  function orFunction( value, property ) {
    assert && assert( typeof property.value === 'boolean', 'boolean value required' );
    return value || property.value;
  }

  return inherit( Property, DerivedProperty, {

    // @public
    dispose: function() {

      // Unlink from dependent Properties
      for ( var i = 0; i < this.dependencies.length; i++ ) {
        var dependency = this.dependencies[ i ];
        dependency.unlink( this.dependencyListeners[ i ] );
      }
      this.dependencies = null;
      this.dependencyListeners = null;

      Property.prototype.dispose.call( this );
    },

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @param value
     * @override
     * @public
     */
    set: function( value ) { throw new Error( 'Cannot set values directly to a DerivedProperty, tried to set: ' + value ); },

    /**
     * Override the mutators to provide an error message.  These should not be called directly, the value should only be modified
     * when the dependencies change. Keep the newValue output in the string so the argument won't be stripped by minifier
     * (which would cause crashes like https://github.com/phetsims/axon/issues/15)
     * @param newValue
     * @override
     * @public
     */
    set value( newValue ) { throw new Error( 'Cannot es5-set values directly to a DerivedProperty, tried to set: ' + newValue ); },

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @override
     * @public
     */
    reset: function() { throw new Error( 'Cannot reset a DerivedProperty directly' ); }
  }, {

    /**
     * Creates a derived boolean Property whose value is true iff firstProperty's value is equal to secondProperty's
     * value.
     * @public
     *
     * @param {Property.<*>} firstProperty
     * @param {Property.<*>} secondProperty
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    valueEquals: function( firstProperty, secondProperty, options ) {
      return new DerivedProperty( [ firstProperty, secondProperty ], equalsFunction, options );
    },

    /**
     * Creates a derived boolean Property whose value is true iff every input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    and: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, andFunction, true ), options );
    },

    /**
     * Creates a derived boolean Property whose value is true iff any input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    or: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, orFunction, false ), options );
    }
  } );
} );<|endoftext|>


<commit_before>// Copyright 2018, University of Colorado Boulder

/**
 * Single location of all accessibility strings.  These strings are not meant to be translatable yet.  Rosetta needs
 * some work to provide translators with context for these strings, and we want to receive some community feedback
 * before these strings are submitted for translation.
 *
 * @author Jesse Greenberg
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );

  var EnergyFormsAndChangesA11yStrings = {
    energySystemsSceneSummaryDescription: {
      value: 'This is an interactive sim. It changes as you play with it. It has a Play Area and a ' +
             'Control Panel. In the play area, construct an energy system with an energy producer, ' +
             'converter and consumer. Adjust the energy production and observe the flow of energy in the ' +
             'system. Inspect the energy forms and changes with energy symbols. In the control panel, ' +
             'use the play, pause and step buttons or reset the sim.'
    },
    energySystemsSceneInteractionHint: {
      value: 'Adjust the energy producer to begin observations.'
    },
    energySystem: {
      value: 'Energy System'
    },
    energySystemHelpText: {
      value: 'Energy system contains a {{producer}}, {{converter}}, and {{user}}.'
    },
    waterFaucet: {
      value: 'water faucet'
    },
    sun: {
      value: 'sun'
    },
    teaPot: {
      value: 'tea pot'
    },
    cyclist: {
      value: 'cyclist'
    },
    electricalGenerator: {
      value: 'electrical generator'
    },
    solarPanel: {
      value: 'solar panel'
    },
    beakerOfWater: {
      value: 'beaker of water'
    },
    incandescentLightBulb: {
      value: 'incandescent light bulb'
    },
    fluorescentLightBulb: {
      value: 'fluorescent light bulb'
    }
  };

  if ( phet.chipper.queryParameters.stringTest === 'xss' ) {
    for ( var key in EnergyFormsAndChangesA11yStrings ) {
      EnergyFormsAndChangesA11yStrings[ key ].value += '';
    }
  }

  // verify that object is immutable, without the runtime penalty in production code
  if ( assert ) { Object.freeze( EnergyFormsAndChangesA11yStrings ); }

  energyFormsAndChanges.register( 'EnergyFormsAndChangesA11yStrings', EnergyFormsAndChangesA11yStrings );

  return EnergyFormsAndChangesA11yStrings;
} );<commit_msg>made energy system names match the design description, see #45<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Single location of all accessibility strings.  These strings are not meant to be translatable yet.  Rosetta needs
 * some work to provide translators with context for these strings, and we want to receive some community feedback
 * before these strings are submitted for translation.
 *
 * @author Jesse Greenberg
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );

  var EnergyFormsAndChangesA11yStrings = {
    energySystemsSceneSummaryDescription: {
      value: 'This is an interactive sim. It changes as you play with it. It has a Play Area and a ' +
             'Control Panel. In the play area, construct an energy system with an energy producer, ' +
             'converter and consumer. Adjust the energy production and observe the flow of energy in the ' +
             'system. Inspect the energy forms and changes with energy symbols. In the control panel, ' +
             'use the play, pause and step buttons or reset the sim.'
    },
    energySystemsSceneInteractionHint: {
      value: 'Adjust the energy producer to begin observations.'
    },
    energySystem: {
      value: 'Energy System'
    },
    energySystemHelpText: {
      value: 'Energy system contains a {{producer}}, {{converter}}, and {{user}}.'
    },
    waterFaucet: {
      value: 'water faucet'
    },
    sun: {
      value: 'sun'
    },
    teaPot: {
      value: 'tea kettle'
    },
    cyclist: {
      value: 'cyclist'
    },
    electricalGenerator: {
      value: 'wheel generator'
    },
    solarPanel: {
      value: 'solar panel'
    },
    beakerOfWater: {
      value: 'beaker of water on heating element'
    },
    incandescentLightBulb: {
      value: 'incandescent light bulb'
    },
    fluorescentLightBulb: {
      value: 'fluorescent light bulb'
    }
  };

  if ( phet.chipper.queryParameters.stringTest === 'xss' ) {
    for ( var key in EnergyFormsAndChangesA11yStrings ) {
      EnergyFormsAndChangesA11yStrings[ key ].value += '';
    }
  }

  // verify that object is immutable, without the runtime penalty in production code
  if ( assert ) { Object.freeze( EnergyFormsAndChangesA11yStrings ); }

  energyFormsAndChanges.register( 'EnergyFormsAndChangesA11yStrings', EnergyFormsAndChangesA11yStrings );

  return EnergyFormsAndChangesA11yStrings;
} );<|endoftext|>


<commit_before>/*
	-----------------------------------------------------------
	MIDI.loadPlugin : 0.1.2 : 01/18/2012
	-----------------------------------------------------------
	https://github.com/mudcube/MIDI.js
	-----------------------------------------------------------
	MIDI.loadPlugin({
		instrument: "acoustic_grand_piano", // or 1 (default)
		instruments: [ "acoustic_grand_piano", "acoustic_guitar_nylon" ], // or multiple instruments
		callback: function() { }
	});
*/

if (typeof (MIDI) === "undefined") var MIDI = {};
if (typeof (MIDI.Soundfont) === "undefined") MIDI.Soundfont = {};

(function() { "use strict";

// Turn on to get "onprogress" event. XHR will not work from file://
var USE_XHR = false;

MIDI.loadPlugin = function(conf) {
	if (typeof(conf) === "function") conf = { callback: conf };
	/// Get the instrument name.
	var instruments = conf.instruments || conf.instrument || "acoustic_grand_piano";
	if (typeof(instruments) !== "object") instruments = [ instruments ];
	instruments.map(function(data) {
		if (typeof(data) === "number") data = MIDI.GeneralMIDI.byId[data];
		return data;
	});
	///
	MIDI.soundfontUrl = conf.soundfontUrl || MIDI.soundfontUrl || "./soundfont/";
	/// Detect the best type of audio to use.
	MIDI.audioDetect(function(types) {
		var type = "";
		// use the most appropriate plugin if not specified
		if (typeof(type) === 'undefined') {
			if (plugins[window.location.hash]) {
				type = window.location.hash.substr(1);
			} else { //
				type = "";
			}
		}
		if (type === "") {
			if (window.webkitAudioContext) { // Chrome
				type = "webaudio";
			} else if (window.Audio) { // Firefox
				type = "audiotag";
			} else { // Internet Explorer
				type = "flash";
			}
		}
		if (!connect[type]) return;
		// use audio/ogg when supported
		var filetype = types["audio/ogg"] ? "ogg" : "mp3";
		// load the specified plugin
		connect[type](filetype, instruments, conf.callback);
	});
};

///

var connect = {};

connect.java = function(filetype, instruments, callback) {
	// works well cross-browser, and fully featured, but has delay when Java machine starts.
	if (MIDI.loader) MIDI.loader.message("Java API...");
	MIDI.Java.connect(callback);
};

connect.flash = function(filetype, instruments, callback) {
	// fairly quick, but requires loading of individual MP3s (more http requests).
	if (MIDI.loader) MIDI.loader.message("Flash API...");
	DOMLoader.script.add({
		src: "./inc/SoundManager2/script/soundmanager2.js",
		verify: "SoundManager",
		callback: function () {
			MIDI.Flash.connect(callback);
		}
	});
};

connect.audiotag = function(filetype, instruments, callback) {
	if (MIDI.loader) MIDI.loader.message("HTML5 Audio API...");
	// works ok, kinda like a drunken tuna fish, across the board.
	var queue = createQueue({
		items: instruments,
		getNext: function(instrumentId) {
			if (USE_XHR) {
				DOMLoader.sendRequest({
					url: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					onprogress: getPercent,
					onload: function (response) {
						MIDI.Soundfont[instrumentId] = JSON.parse(response.responseText);
						if (MIDI.loader) MIDI.loader.update(null, "Downloading", 100);
						queue.getNext();
					}
				});
			} else {
				DOMLoader.script.add({
					src: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					verify: instrumentId,
					callback: function() {
						if (MIDI.loader) MIDI.loader.update(null, "Downloading...", 100);
						queue.getNext();
					}
				});
			}
		},
		onComplete: function() {
			MIDI.AudioTag.connect(callback);
		}
	});
};

connect.webaudio = function(filetype, instruments, callback) {
	if (MIDI.loader) MIDI.loader.message("Web Audio API...");
	// works awesome! safari and chrome support
	var queue = createQueue({
		items: instruments,
		getNext: function(instrumentId) {
			if (USE_XHR) {
				DOMLoader.sendRequest({
					url: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					onprogress: getPercent,
					onload: function(response) {
						MIDI.Soundfont[instrumentId] = JSON.parse(response.responseText);
						if (MIDI.loader) MIDI.loader.update(null, "Downloading...", 100);
						queue.getNext();
					}
				});
			} else {
				DOMLoader.script.add({
					src: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					verify: "MIDI.Soundfont." + instrumentId,
					callback: function() {
					console.log(MIDI.Soundfont[instrumentId])
						if (MIDI.loader) MIDI.loader.update(null, "Downloading...", 100);
						queue.getNext();
					}
				});
			}
		},
		onComplete: function() {
			MIDI.WebAudioAPI.connect(callback);
		}
	});
};

/// Helpers

var plugins = {
	"#webaudio": true,
	"#audiotag": true,
	"#java": true,
	"#flash": true
};

var getPercent = function(event) {
	if (!this.totalSize) {
		if (this.getResponseHeader("Content-Length-Raw")) {
			this.totalSize = parseInt(this.getResponseHeader("Content-Length-Raw"));
		} else {
			this.totalSize = event.total;
		}
	}
	var percent = this.totalSize ? Math.round(event.loaded / this.totalSize * 100) : "";
	if (MIDI.loader) MIDI.loader.update(null, "Downloading...", percent);
};

var createQueue = function(conf) {
	var self = {};
	self.queue = [];
	for (var key in conf.items) {
		self.queue.push(conf.items[key]);
	}
	self.getNext = function() {
		if (!self.queue.length) return conf.onComplete();
		conf.getNext(self.queue.shift());
	};
	setTimeout(self.getNext, 1);
	return self;
};

})();<commit_msg>whoops, remove debug console.log<commit_after>/*
	-----------------------------------------------------------
	MIDI.loadPlugin : 0.1.2 : 01/18/2012
	-----------------------------------------------------------
	https://github.com/mudcube/MIDI.js
	-----------------------------------------------------------
	MIDI.loadPlugin({
		instrument: "acoustic_grand_piano", // or 1 (default)
		instruments: [ "acoustic_grand_piano", "acoustic_guitar_nylon" ], // or multiple instruments
		callback: function() { }
	});
*/

if (typeof (MIDI) === "undefined") var MIDI = {};
if (typeof (MIDI.Soundfont) === "undefined") MIDI.Soundfont = {};

(function() { "use strict";

// Turn on to get "onprogress" event. XHR will not work from file://
var USE_XHR = false;

MIDI.loadPlugin = function(conf) {
	if (typeof(conf) === "function") conf = { callback: conf };
	/// Get the instrument name.
	var instruments = conf.instruments || conf.instrument || "acoustic_grand_piano";
	if (typeof(instruments) !== "object") instruments = [ instruments ];
	instruments.map(function(data) {
		if (typeof(data) === "number") data = MIDI.GeneralMIDI.byId[data];
		return data;
	});
	///
	MIDI.soundfontUrl = conf.soundfontUrl || MIDI.soundfontUrl || "./soundfont/";
	/// Detect the best type of audio to use.
	MIDI.audioDetect(function(types) {
		var type = "";
		// use the most appropriate plugin if not specified
		if (typeof(type) === 'undefined') {
			if (plugins[window.location.hash]) {
				type = window.location.hash.substr(1);
			} else { //
				type = "";
			}
		}
		if (type === "") {
			if (window.webkitAudioContext) { // Chrome
				type = "webaudio";
			} else if (window.Audio) { // Firefox
				type = "audiotag";
			} else { // Internet Explorer
				type = "flash";
			}
		}
		if (!connect[type]) return;
		// use audio/ogg when supported
		var filetype = types["audio/ogg"] ? "ogg" : "mp3";
		// load the specified plugin
		connect[type](filetype, instruments, conf.callback);
	});
};

///

var connect = {};

connect.java = function(filetype, instruments, callback) {
	// works well cross-browser, and fully featured, but has delay when Java machine starts.
	if (MIDI.loader) MIDI.loader.message("Java API...");
	MIDI.Java.connect(callback);
};

connect.flash = function(filetype, instruments, callback) {
	// fairly quick, but requires loading of individual MP3s (more http requests).
	if (MIDI.loader) MIDI.loader.message("Flash API...");
	DOMLoader.script.add({
		src: "./inc/SoundManager2/script/soundmanager2.js",
		verify: "SoundManager",
		callback: function () {
			MIDI.Flash.connect(callback);
		}
	});
};

connect.audiotag = function(filetype, instruments, callback) {
	if (MIDI.loader) MIDI.loader.message("HTML5 Audio API...");
	// works ok, kinda like a drunken tuna fish, across the board.
	var queue = createQueue({
		items: instruments,
		getNext: function(instrumentId) {
			if (USE_XHR) {
				DOMLoader.sendRequest({
					url: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					onprogress: getPercent,
					onload: function (response) {
						MIDI.Soundfont[instrumentId] = JSON.parse(response.responseText);
						if (MIDI.loader) MIDI.loader.update(null, "Downloading", 100);
						queue.getNext();
					}
				});
			} else {
				DOMLoader.script.add({
					src: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					verify: instrumentId,
					callback: function() {
						if (MIDI.loader) MIDI.loader.update(null, "Downloading...", 100);
						queue.getNext();
					}
				});
			}
		},
		onComplete: function() {
			MIDI.AudioTag.connect(callback);
		}
	});
};

connect.webaudio = function(filetype, instruments, callback) {
	if (MIDI.loader) MIDI.loader.message("Web Audio API...");
	// works awesome! safari and chrome support
	var queue = createQueue({
		items: instruments,
		getNext: function(instrumentId) {
			if (USE_XHR) {
				DOMLoader.sendRequest({
					url: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					onprogress: getPercent,
					onload: function(response) {
						MIDI.Soundfont[instrumentId] = JSON.parse(response.responseText);
						if (MIDI.loader) MIDI.loader.update(null, "Downloading...", 100);
						queue.getNext();
					}
				});
			} else {
				DOMLoader.script.add({
					src: MIDI.soundfontUrl + instrumentId + "-" + filetype + ".js",
					verify: "MIDI.Soundfont." + instrumentId,
					callback: function() {
						if (MIDI.loader) MIDI.loader.update(null, "Downloading...", 100);
						queue.getNext();
					}
				});
			}
		},
		onComplete: function() {
			MIDI.WebAudioAPI.connect(callback);
		}
	});
};

/// Helpers

var plugins = {
	"#webaudio": true,
	"#audiotag": true,
	"#java": true,
	"#flash": true
};

var getPercent = function(event) {
	if (!this.totalSize) {
		if (this.getResponseHeader("Content-Length-Raw")) {
			this.totalSize = parseInt(this.getResponseHeader("Content-Length-Raw"));
		} else {
			this.totalSize = event.total;
		}
	}
	var percent = this.totalSize ? Math.round(event.loaded / this.totalSize * 100) : "";
	if (MIDI.loader) MIDI.loader.update(null, "Downloading...", percent);
};

var createQueue = function(conf) {
	var self = {};
	self.queue = [];
	for (var key in conf.items) {
		self.queue.push(conf.items[key]);
	}
	self.getNext = function() {
		if (!self.queue.length) return conf.onComplete();
		conf.getNext(self.queue.shift());
	};
	setTimeout(self.getNext, 1);
	return self;
};

})();<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Thermometer node, see https://github.com/phetsims/scenery-phet/issues/43
 *
 * @author Aaron Davis
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var ShadedSphereNode = require( 'SCENERY_PHET/ShadedSphereNode' );
  var LinearGradient = require( 'SCENERY/util/LinearGradient' );
  var Shape = require( 'KITE/Shape' );
  var LinearFunction = require( 'DOT/LinearFunction' );

  function ThermometerNode( minTemperature, maxTemperature, temperatureProperty, options ) {

    options = _.extend( {
      bulbDiameter: 50,
      tubeWidth: 30,
      tubeHeight: 100,
      lineWidth: 4,
      outlineStroke: 'black',
      tickSpacing: 15,
      majorTickLength: 15,
      minorTickLength: 7.5,
      fluidSphereSpacing: 2, // the empty space between the fluid sphere and the thermometer outline
      fluidRectSpacing: 2, // the empty space between the fluid in the tube and the thermometer outline
      backgroundColor: null,

      // all the default colors are shades of red
      fluidMainColor: '#850e0e', // the main color of the shaded sphere and the left side of the tube gradient
      fluidHighlightColor: '#ff7575', // the highlight color of the shaded sphere and the middle of the tube gradient
      fluidRightSideColor: '#c41515' // the right side of the tube gradient
    }, options );

    Node.call( this );

    // assume the center of the bulb is at (0, 0) and let the client code move to the correct place
    var bulbCenterX = 0;
    var bulbCenterY = 0;

    // Create a shaded sphere to act as the bulb fill
    var fluidSphere = new ShadedSphereNode( options.bulbDiameter - options.lineWidth - options.fluidSphereSpacing * 2,
      {
        centerX: bulbCenterX,
        centerY: bulbCenterY,
        mainColor: options.fluidMainColor,
        highlightColor: options.fluidHighlightColor,
        highlightXOffset: -0.2,
        highlightYOffset: -0.2,
        rotation: Math.PI / 2
      } );

    // Angles for the outline of the bulb
    var startAngle = -Math.acos( options.tubeWidth / options.bulbDiameter );
    var endAngle = Math.PI - startAngle;

    // Create the outline for the thermometer
    var shape = new Shape()
      .arc( bulbCenterX, bulbCenterY, options.bulbDiameter / 2, startAngle, endAngle )
      .verticalLineToRelative( -options.tubeHeight );

    var upperLeftCorner = shape.getLastPoint();
    shape.arc( upperLeftCorner.x + options.tubeWidth / 2, upperLeftCorner.y, options.tubeWidth / 2, Math.PI, 0 )
      .verticalLineToRelative( options.tubeHeight ).close();

    var tickMarkLength = options.tubeWidth * 0.5;
    shape.moveToPoint( upperLeftCorner ).moveToRelative( tickMarkLength ).horizontalLineToRelative( -tickMarkLength );
    for ( var i = 0; i < Math.floor( options.tubeHeight / options.tickSpacing ); i++ ) {
      if ( i % 2 === 0 ) {
        shape.moveToRelative( options.minorTickLength, options.tickSpacing ).horizontalLineToRelative( -options.minorTickLength );
      } else {
        shape.moveToRelative( options.majorTickLength, options.tickSpacing ).horizontalLineToRelative( -options.majorTickLength );
      }
    }

    var outline = new Path( shape,
      {
        stroke: options.outlineStroke,
        lineWidth: options.lineWidth
      } );

    // parameters for the fluid rectangle
    var fluidWidth = options.tubeWidth - options.lineWidth - options.fluidRectSpacing * 2;
    var rectangleX = upperLeftCorner.x + options.lineWidth / 2 + options.fluidRectSpacing;
    var tubeBase = upperLeftCorner.y + options.tubeHeight;
    var fluidBase = bulbCenterY; // put the base of the rectangle in at the center of the bulb to make sure there is no break between them
    var fluidOffset = fluidBase - tubeBase; // the 0 temperature point of the rectangle
    var maxFluidHeight = options.tubeHeight;

    var fluidRectangleGradient = new LinearGradient( rectangleX, 0, rectangleX + fluidWidth, 0 ).
      addColorStop( 0, options.fluidMainColor ).
      addColorStop( 0.5, options.fluidHighlightColor ).
      addColorStop( 0.7, options.fluidHighlightColor ).
      addColorStop( 1, options.fluidRightSideColor );

    var fluidRectangle = new Rectangle( 0, 0, fluidWidth, 0, { fill: fluidRectangleGradient } );

    var temperatureLinearFunction = new LinearFunction( minTemperature, maxTemperature, fluidOffset, maxFluidHeight + fluidOffset );
    temperatureProperty.link( function( temp ) {
      var fluidHeight = temperatureLinearFunction( temp );
      fluidRectangle.setRect( rectangleX, fluidBase - fluidHeight, fluidWidth, fluidHeight );
    } );

    if ( options.backgroundColor ) {
      var backgroundY = upperLeftCorner.y - options.tubeWidth / 2;
      var backgroundHeight = options.tubeHeight + options.tubeWidth / 2;
      var backgroundRectangle = new Rectangle( upperLeftCorner.x, backgroundY, options.tubeWidth, backgroundHeight,
        { fill: options.backgroundColor } );
      backgroundRectangle.setClipArea( shape );
      this.addChild( backgroundRectangle );
    }
    this.addChild( fluidRectangle );
    this.addChild( fluidSphere );
    this.addChild( outline );

    this.mutate( options );
  }

  return inherit( Node, ThermometerNode );
} );<commit_msg>add option to clip fluid in ThermometerNode, see #43<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Thermometer node, see https://github.com/phetsims/scenery-phet/issues/43
 *
 * @author Aaron Davis
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var ShadedSphereNode = require( 'SCENERY_PHET/ShadedSphereNode' );
  var LinearGradient = require( 'SCENERY/util/LinearGradient' );
  var Shape = require( 'KITE/Shape' );
  var LinearFunction = require( 'DOT/LinearFunction' );

  function ThermometerNode( minTemperature, maxTemperature, temperatureProperty, options ) {

    options = _.extend( {
      bulbDiameter: 50,
      tubeWidth: 30,
      tubeHeight: 100,
      lineWidth: 4,
      outlineStroke: 'black',
      tickSpacing: 15,
      majorTickLength: 15,
      minorTickLength: 7.5,
      clipFluidRectangle: true,
      fluidSphereSpacing: 2, // the empty space between the fluid sphere and the thermometer outline
      fluidRectSpacing: 2, // the empty space between the fluid in the tube and the thermometer outline

      // leave as null to have a transparent background. If a color is given, then an extra Rectangle is created for the background
      backgroundColor: null,

      // all the default colors are shades of red
      fluidMainColor: '#850e0e', // the main color of the shaded sphere and the left side of the tube gradient
      fluidHighlightColor: '#ff7575', // the highlight color of the shaded sphere and the middle of the tube gradient
      fluidRightSideColor: '#c41515' // the right side of the tube gradient
    }, options );

    Node.call( this );

    // assume the center of the bulb is at (0, 0) and let the client code move to the correct place
    var bulbCenterX = 0;
    var bulbCenterY = 0;

    // Create a shaded sphere to act as the bulb fill
    var fluidSphere = new ShadedSphereNode( options.bulbDiameter - options.lineWidth - options.fluidSphereSpacing * 2,
      {
        centerX: bulbCenterX,
        centerY: bulbCenterY,
        mainColor: options.fluidMainColor,
        highlightColor: options.fluidHighlightColor,
        highlightXOffset: -0.2,
        highlightYOffset: -0.2,
        rotation: Math.PI / 2
      } );

    // Angles for the outline of the bulb
    var startAngle = -Math.acos( options.tubeWidth / options.bulbDiameter );
    var endAngle = Math.PI - startAngle;

    // Create the outline for the thermometer
    var shape = new Shape()
      .arc( bulbCenterX, bulbCenterY, options.bulbDiameter / 2, startAngle, endAngle )
      .verticalLineToRelative( -options.tubeHeight );

    var upperLeftCorner = shape.getLastPoint();
    shape.arc( upperLeftCorner.x + options.tubeWidth / 2, upperLeftCorner.y, options.tubeWidth / 2, Math.PI, 0 )
      .verticalLineToRelative( options.tubeHeight ).close();

    var tickMarkLength = options.tubeWidth * 0.5;
    shape.moveToPoint( upperLeftCorner ).moveToRelative( tickMarkLength ).horizontalLineToRelative( -tickMarkLength );
    for ( var i = 0; i < Math.floor( options.tubeHeight / options.tickSpacing ); i++ ) {
      if ( i % 2 === 0 ) {
        shape.moveToRelative( options.minorTickLength, options.tickSpacing ).horizontalLineToRelative( -options.minorTickLength );
      }
      else {
        shape.moveToRelative( options.majorTickLength, options.tickSpacing ).horizontalLineToRelative( -options.majorTickLength );
      }
    }

    var outline = new Path( shape,
      {
        stroke: options.outlineStroke,
        lineWidth: options.lineWidth
      } );

    // parameters for the fluid rectangle
    var fluidWidth = options.tubeWidth - options.lineWidth - options.fluidRectSpacing * 2;
    var rectangleX = upperLeftCorner.x + options.lineWidth / 2 + options.fluidRectSpacing;
    var tubeBase = upperLeftCorner.y + options.tubeHeight;
    var fluidBase = bulbCenterY; // put the base of the rectangle in at the center of the bulb to make sure there is no break between them
    var fluidOffset = fluidBase - tubeBase; // the 0 temperature point of the rectangle
    var maxFluidHeight = options.tubeHeight;

    var fluidRectangleGradient = new LinearGradient( rectangleX, 0, rectangleX + fluidWidth, 0 ).
      addColorStop( 0, options.fluidMainColor ).
      addColorStop( 0.5, options.fluidHighlightColor ).
      addColorStop( 0.7, options.fluidHighlightColor ).
      addColorStop( 1, options.fluidRightSideColor );

    var fluidRectangle = new Rectangle( 0, 0, fluidWidth, 0, { fill: fluidRectangleGradient } );
    if ( options.clipFluidRectangle ) { fluidRectangle.setClipArea( shape ); }

    var temperatureLinearFunction = new LinearFunction( minTemperature, maxTemperature, fluidOffset, maxFluidHeight + fluidOffset );
    temperatureProperty.link( function( temp ) {
      var fluidHeight = temperatureLinearFunction( temp );
      fluidRectangle.setRect( rectangleX, fluidBase - fluidHeight, fluidWidth, fluidHeight );
    } );

    if ( options.backgroundColor ) {
      var backgroundY = upperLeftCorner.y - options.tubeWidth / 2;
      var backgroundHeight = options.tubeHeight + options.tubeWidth / 2;
      var backgroundRectangle = new Rectangle( upperLeftCorner.x, backgroundY, options.tubeWidth, backgroundHeight,
        { fill: options.backgroundColor } );
      backgroundRectangle.setClipArea( shape );
      this.addChild( backgroundRectangle );
    }
    this.addChild( fluidRectangle );
    this.addChild( fluidSphere );
    this.addChild( outline );

    this.mutate( options );
  }

  return inherit( Node, ThermometerNode );
} );<|endoftext|>


<commit_before>// Copyright 2014-2020, University of Colorado Boulder

/**
 * U-Turn arrow shape, for use with "reset" or "undo" purposes
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Shape from '../../kite/js/Shape.js';
import inherit from '../../phet-core/js/inherit.js';
import sceneryPhet from './sceneryPhet.js';

/**
 * @param {number} size A size factor (it'll be a bit bigger)
 * @constructor
 */
function UTurnArrowShape( size ) {
  Shape.call( this );

  const strokeWidth = size * 0.3;
  const strokeOffset = strokeWidth / 2;
  const mainWidth = size * 0.6;
  const mainHeight = size;
  const headWidth = size * 0.5;
  const headHeight = size * 0.75;
  const halfHeadWidth = headWidth / 2;
  const halfHeadHeight = headHeight / 2;

  // starts adjacent to the arrowhead on the top, going clockwise
  this.moveTo( halfHeadWidth, -strokeOffset );
  this.lineTo( mainWidth, -strokeOffset );
  // arc (mainWidth,-strokeOffset) => (mainWidth,mainHeight+strokeOffset)
  this.arc( mainWidth, mainHeight / 2, mainHeight / 2 + strokeOffset, -Math.PI / 2, Math.PI / 2, false );
  this.lineTo( 0, mainHeight + strokeOffset );
  this.lineTo( 0, mainHeight - strokeOffset );
  this.lineTo( mainWidth, mainHeight - strokeOffset );
  // arc (mainWidth,mainHeight-strokeOffset) => (mainWidth,strokeOffset)
  this.arc( mainWidth, mainHeight / 2, mainHeight / 2 - strokeOffset, Math.PI / 2, -Math.PI / 2, true );
  this.lineTo( halfHeadWidth, strokeOffset );
  // three lines of the arrow head
  this.lineTo( halfHeadWidth, halfHeadHeight );
  this.lineTo( -halfHeadWidth, 0 );
  this.lineTo( halfHeadWidth, -halfHeadHeight );
  this.close();
}

sceneryPhet.register( 'UTurnArrowShape', UTurnArrowShape );

inherit( Shape, UTurnArrowShape );
export default UTurnArrowShape;<commit_msg>ES6 UTurnArrowShape, see https://github.com/phetsims/tasks/issues/1044<commit_after>// Copyright 2014-2020, University of Colorado Boulder

/**
 * U-Turn arrow shape, for use with "reset" or "undo" purposes
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Shape from '../../kite/js/Shape.js';
import sceneryPhet from './sceneryPhet.js';

class UTurnArrowShape extends Shape {
  /**
   * @param {number} size A size factor (it'll be a bit bigger)
   */
  constructor( size ) {
    super();

    const strokeWidth = size * 0.3;
    const strokeOffset = strokeWidth / 2;
    const mainWidth = size * 0.6;
    const mainHeight = size;
    const headWidth = size * 0.5;
    const headHeight = size * 0.75;
    const halfHeadWidth = headWidth / 2;
    const halfHeadHeight = headHeight / 2;

    // starts adjacent to the arrowhead on the top, going clockwise
    this.moveTo( halfHeadWidth, -strokeOffset );
    this.lineTo( mainWidth, -strokeOffset );
    // arc (mainWidth,-strokeOffset) => (mainWidth,mainHeight+strokeOffset)
    this.arc( mainWidth, mainHeight / 2, mainHeight / 2 + strokeOffset, -Math.PI / 2, Math.PI / 2, false );
    this.lineTo( 0, mainHeight + strokeOffset );
    this.lineTo( 0, mainHeight - strokeOffset );
    this.lineTo( mainWidth, mainHeight - strokeOffset );
    // arc (mainWidth,mainHeight-strokeOffset) => (mainWidth,strokeOffset)
    this.arc( mainWidth, mainHeight / 2, mainHeight / 2 - strokeOffset, Math.PI / 2, -Math.PI / 2, true );
    this.lineTo( halfHeadWidth, strokeOffset );
    // three lines of the arrow head
    this.lineTo( halfHeadWidth, halfHeadHeight );
    this.lineTo( -halfHeadWidth, 0 );
    this.lineTo( halfHeadWidth, -halfHeadHeight );
    this.close();
  }
}

sceneryPhet.register( 'UTurnArrowShape', UTurnArrowShape );

export default UTurnArrowShape;<|endoftext|>