<commit_before>/*
 * L.Transition native implementation that powers Leaflet animation
 * in browsers that support CSS3 Transitions
 */

L.Transition = L.Transition.extend({
	statics: (function () {
		var transition = L.DomUtil.TRANSITION,
			transitionEnd = (transition === 'webkitTransition' || transition === 'OTransition' ?
				transition + 'End' : 'transitionend');

		return {
			NATIVE: !!transition,

			TRANSITION: transition,
			PROPERTY: transition + 'Property',
			DURATION: transition + 'Duration',
			EASING: transition + 'TimingFunction',
			END: transitionEnd,

			// transition-property value to use with each particular custom property
			CUSTOM_PROPS_PROPERTIES: {
				position: L.Browser.any3d ? L.DomUtil.TRANSFORM : 'top, left'
			}
		};
	}()),

	options: {
		fakeStepInterval: 100
	},

	initialize: function (/*HTMLElement*/ el, /*Object*/ options) {
		this._el = el;
		L.Util.setOptions(this, options);

		L.DomEvent.on(el, L.Transition.END, this._onTransitionEnd, this);
		this._onFakeStep = L.Util.bind(this._onFakeStep, this);
	},

	run: function (/*Object*/ props)
	{
		var prop,
			propsList = [],
			customProp = L.Transition.CUSTOM_PROPS_PROPERTIES;

		for (prop in props) {
			if (props.hasOwnProperty(prop)) {
				prop = customProp[prop] ? customProp[prop] : prop;
				prop = this._dasherize(prop);
				propsList.push(prop);
			}
		}

		this._el.style[L.Transition.DURATION] = this.options.duration + 's';
		this._el.style[L.Transition.EASING] = this.options.easing;
		this._el.style[L.Transition.PROPERTY] = propsList.join(', ');

		for (prop in props) {
			if (props.hasOwnProperty(prop)) {
				this._setProperty(prop, props[prop]);
			}
		}

		this._inProgress = true;

		this.fire('start');

		if (L.Browser.mobileWebkit) {
			// Set up a slightly delayed call to a backup event if webkitTransitionEnd doesn't fire properly
			this.backupEventFire = setTimeout(L.Util.bind(this._onBackupFireEnd, this), this.options.duration * 1.2 * 1000);
		}

		if (L.Transition.NATIVE) {
			clearInterval(this._timer);
			this._timer = setInterval(this._onFakeStep, this.options.fakeStepInterval);
		} else {
			this._onTransitionEnd();
		}
	},

	_dasherize: (function () {
		var re = /([A-Z])/g;

		function replaceFn(w) {
			return '-' + w.toLowerCase();
		}

		return function (str) {
			return str.replace(re, replaceFn);
		};
	}()),

	_onFakeStep: function () {
		this.fire('step');
	},

	_onTransitionEnd: function (e) {
		if (this._inProgress) {
			this._inProgress = false;
			clearInterval(this._timer);

			this._el.style[L.Transition.TRANSITION] = '';

			// Clear the delayed call to the backup event, we have recieved some form of webkitTransitionEnd
			clearTimeout(this.backupEventFire);
			delete this.backupEventFire;

			this.fire('step');

			if (e && e.type) {
				this.fire('end');
			}
		}
	},

	_onBackupFireEnd: function () {
		// Create and fire a transitionEnd event on the element.

		var event = document.createEvent("Event");
		event.initEvent(L.Transition.END, true, false);
		this._el.dispatchEvent(event);
	}
});
<commit_msg>Code conventions adherence<commit_after>/*
 * L.Transition native implementation that powers Leaflet animation
 * in browsers that support CSS3 Transitions
 */

L.Transition = L.Transition.extend({
	statics: (function () {
		var transition = L.DomUtil.TRANSITION,
			transitionEnd = (transition === 'webkitTransition' || transition === 'OTransition' ?
				transition + 'End' : 'transitionend');

		return {
			NATIVE: !!transition,

			TRANSITION: transition,
			PROPERTY: transition + 'Property',
			DURATION: transition + 'Duration',
			EASING: transition + 'TimingFunction',
			END: transitionEnd,

			// transition-property value to use with each particular custom property
			CUSTOM_PROPS_PROPERTIES: {
				position: L.Browser.any3d ? L.DomUtil.TRANSFORM : 'top, left'
			}
		};
	}()),

	options: {
		fakeStepInterval: 100
	},

	initialize: function (/*HTMLElement*/ el, /*Object*/ options) {
		this._el = el;
		L.Util.setOptions(this, options);

		L.DomEvent.on(el, L.Transition.END, this._onTransitionEnd, this);
		this._onFakeStep = L.Util.bind(this._onFakeStep, this);
	},

	run: function (/*Object*/ props) {
		var prop,
			propsList = [],
			customProp = L.Transition.CUSTOM_PROPS_PROPERTIES;

		for (prop in props) {
			if (props.hasOwnProperty(prop)) {
				prop = customProp[prop] ? customProp[prop] : prop;
				prop = this._dasherize(prop);
				propsList.push(prop);
			}
		}

		this._el.style[L.Transition.DURATION] = this.options.duration + 's';
		this._el.style[L.Transition.EASING] = this.options.easing;
		this._el.style[L.Transition.PROPERTY] = propsList.join(', ');

		for (prop in props) {
			if (props.hasOwnProperty(prop)) {
				this._setProperty(prop, props[prop]);
			}
		}

		this._inProgress = true;

		this.fire('start');

		if (L.Browser.mobileWebkit) {
			// Set up a slightly delayed call to a backup event if webkitTransitionEnd doesn't fire properly
			this.backupEventFire = setTimeout(L.Util.bind(this._onBackupFireEnd, this), this.options.duration * 1.2 * 1000);
		}

		if (L.Transition.NATIVE) {
			clearInterval(this._timer);
			this._timer = setInterval(this._onFakeStep, this.options.fakeStepInterval);
		} else {
			this._onTransitionEnd();
		}
	},

	_dasherize: (function () {
		var re = /([A-Z])/g;

		function replaceFn(w) {
			return '-' + w.toLowerCase();
		}

		return function (str) {
			return str.replace(re, replaceFn);
		};
	}()),

	_onFakeStep: function () {
		this.fire('step');
	},

	_onTransitionEnd: function (e) {
		if (this._inProgress) {
			this._inProgress = false;
			clearInterval(this._timer);

			this._el.style[L.Transition.TRANSITION] = '';

			// Clear the delayed call to the backup event, we have recieved some form of webkitTransitionEnd
			clearTimeout(this.backupEventFire);
			delete this.backupEventFire;

			this.fire('step');

			if (e && e.type) {
				this.fire('end');
			}
		}
	},

	_onBackupFireEnd: function () {
		// Create and fire a transitionEnd event on the element.

		var event = document.createEvent("Event");
		event.initEvent(L.Transition.END, true, false);
		this._el.dispatchEvent(event);
	}
});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

// DbxrefList
// ==========
// Display comma-separated list of linked external IDs/dbxrefs. For simplicity, I'll just call
// these "dbxrefs" from now. This uses a global array (dbxrefPrefixMap below) of possible dbxref
// URL patterns based on dbxref prefixes.
//
// Dbxrefs usually look like {prefix}:{value}, and this maps to a URL that includes the value in
// some way, maybe as a REST endpoint (https://abc.com/{value}) or as part of a query string
// (https://abc.com/?value={value}). The prefix selects which URL pattern to use.
//
// A URL pattern here is the URL to link to for each prefix, and with a "{0}" embedded in the
// pattern that shows where the {value} should go. For example, if we have a dbxref
// "UniProtKB:1234" then you can see from the dbxrefPrefixMap global that this maps to the URL
// pattern:
//
// http://www.uniprot.org/uniprot/{0}
//
// Because this is the simplest case that needs no more complex processing, the resulting link that
// <DbxrefList> generates for this example is:
//
// http://www.uniprot.org/uniprot/1234
//
// Preprocessor
// ------------
// Dbxrefs aren't always so simple and need some massaging before DbxrefList generates the URL. An
// example is:
//
//     "GEO:GSM1234" that should generate https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=1234
//     "GEO:SAMN123" that should generate https://www.ncbi.nlm.nih.gov/biosample/1234
//
// They both use the "GEO" prefix but map to different URL patterns depending on the following
// value. To handle this, dbxrefPrefixMap includes a preprocess for GEO that examines the dbxref
// value and returns a different URL if it detects the "SAMN" string at the start.
//
// The preprocessor callback takes the given `context` and `dbxref` string, and returns an object
// with zero, one, or both of these properties:
//
// {
//     altUrlPattern: String with the alternate URL pattern to use instead of the default one.
//     altValue: Dbxref value to use instead of the one in the dbxref string
// }
//
// `altUrlPattern` is a URL *pattern*, so it probably should include {0} so that this component
// replaces that with the value. You could even provide some other replacement pattern, like {1}
// maybe, that the postprocessor can replace if needed.
//
// Postprocessor
// ------------
// Sometimes the generated URL needs modification, like maybe it needs a second value placed
// somewhere in it. The postprocessor can do this. It receives the given `context`, `dbxref`, and
// the URL pattern after substitution. We normally call this *after* value substitution has taken
// place, so we have a URL, not a URL pattern. But the postprocessor can do its own value
// substitution by putting something like {1}, {2} etc. which gets preserved for the postprocessor
// to do its own substitution.
//

export const dbxrefPrefixMap = {
    UniProtKB: {
        pattern: 'http://www.uniprot.org/uniprot/{0}',
    },
    HGNC: {
        pattern: 'http://www.genecards.org/cgi-bin/carddisp.pl?gene={0}',
        preprocessor: (context) => {
            // For dbxrefs in targets, use the symbol of the first gene in target.genes instead of the dbxref value.
            if (context['@type'][0] === 'Target' && context.genes && context.genes.length > 0) {
                return { altValue: context.genes[0].symbol };
            }
            // If a gene displays its dbxrefs, use HGNC URL as NCBI Entrez does.
            if (context['@type'][0] === 'Gene') {
                return { altUrlPattern: 'https://www.genenames.org/cgi-bin/gene_symbol_report?hgnc_id={0}' };
            }
            return {};
        },
    },
    ENSEMBL: {
        pattern: 'http://www.ensembl.org/Homo_sapiens/Gene/Summary?g={0}',
        preprocessor: (context) => {
            // The URL is for human by default for ENSEMBL dbxrefs.
            if (context.organism && context.organism.scientific_name === 'Mus musculus') {
                return { altUrlPattern: 'http://www.ensembl.org/Mus_musculus/Gene/Summary?g={0}' };
            }
            return {};
        },
    },
    GeneID: {
        pattern: 'https://www.ncbi.nlm.nih.gov/gene/{0}',
    },
    GEO: {
        pattern: 'https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc={0}',
        preprocessor: (context, dbxref) => {
            // If the first four characters of the GEO value is "SAMN" then we need to use a
            // different URL pattern.
            const value = dbxref.split(':');
            if (value[1] && value[1].substr(0, 4) === 'SAMN') {
                return { altUrlPattern: 'https://www.ncbi.nlm.nih.gov/biosample/{0}' };
            }
            return {};
        },
    },
    IHEC: {
        pattern: 'http://www.ebi.ac.uk/vg/epirr/view/{0}',
    },
    Cellosaurus: {
        pattern: 'https://web.expasy.org/cellosaurus/{0}',
    },
    FlyBase: {
        pattern: 'http://flybase.org/search/symbol/{0}',
        preprocessor: (context) => {
            // If a target displays its dbxrefs, use the fly stock URL.
            if (context['@type'][0] !== 'Target') {
                return { altUrlPattern: 'http://flybase.org/reports/{0}.html' };
            }
            return {};
        },
    },
    BDSC: {
        pattern: 'http://flystocks.bio.indiana.edu/stocks/{0}',
    },
    WormBase: {
        pattern: 'http://www.wormbase.org/species/c_elegans/gene/{0}',
        preprocessor: (context) => {
            // If a target or gene displays its dbxrefs, use the worm stock URL.
            if (context['@type'][0] !== 'Target' && context['@type'][0] !== 'Gene') {
                return { altUrlPattern: 'http://www.wormbase.org/species/c_elegans/strain/{0}' };
            }
            return {};
        },
    },
    CGC: {
        pattern: 'https://cgc.umn.edu/strain/{0}',
    },
    DSSC: {
        pattern: 'https://stockcenter.ucsd.edu/index.php?action=view&q={0}&table=Species&submit=Search',
    },
    'MGI.D': {
        pattern: 'http://www.informatics.jax.org/inbred_strains/mouse/docs/{0}.shtml',
    },
    MGI: {
        pattern: 'http://www.informatics.jax.org/marker/MGI:{0}',
    },
    RBPImage: {
        pattern: 'http://rnabiology.ircm.qc.ca/RBPImage/gene.php?cells={1}&targets={0}',
        postprocessor: (context, dbxref, urlPattern) => (
            // Experiments with RBPImage need to replace one urlPattern element with
            // biosample_term_name.
            (context['@type'][0] === 'Experiment' ? urlPattern.replace(/\{1\}/g, context.biosample_term_name) : urlPattern)
        ),
    },
    RefSeq: {
        pattern: 'https://www.ncbi.nlm.nih.gov/gene/?term={0}',
    },
    JAX: {
        pattern: 'https://www.jax.org/strain/{0}',
    },
    NBRP: {
        pattern: 'https://shigen.nig.ac.jp/c.elegans/mutants/DetailsSearch?lang=english&seq={0}',
    },
    'UCSC-ENCODE-mm9': {
        pattern: 'http://genome.ucsc.edu/cgi-bin/hgTracks?tsCurTab=advancedTab&tsGroup=Any&tsType=Any&hgt_mdbVar1=dccAccession&hgt_tSearch=search&hgt_tsDelRow=&hgt_tsAddRow=&hgt_tsPage=&tsSimple=&tsName=&tsDescr=&db=mm9&hgt_mdbVal1={0}',
    },
    'UCSC-ENCODE-hg19': {
        pattern: 'http://genome.ucsc.edu/cgi-bin/hgTracks?tsCurTab=advancedTab&tsGroup=Any&tsType=Any&hgt_mdbVar1=dccAccession&hgt_tSearch=search&hgt_tsDelRow=&hgt_tsAddRow=&hgt_tsPage=&tsSimple=&tsName=&tsDescr=&db=hg19&hgt_mdbVal1={0}',
    },
    'UCSC-ENCODE-cv': {
        pattern: 'http://genome.cse.ucsc.edu/cgi-bin/hgEncodeVocab?ra=encode%2Fcv.ra&term=%22{0}%22',
    },
    'UCSC-GB-mm9': {
        pattern: 'http://genome.cse.ucsc.edu/cgi-bin/hgTrackUi?db=mm9&g={0}',
    },
    'UCSC-GB-hg19': {
        pattern: 'http://genome.cse.ucsc.edu/cgi-bin/hgTrackUi?db=hg19&g={0}',
    },
    PMID: {
        pattern: 'https://www.ncbi.nlm.nih.gov/pubmed/?term={0}',
    },
    PMCID: {
        pattern: 'https://www.ncbi.nlm.nih.gov/pmc/articles/{0}',
    },
    doi: {
        pattern: 'https://doi.org/doi:{0}',
    },
    AR: {
        pattern: 'http://antibodyregistry.org/search.php?q={0}',
    },
    NIH: {
        pattern: 'https://search.usa.gov/search?utf8=%E2%9C%93&affiliate=grants.nih.gov&query={0}',
    },
    PGP: {
        pattern: 'https://my.pgp-hms.org/profile_public?hex={0}',
    },
    TRiP: {
        pattern: 'http://www.flyrnai.org/cgi-bin/DRSC_gene_lookup.pl?gname={0}',
    },
    DGGR: {
        pattern: 'https://kyotofly.kit.jp/cgi-bin/stocks/search_res_det.cgi?DB_NUM=1&DG_NUM={0}',
    },
    MIM: {
        pattern: 'https://www.ncbi.nlm.nih.gov/omim/{0}',
    },
    Vega: {
        pattern: 'http://vega.sanger.ac.uk/id/{0}',
    },
    miRBase: {
        pattern: 'http://www.mirbase.org/cgi-bin/mirna_entry.pl?acc={0}',
    },
    GO: {
        pattern: 'http://amigo.geneontology.org/amigo/term/GO:{0}',
    },
    'IMGT/GENE-DB': {
        pattern: 'http://www.imgt.org/IMGT_GENE-DB/GENElect?species=Homo+sapiens&query=2+{0}',
    },
};

/**
 * Convert a dbxref prefix and value to a URL using the same URL patterns as the <DbxrefList>
 * component below. This function does no pre- nor post-processing, so the given prefix and value
 * have to map to a real URL by themselves.
 *
 * @param {string} prefix - dbxref prefix string, like 'HGNC'
 * @param {string} value - String value you'd normally see after the colon in a dbxref
 * @return {string} - URL that the given prefix and value map to, or null if the mapping table doesn't include the given prefix.
 */
export function dbxrefHref(prefix, value) {
    const urlProcessor = dbxrefPrefixMap[prefix];
    if (urlProcessor) {
        return urlProcessor.pattern.replace(/\{0\}/g, encodeURIComponent(value));
    }
    return null;
}

/**
 * Internal component to display one dbxref as a string. It handles calling the pre- and post-
 * processor from `dbxrefPrefixMap` above, and looking up the URL for the given dbxref. It
 * generates either a link with the generated URL for the given dbxref and the dbxref itself as the
 * link text, o just the dbxref in a  if we don't have that dbxref in `dbxrefPrefixMap`.
 *
 * @prop {string} dbxref - String containing one dbxref string.
 * @prop {object} context - Object (Experiment, HumanDonor, etc.) containing the dbxref being
 *     displayed.
 */
const DbxrefUrl = (props) => {
    const { dbxref, context } = props;

    // Standard dbxref pattern: {prefix}:{value}. If the dbxref has more than one colon, only the
    // first colon splits the dbxref into `prefix` and `value`. The other colons get included as
    // part of the value. If the dbxref has no colons at all, prefix gets the whole dbxref string
    // and `value` gets the empty string.
    const prefix = dbxref.split(':', 1)[0];
    let value = dbxref.slice(prefix.length + 1);

    // Using the prefix, find the corresponding URL pattern, if any.
    const urlProcessor = dbxrefPrefixMap[prefix];
    if (urlProcessor) {
        // Get the urlPattern for the dbxref prefix. This pattern can be replaced by the preprocessor
        // during the next step.
        let urlPattern = urlProcessor.pattern;

        // Call the preprocessor if it exists to replace either the URL pattern, the value, or both.
        // Normally, the contents of the context object determines if a URL or value should change.
        if (urlProcessor.preprocessor) {
            const { altUrlPattern, altValue } = urlProcessor.preprocessor(context, dbxref);
            urlPattern = altUrlPattern || urlPattern;
            value = altValue || value;
        }

        // Now replace the {0} in the URL pattern with the value we extracted to form the final URL,
        // then display that as a link.
        let url = urlPattern.replace(/\{0\}/g, encodeURIComponent(value));

        // If, after replacing the {0} withx the value, the URL needs further modification, call the
        // caller-provided post-processor with the given dbxref and the generated URL.
        if (urlProcessor.postprocessor) {
            url = urlProcessor.postprocessor(context, dbxref, url);
        }

        // Return the final dbxref as a link.
        return {dbxref};
    }

    // The dbxref prefix didn't map to anything we know about, so just display the dbxref as
    // unlinked text.
    return {dbxref};
};

DbxrefUrl.propTypes = {
    dbxref: PropTypes.string.isRequired, // dbxref string
    context: PropTypes.object.isRequired, // Object that contains the dbxref
};

/**
 * Display a list of dbxrefs as comma-separated links to external sites. The links appear within a
 *

 list which work within a

 list.
 *
 * @prop {array} dbxrefs - Array of dbxref strings. You normally pass the dbxref, external_id,
 *     etc. property here directly.
 * @prop {object} context - Object (Experiment, HumanDonor, etc.) being displayed that contains the
 *     array of dbxrefs. Some dbxref links rely on information in this object, so for consistency
 *     this property is always required though probably rarely used.
 * @prop {string} addClasses - String with space-separated classes that gets added to the
 that
 *     contains the displayed list of dbxrefs. Optional.
 */
export const DbxrefList = (props) => {
    const { dbxrefs, context, addClasses } = props;

    return (

            {dbxrefs.map((dbxref, i) =>

<DbxrefUrl dbxref={dbxref} context={context} />

            )}

    );
};

DbxrefList.propTypes = {
    dbxrefs: PropTypes.array.isRequired, // Array of dbxref values to display
    context: PropTypes.object.isRequired, // Object containing the dbxref
    addClasses: PropTypes.string, // CSS class to apply to dbxref list
};

DbxrefList.defaultProps = {
    addClasses: '',
};
<commit_msg>ENCD-4375 Restore SRA dbxrefs linkouts (#2558)<commit_after>import React from 'react';
import PropTypes from 'prop-types';

// DbxrefList
// ==========
// Display comma-separated list of linked external IDs/dbxrefs. For simplicity, I'll just call
// these "dbxrefs" from now. This uses a global array (dbxrefPrefixMap below) of possible dbxref
// URL patterns based on dbxref prefixes.
//
// Dbxrefs usually look like {prefix}:{value}, and this maps to a URL that includes the value in
// some way, maybe as a REST endpoint (https://abc.com/{value}) or as part of a query string
// (https://abc.com/?value={value}). The prefix selects which URL pattern to use.
//
// A URL pattern here is the URL to link to for each prefix, and with a "{0}" embedded in the
// pattern that shows where the {value} should go. For example, if we have a dbxref
// "UniProtKB:1234" then you can see from the dbxrefPrefixMap global that this maps to the URL
// pattern:
//
// http://www.uniprot.org/uniprot/{0}
//
// Because this is the simplest case that needs no more complex processing, the resulting link that
// <DbxrefList> generates for this example is:
//
// http://www.uniprot.org/uniprot/1234
//
// Preprocessor
// ------------
// Dbxrefs aren't always so simple and need some massaging before DbxrefList generates the URL. An
// example is:
//
//     "GEO:GSM1234" that should generate https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=1234
//     "GEO:SAMN123" that should generate https://www.ncbi.nlm.nih.gov/biosample/1234
//
// They both use the "GEO" prefix but map to different URL patterns depending on the following
// value. To handle this, dbxrefPrefixMap includes a preprocess for GEO that examines the dbxref
// value and returns a different URL if it detects the "SAMN" string at the start.
//
// The preprocessor callback takes the given `context` and `dbxref` string, and returns an object
// with zero, one, or both of these properties:
//
// {
//     altUrlPattern: String with the alternate URL pattern to use instead of the default one.
//     altValue: Dbxref value to use instead of the one in the dbxref string
// }
//
// `altUrlPattern` is a URL *pattern*, so it probably should include {0} so that this component
// replaces that with the value. You could even provide some other replacement pattern, like {1}
// maybe, that the postprocessor can replace if needed.
//
// Postprocessor
// ------------
// Sometimes the generated URL needs modification, like maybe it needs a second value placed
// somewhere in it. The postprocessor can do this. It receives the given `context`, `dbxref`, and
// the URL pattern after substitution. We normally call this *after* value substitution has taken
// place, so we have a URL, not a URL pattern. But the postprocessor can do its own value
// substitution by putting something like {1}, {2} etc. which gets preserved for the postprocessor
// to do its own substitution.
//

export const dbxrefPrefixMap = {
    UniProtKB: {
        pattern: 'http://www.uniprot.org/uniprot/{0}',
    },
    HGNC: {
        pattern: 'http://www.genecards.org/cgi-bin/carddisp.pl?gene={0}',
        preprocessor: (context) => {
            // For dbxrefs in targets, use the symbol of the first gene in target.genes instead of the dbxref value.
            if (context['@type'][0] === 'Target' && context.genes && context.genes.length > 0) {
                return { altValue: context.genes[0].symbol };
            }
            // If a gene displays its dbxrefs, use HGNC URL as NCBI Entrez does.
            if (context['@type'][0] === 'Gene') {
                return { altUrlPattern: 'https://www.genenames.org/cgi-bin/gene_symbol_report?hgnc_id={0}' };
            }
            return {};
        },
    },
    ENSEMBL: {
        pattern: 'http://www.ensembl.org/Homo_sapiens/Gene/Summary?g={0}',
        preprocessor: (context) => {
            // The URL is for human by default for ENSEMBL dbxrefs.
            if (context.organism && context.organism.scientific_name === 'Mus musculus') {
                return { altUrlPattern: 'http://www.ensembl.org/Mus_musculus/Gene/Summary?g={0}' };
            }
            return {};
        },
    },
    GeneID: {
        pattern: 'https://www.ncbi.nlm.nih.gov/gene/{0}',
    },
    GEO: {
        pattern: 'https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc={0}',
        preprocessor: (context, dbxref) => {
            // If the first four characters of the GEO value is "SAMN" then we need to use a
            // different URL pattern.
            const value = dbxref.split(':');
            if (value[1] && value[1].substr(0, 4) === 'SAMN') {
                return { altUrlPattern: 'https://www.ncbi.nlm.nih.gov/biosample/{0}' };
            }
            return {};
        },
    },
    IHEC: {
        pattern: 'http://www.ebi.ac.uk/vg/epirr/view/{0}',
    },
    Cellosaurus: {
        pattern: 'https://web.expasy.org/cellosaurus/{0}',
    },
    FlyBase: {
        pattern: 'http://flybase.org/search/symbol/{0}',
        preprocessor: (context) => {
            // If a target displays its dbxrefs, use the fly stock URL.
            if (context['@type'][0] !== 'Target') {
                return { altUrlPattern: 'http://flybase.org/reports/{0}.html' };
            }
            return {};
        },
    },
    BDSC: {
        pattern: 'http://flystocks.bio.indiana.edu/stocks/{0}',
    },
    WormBase: {
        pattern: 'http://www.wormbase.org/species/c_elegans/gene/{0}',
        preprocessor: (context) => {
            // If a target or gene displays its dbxrefs, use the worm stock URL.
            if (context['@type'][0] !== 'Target' && context['@type'][0] !== 'Gene') {
                return { altUrlPattern: 'http://www.wormbase.org/species/c_elegans/strain/{0}' };
            }
            return {};
        },
    },
    CGC: {
        pattern: 'https://cgc.umn.edu/strain/{0}',
    },
    DSSC: {
        pattern: 'https://stockcenter.ucsd.edu/index.php?action=view&q={0}&table=Species&submit=Search',
    },
    'MGI.D': {
        pattern: 'http://www.informatics.jax.org/inbred_strains/mouse/docs/{0}.shtml',
    },
    MGI: {
        pattern: 'http://www.informatics.jax.org/marker/MGI:{0}',
    },
    RBPImage: {
        pattern: 'http://rnabiology.ircm.qc.ca/RBPImage/gene.php?cells={1}&targets={0}',
        postprocessor: (context, dbxref, urlPattern) => (
            // Experiments with RBPImage need to replace one urlPattern element with
            // biosample_term_name.
            (context['@type'][0] === 'Experiment' ? urlPattern.replace(/\{1\}/g, context.biosample_term_name) : urlPattern)
        ),
    },
    RefSeq: {
        pattern: 'https://www.ncbi.nlm.nih.gov/gene/?term={0}',
    },
    JAX: {
        pattern: 'https://www.jax.org/strain/{0}',
    },
    NBRP: {
        pattern: 'https://shigen.nig.ac.jp/c.elegans/mutants/DetailsSearch?lang=english&seq={0}',
    },
    'UCSC-ENCODE-mm9': {
        pattern: 'http://genome.ucsc.edu/cgi-bin/hgTracks?tsCurTab=advancedTab&tsGroup=Any&tsType=Any&hgt_mdbVar1=dccAccession&hgt_tSearch=search&hgt_tsDelRow=&hgt_tsAddRow=&hgt_tsPage=&tsSimple=&tsName=&tsDescr=&db=mm9&hgt_mdbVal1={0}',
    },
    'UCSC-ENCODE-hg19': {
        pattern: 'http://genome.ucsc.edu/cgi-bin/hgTracks?tsCurTab=advancedTab&tsGroup=Any&tsType=Any&hgt_mdbVar1=dccAccession&hgt_tSearch=search&hgt_tsDelRow=&hgt_tsAddRow=&hgt_tsPage=&tsSimple=&tsName=&tsDescr=&db=hg19&hgt_mdbVal1={0}',
    },
    'UCSC-ENCODE-cv': {
        pattern: 'http://genome.cse.ucsc.edu/cgi-bin/hgEncodeVocab?ra=encode%2Fcv.ra&term=%22{0}%22',
    },
    'UCSC-GB-mm9': {
        pattern: 'http://genome.cse.ucsc.edu/cgi-bin/hgTrackUi?db=mm9&g={0}',
    },
    'UCSC-GB-hg19': {
        pattern: 'http://genome.cse.ucsc.edu/cgi-bin/hgTrackUi?db=hg19&g={0}',
    },
    PMID: {
        pattern: 'https://www.ncbi.nlm.nih.gov/pubmed/?term={0}',
    },
    PMCID: {
        pattern: 'https://www.ncbi.nlm.nih.gov/pmc/articles/{0}',
    },
    doi: {
        pattern: 'https://doi.org/doi:{0}',
    },
    AR: {
        pattern: 'http://antibodyregistry.org/search.php?q={0}',
    },
    NIH: {
        pattern: 'https://search.usa.gov/search?utf8=%E2%9C%93&affiliate=grants.nih.gov&query={0}',
    },
    PGP: {
        pattern: 'https://my.pgp-hms.org/profile_public?hex={0}',
    },
    TRiP: {
        pattern: 'http://www.flyrnai.org/cgi-bin/DRSC_gene_lookup.pl?gname={0}',
    },
    DGGR: {
        pattern: 'https://kyotofly.kit.jp/cgi-bin/stocks/search_res_det.cgi?DB_NUM=1&DG_NUM={0}',
    },
    MIM: {
        pattern: 'https://www.ncbi.nlm.nih.gov/omim/{0}',
    },
    Vega: {
        pattern: 'http://vega.sanger.ac.uk/id/{0}',
    },
    miRBase: {
        pattern: 'http://www.mirbase.org/cgi-bin/mirna_entry.pl?acc={0}',
    },
    GO: {
        pattern: 'http://amigo.geneontology.org/amigo/term/GO:{0}',
    },
    'IMGT/GENE-DB': {
        pattern: 'http://www.imgt.org/IMGT_GENE-DB/GENElect?species=Homo+sapiens&query=2+{0}',
    },
    SRA: {
        pattern: 'http://www.ncbi.nlm.nih.gov/Traces/sra/?run={0}',
    },
};

/**
 * Convert a dbxref prefix and value to a URL using the same URL patterns as the <DbxrefList>
 * component below. This function does no pre- nor post-processing, so the given prefix and value
 * have to map to a real URL by themselves.
 *
 * @param {string} prefix - dbxref prefix string, like 'HGNC'
 * @param {string} value - String value you'd normally see after the colon in a dbxref
 * @return {string} - URL that the given prefix and value map to, or null if the mapping table doesn't include the given prefix.
 */
export function dbxrefHref(prefix, value) {
    const urlProcessor = dbxrefPrefixMap[prefix];
    if (urlProcessor) {
        return urlProcessor.pattern.replace(/\{0\}/g, encodeURIComponent(value));
    }
    return null;
}

/**
 * Internal component to display one dbxref as a string. It handles calling the pre- and post-
 * processor from `dbxrefPrefixMap` above, and looking up the URL for the given dbxref. It
 * generates either a link with the generated URL for the given dbxref and the dbxref itself as the
 * link text, o just the dbxref in a  if we don't have that dbxref in `dbxrefPrefixMap`.
 *
 * @prop {string} dbxref - String containing one dbxref string.
 * @prop {object} context - Object (Experiment, HumanDonor, etc.) containing the dbxref being
 *     displayed.
 */
const DbxrefUrl = (props) => {
    const { dbxref, context } = props;

    // Standard dbxref pattern: {prefix}:{value}. If the dbxref has more than one colon, only the
    // first colon splits the dbxref into `prefix` and `value`. The other colons get included as
    // part of the value. If the dbxref has no colons at all, prefix gets the whole dbxref string
    // and `value` gets the empty string.
    const prefix = dbxref.split(':', 1)[0];
    let value = dbxref.slice(prefix.length + 1);

    // Using the prefix, find the corresponding URL pattern, if any.
    const urlProcessor = dbxrefPrefixMap[prefix];
    if (urlProcessor) {
        // Get the urlPattern for the dbxref prefix. This pattern can be replaced by the preprocessor
        // during the next step.
        let urlPattern = urlProcessor.pattern;

        // Call the preprocessor if it exists to replace either the URL pattern, the value, or both.
        // Normally, the contents of the context object determines if a URL or value should change.
        if (urlProcessor.preprocessor) {
            const { altUrlPattern, altValue } = urlProcessor.preprocessor(context, dbxref);
            urlPattern = altUrlPattern || urlPattern;
            value = altValue || value;
        }

        // Now replace the {0} in the URL pattern with the value we extracted to form the final URL,
        // then display that as a link.
        let url = urlPattern.replace(/\{0\}/g, encodeURIComponent(value));

        // If, after replacing the {0} withx the value, the URL needs further modification, call the
        // caller-provided post-processor with the given dbxref and the generated URL.
        if (urlProcessor.postprocessor) {
            url = urlProcessor.postprocessor(context, dbxref, url);
        }

        // Return the final dbxref as a link.
        return {dbxref};
    }

    // The dbxref prefix didn't map to anything we know about, so just display the dbxref as
    // unlinked text.
    return {dbxref};
};

DbxrefUrl.propTypes = {
    dbxref: PropTypes.string.isRequired, // dbxref string
    context: PropTypes.object.isRequired, // Object that contains the dbxref
};

/**
 * Display a list of dbxrefs as comma-separated links to external sites. The links appear within a
 *

 list which work within a

 list.
 *
 * @prop {array} dbxrefs - Array of dbxref strings. You normally pass the dbxref, external_id,
 *     etc. property here directly.
 * @prop {object} context - Object (Experiment, HumanDonor, etc.) being displayed that contains the
 *     array of dbxrefs. Some dbxref links rely on information in this object, so for consistency
 *     this property is always required though probably rarely used.
 * @prop {string} addClasses - String with space-separated classes that gets added to the
 that
 *     contains the displayed list of dbxrefs. Optional.
 */
export const DbxrefList = (props) => {
    const { dbxrefs, context, addClasses } = props;

    return (

            {dbxrefs.map((dbxref, i) =>

<DbxrefUrl dbxref={dbxref} context={context} />

            )}

    );
};

DbxrefList.propTypes = {
    dbxrefs: PropTypes.array.isRequired, // Array of dbxref values to display
    context: PropTypes.object.isRequired, // Object containing the dbxref
    addClasses: PropTypes.string, // CSS class to apply to dbxref list
};

DbxrefList.defaultProps = {
    addClasses: '',
};
<|endoftext|>


<commit_before>/*global imagesLoaded, jQuery */

/******************************************
 * jQuery FitFrame
 *
 * A lightweight, easy-to-use jQuery plugin for responsive slide layout.
 *
 * Author          @jenkins118 (https://fabrik.io)
 * Copyright       Copyright (c) 2015 Phil Jenkins.
 * License         MIT
 * Version         0.0.0.1
 *
 ******************************************/

(function ($, window, undefined) {

  var PLUGIN_NAME = "fabrikStrip",
      INSTANCE_KEY = "plugin_" + PLUGIN_NAME;

  function FabrikStrip(element, options, defaults) {
    this.element = $(element);
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._init();
  }

  FabrikStrip.prototype = {

    goTo: function (index) {
      // Go to specific blade

      var self = this,
          bladesCount = $(self.options.bladesSelector).length;

      if (index > bladesCount - 1) {
        return;
      }

      $('button', $(self.options.pagerSelector)).show();

      if (index <= 0) {
        self.goToFirst();
      }
      else if (index >= bladesCount - 1) {
        self.goToLast();
      }
      else {
        var beforeWidth = 0;

        $(self.options.bladesSelector).each(function () {
          var $blade = $(this);

          if ($blade.index() < index) {
            beforeWidth += $blade.width();
          }
        });

        var viewableWidth = $(self.element[0]).width(),
            halfView = (viewableWidth - $(self.options.bladesSelector).eq(index).width()) / 2,
            pull = beforeWidth - halfView;

        this._setActive(index);
        this._setPull(-pull);

        this.options.afterChange(index);
        return index;
      }
    },

    goToFirst: function () {
      // Go to first blade
      $('.left', $(this.options.pagerSelector)).hide();
      this._setActive(0);
      this._setPull(0);

      this.options.afterChange(0);
      return 0;
    },

    goToLast: function () {
      // Go to last blade
      $('.right', $(this.options.pagerSelector)).hide();
      var pull = $(this.options.innerStripSelector).width() - $(this.element[0]).width(),
          index = $(this.options.bladesSelector).length - 1;

      this._setActive(index);
      this._setPull(-pull);

      this.options.afterChange(index);
      return index;
    },

    _init: function () {
      $('html').addClass('fabrik-strip');
      this._bind();
      this._setSizes();
      this._setActive(this.options.startIndex);
    },

    _setSizes: function () {

      var self = this,
          windowHeight = $(window).height(),
          windowWidth = $(window).width();

      if ($(self.options.headerSelector).length) {
        windowHeight -= $(self.options.headerSelector).height();
      }

      $(self.element[0]).height(windowHeight);
      $(self.options.bladesSelector).removeAttr('style');

      // after images are loaded get the widths of the blades so we can set parent container

      if (imagesLoaded !== undefined) {
        imagesLoaded(self.element[0], function () {
          var width = 0;

          $(self.options.bladesSelector).each(function () {

            var $blade = $(this),
                bladewidth = $(this).width(),
                $img = $('img', $blade);

            if ($img.length) {
              bladewidth = $img.width();
            }

            $blade.width(bladewidth);
            width += bladewidth;
          });

          $(self.options.innerStripSelector).width(width).addClass('blades-loaded');
        });
      }
      else {
        console.info("You need to add images Loaded plugin http://imagesloaded.desandro.com/");
      }

      var pagerWidth = $('.left').outerWidth(true),
          infoWidth = windowWidth - pagerWidth;

      if (windowWidth >= 1200) {
        infoWidth = $(self.element[0]).width() / 2;
      }

      $('.project-info-blade').width(infoWidth);

    },

    _setPull: function (int) {
      $(this.options.innerStripSelector).css({
        "-webkit-transform": "translate3d(" + int + "px, 0px, 0px)",
        "-moz-transform": "translate3d(" + int + "px, 0px, 0px)",
        "-ms-transform": "translate3d(" + int + "px, 0px, 0px)",
        "-o-transform": "translate3d(" + int + "px, 0px, 0px)",
        "transform": "translate3d(" + int + "px, 0px, 0px)"
      });
    },

    _setActive: function (index) {
      $(this.options.bladesSelector).removeClass('active');
      // Get the new active blade
      var $blade = $(this.options.bladesSelector).eq(index);
      $blade.addClass('active');

      $(this.element[0]).data('activeIndex', index);
    },

    _goToOnResize: function (index) {
      var self = this;

      setTimeout(function () {
        self.goTo(index);
      }, 200);
    },

    _bind: function () {
      // debounced resizing
      var self = this, t;

      $('button', $(self.options.pagerSelector)).on('click', function (e) {
        e.preventDefault();

        var activeIndex = $(self.element[0]).data('activeIndex'),
            index = activeIndex + 1;

        if ($(this).hasClass('left')) {
          index = activeIndex - 1;
        }

        self.options.beforeChange(activeIndex);

        self.goTo(index);
      });

      $(self.options.bladesSelector).on('click', function (e) {

        if (!$(this).hasClass('active')) {
          e.preventDefault();
          var activeIndex = $(self.element[0]).data('activeIndex');
          self.options.beforeChange(activeIndex);
          self.goTo($(this).index());
        }
      });

      $(window).on('resize.' + PLUGIN_NAME, function () {
        clearTimeout(t);
        t = setTimeout(function () {
          // On resize set the sizes
          self._setSizes();
          self._goToOnResize($(self.element[0]).data('activeIndex'));
        }, 100);
      });

      $(document.documentElement).keyup(function (event) {
        var activeIndex = 0,
            index = 0;

        // handle cursor keys
        if (event.keyCode == 37) {
          // go left
          activeIndex = $(self.element[0]).data('activeIndex');
          index = activeIndex - 1;

          self.options.beforeChange(activeIndex);
          self.goTo(index);
        } else if (event.keyCode == 39) {
          // go right
          activeIndex = $(self.element[0]).data('activeIndex');
          index = activeIndex + 1;

          self.options.beforeChange(activeIndex);
          self.goTo(index);
        }
      });

    }

  };

  $.fn[PLUGIN_NAME] = function (options) {

    var args = arguments,
      returns;

    this.each(function () {

      var instance = $.data(this, INSTANCE_KEY);

      if (instance) {
        // check if invoking public methods
        if (typeof (options) === 'string' && options[0] !== '_') {
          var method = instance[options];
          if (typeof (method) === 'function') {
            returns = method.apply(instance, Array.prototype.slice.call(args, 1));
          } else {
            // method missing
            $.error('Public method \'' + options + '\' does not exist on jQuery.' + PLUGIN_NAME);
          }
        }

      } else {
        $.data(this, INSTANCE_KEY, new FabrikStrip(this, options, $.fn[PLUGIN_NAME].defaults));
      }
    });

    // if the earlier cached method has a value return it, otherwise return this to preserve chainability
    return returns !== undefined ? returns : this;
  };

  $.fn[PLUGIN_NAME].defaults = {
    bladesSelector: '.blade',
    innerStripSelector: '.strip',
    headerSelector: null,
    pagerSelector: '.strip-pagers',
    startIndex: 0,
    afterChange: function () { },
    beforeChange: function () { },
  };

})(jQuery, window);<commit_msg>fixed issue with resize<commit_after>/*global imagesLoaded, jQuery */

/******************************************
 * jQuery FitFrame
 *
 * A lightweight, easy-to-use jQuery plugin for responsive slide layout.
 *
 * Author          @jenkins118 (https://fabrik.io)
 * Copyright       Copyright (c) 2015 Phil Jenkins.
 * License         MIT
 * Version         0.0.0.1
 *
 ******************************************/

(function ($, window, undefined) {

  var PLUGIN_NAME = "fabrikStrip",
      INSTANCE_KEY = "plugin_" + PLUGIN_NAME;

  function FabrikStrip(element, options, defaults) {
    this.element = $(element);
    this.options = $.extend({}, defaults, options);
    this._defaults = defaults;
    this._init();
  }

  FabrikStrip.prototype = {

    goTo: function (index) {
      // Go to specific blade

      var self = this,
          bladesCount = $(self.options.bladesSelector).length;

      if (index > bladesCount - 1) {
        return;
      }

      $('button', $(self.options.pagerSelector)).show();

      if (index <= 0) {
        self.goToFirst();
      }
      else if (index >= bladesCount - 1) {
        self.goToLast();
      }
      else {
        var beforeWidth = 0;

        $(self.options.bladesSelector).each(function () {
          var $blade = $(this);

          if ($blade.index() < index) {
            beforeWidth += $blade.width();
          }
        });

        var viewableWidth = $(self.element[0]).width(),
            halfView = (viewableWidth - $(self.options.bladesSelector).eq(index).width()) / 2,
            pull = beforeWidth - halfView;

        this._setActive(index);
        this._setPull(-pull);

        this.options.afterChange(index);
        return index;
      }
    },

    goToFirst: function () {
      // Go to first blade
      $('.left', $(this.options.pagerSelector)).hide();
      this._setActive(0);
      this._setPull(0);

      this.options.afterChange(0);
      return 0;
    },

    goToLast: function () {
      // Go to last blade
      $('.right', $(this.options.pagerSelector)).hide();
      var pull = $(this.options.innerStripSelector).width() - $(this.element[0]).width(),
          index = $(this.options.bladesSelector).length - 1;

      this._setActive(index);
      this._setPull(-pull);

      this.options.afterChange(index);
      return index;
    },

    _init: function () {
      $('html').addClass('fabrik-strip');
      this._bind();
      this._setSizes();
      this._setActive(this.options.startIndex);
    },

    _setSizes: function () {

      var self = this,
          windowHeight = $(window).height(),
          windowWidth = $(window).width();

      if ($(self.options.headerSelector).length) {
        windowHeight -= $(self.options.headerSelector).height();
      }

      $(self.element[0]).height(windowHeight);
      $(self.options.bladesSelector).removeAttr('style');
      $(self.options.innerStripSelector).width('999em');

      // after images are loaded get the widths of the blades so we can set parent container

      if (imagesLoaded !== undefined) {
        imagesLoaded(self.element[0], function () {
          var width = 0;

          $(self.options.bladesSelector).each(function () {

            var $blade = $(this),
                bladewidth = $(this).width(),
                $img = $('img', $blade);

            if ($img.length) {
              bladewidth = $img.width();
            }

            $blade.width(bladewidth);
            width += bladewidth;
          });

          $(self.options.innerStripSelector).width(width).addClass('blades-loaded');
        });
      }
      else {
        console.info("You need to add images Loaded plugin http://imagesloaded.desandro.com/");
      }

      var pagerWidth = $('.left').outerWidth(true),
          infoWidth = windowWidth - pagerWidth;

      if (windowWidth >= 1200) {
        infoWidth = $(self.element[0]).width() / 2;
      }

      $('.project-info-blade').width(infoWidth);

    },

    _setPull: function (int) {
      $(this.options.innerStripSelector).css({
        "-webkit-transform": "translate3d(" + int + "px, 0px, 0px)",
        "-moz-transform": "translate3d(" + int + "px, 0px, 0px)",
        "-ms-transform": "translate3d(" + int + "px, 0px, 0px)",
        "-o-transform": "translate3d(" + int + "px, 0px, 0px)",
        "transform": "translate3d(" + int + "px, 0px, 0px)"
      });
    },

    _setActive: function (index) {
      $(this.options.bladesSelector).removeClass('active');
      // Get the new active blade
      var $blade = $(this.options.bladesSelector).eq(index);
      $blade.addClass('active');

      $(this.element[0]).data('activeIndex', index);
    },

    _goToOnResize: function (index) {
      var self = this;

      setTimeout(function () {
        self.goTo(index);
      }, 200);
    },

    _bind: function () {
      // debounced resizing
      var self = this, t;

      $('button', $(self.options.pagerSelector)).on('click', function (e) {
        e.preventDefault();

        var activeIndex = $(self.element[0]).data('activeIndex'),
            index = activeIndex + 1;

        if ($(this).hasClass('left')) {
          index = activeIndex - 1;
        }

        self.options.beforeChange(activeIndex);

        self.goTo(index);
      });

      $(self.options.bladesSelector).on('click', function (e) {

        if (!$(this).hasClass('active')) {
          e.preventDefault();
          var activeIndex = $(self.element[0]).data('activeIndex');
          self.options.beforeChange(activeIndex);
          self.goTo($(this).index());
        }
      });

      $(window).on('resize.' + PLUGIN_NAME, function () {
        clearTimeout(t);
        t = setTimeout(function () {
          // On resize set the sizes
          self._setSizes();
          self._goToOnResize($(self.element[0]).data('activeIndex'));
        }, 200);
      });

      $(document.documentElement).keyup(function (event) {
        var activeIndex = 0,
            index = 0;

        // handle cursor keys
        if (event.keyCode == 37) {
          // go left
          activeIndex = $(self.element[0]).data('activeIndex');
          index = activeIndex - 1;

          self.options.beforeChange(activeIndex);
          self.goTo(index);
        } else if (event.keyCode == 39) {
          // go right
          activeIndex = $(self.element[0]).data('activeIndex');
          index = activeIndex + 1;

          self.options.beforeChange(activeIndex);
          self.goTo(index);
        }
      });

    }

  };

  $.fn[PLUGIN_NAME] = function (options) {

    var args = arguments,
      returns;

    this.each(function () {

      var instance = $.data(this, INSTANCE_KEY);

      if (instance) {
        // check if invoking public methods
        if (typeof (options) === 'string' && options[0] !== '_') {
          var method = instance[options];
          if (typeof (method) === 'function') {
            returns = method.apply(instance, Array.prototype.slice.call(args, 1));
          } else {
            // method missing
            $.error('Public method \'' + options + '\' does not exist on jQuery.' + PLUGIN_NAME);
          }
        }

      } else {
        $.data(this, INSTANCE_KEY, new FabrikStrip(this, options, $.fn[PLUGIN_NAME].defaults));
      }
    });

    // if the earlier cached method has a value return it, otherwise return this to preserve chainability
    return returns !== undefined ? returns : this;
  };

  $.fn[PLUGIN_NAME].defaults = {
    bladesSelector: '.blade',
    innerStripSelector: '.strip',
    headerSelector: null,
    pagerSelector: '.strip-pagers',
    startIndex: 0,
    afterChange: function () { },
    beforeChange: function () { },
  };

})(jQuery, window);<|endoftext|>


<commit_before>'use strict';

//GET REACT BOOTSTRAP COMPONENTS

var ButtonGroup = ReactBootstrap.ButtonGroup;
var Button  = ReactBootstrap.Button;
var Modal = ReactBootstrap.Modal;
var Input = ReactBootstrap.Input;

//SOCKET.IO SETUP
console.log(window.location.hostname)
var socket = io.connect("/");

//FUNCTIONS

//STOCK FILTER
function filterStocks(stocks, stockName) {

  return stocks.filter(function(stock) {
    return stock.name !== stockName;
  })

}

function getDate(date) {
  return new Date(date)
}

function addLabels(height, margin, width, svg, data) {
  //ADD Y LABEL
   var yLabel = svg.append("text")
     .attr("x", 0 - height/2)
     .attr("y", 0 - margin.left/1.5)
      .style("text-anchor", "middle")
      .text("Stock Price ($)")
      .attr('transform', 'rotate(-90)')
      .classed("label", true)
   //ADD X LABEL
    svg.append("text")
     .attr("x", width / 2)
     .attr("y", height + margin.bottom/1.3)
      .style("text-anchor", "middle")
      .text("Date")
      .classed("label", true)
}

function randomColor() {
  function random() {
    return Math.floor((Math.random() * 255));
  }

  var color = "rgb("+ random() + "," + random() + "," + random()+ ")"
  return color;
}

//CONTAINER TO HOLD COMPONENTS
var StockContainer = React.createClass({

    getInitialState() {

      return {
      stocks: [],
    };

    },

    updateStocks(stock) {
      var component = this;
      socket.on('serverStocks', function (data) {
          component.setState({stocks: data.stocks});
       });
    },

    removeStock(stock) {
    socket.emit('removeStock', {stock: stock});
    var stocks = this.state.stocks;
    filterStocks(stocks, stock)
    this.setState({stocks: filterStocks(stocks, stock)})
    },

    render: function() {

       return (

         <InputBox first={this.state.first} updateStocks={this.updateStocks} stocks={this.state.stocks} removeStock={this.removeStock}/>
          <SVG stocks={this.state.stocks}/>

        );

      }
});

//PANEL FOR EACH RECIPE
var InputBox = React.createClass({

      getInitialState() {
    return {
      showModal: false,
      modalText: "",
      stock: "MSFT"
    };
    },

    componentDidMount: function() {
      this.addStock();
    },

    close: function() {
      this.setState({showModal: false})
    },

    show: function() {
    this.setState({ showModal: true })
    },

    keyPress: function(e) {
     if (e.charCode === 13) {
     	this.addStock()
     }
    },

   addStock: function() {
    console.log("called")
     var stocks = this.props.stocks
     var stock = this.state.stock.toUpperCase()
     //CHECK IF STOCK ALREADY ADDED

     var stockNotAdded = true;
     stocks.map(function(stockObj) {
       if (stock === stockObj.name) {

         this.setState({modalText: "You already added that stock"})
         this.setState({showModal: true})
         stockNotAdded = false;
       }
     }.bind(this))

     //if stock not already added - make ajax request
     if (stockNotAdded) {

       var date = new Date();
       var month = date.getMonth() + 1;

        var url = "https://www.quandl.com/api/v3/datasets/WIKI/" + stock + ".json?api_key=scg9nFzbjxfysc6spmY3&start_date=2016-" + month + "-01&end_date=2016-" + month + "-30"

        $.getJSON(url, function(data) {

        })
        //IF SUCCESS
        .success(function(data) {
          var december = data.dataset.data;
          var closingObj = {};
          closingObj.name = stock;
          closingObj.data = [];
          closingObj.color = randomColor();
            december.map(function(data) {
              closingObj.data.push([data[0], data[4]])
            });
        this.props.updateStocks(closingObj)
         socket.emit('clientStocks', {stock: closingObj});
          }.bind(this))

          //IF ERR
        .error(function() {
          this.setState({modalText: "No Data Found for That Stock, Please Try Again"})
          this.setState({showModal:true})
        }.bind(this))
        }
        this.setState({stock: ""})
  },

  updateState: function(event) {
    this.setState({stock: event.target.value})
  },

  removeStock: function(stockName) {
    this.props.removeStock(stockName);
  },

  render: function() {

    return (

      <Input type="text" placeholder="Enter stock name" className="input" onChange={this.updateState} value={this.state.stock} onKeyPress={this.keyPress}/>
      <Button className="add-btn" onClick={this.addStock}> Add </Button>

      {this.props.stocks.map(function(stock) {
              var stockName = stock.name;
              var buttonStyle = {background: stock.color};
              return <Button key={stock.name} className="stock-button" style={buttonStyle} onClick={this.removeStock.bind(null, stockName)}> {stock.name}   x   </Button>;
            }.bind(this))}

      <ErrorModal show={this.state.showModal} onHide={this.close} text={this.state.modalText}/>

    )
  }

});

//MODAL TO EDIT RECIPE
var ErrorModal = React.createClass({

  getInitialState: function() {
    return {name: this.props.name,
           ingredients: this.props.ingredients,
           }
  },

  render: function() {
    return (

        <Modal show={this.props.show}>

      <Modal.Body>
            {this.props.text}
      </Modal.Body>
      <Modal.Footer>
        <Button bsStyle="primary" className="close-button" onClick={this.props.onHide}>Close</Button>
      </Modal.Footer>
        </Modal>

    )

      }
});

var SVG = React.createClass({

  getInitialState: function() {
      return  {
      margin: {top: 20, right: 70, bottom: 70, left: 70},
    }
  },

  componentDidMount: function() {
       //CREATE SVG MARGIN

   var margin = this.state.margin;

   var width = 800 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    this.setState({height: height, width: width})

    //DEFINE SVG
    var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    this.setState({svg: svg})

  },

  componentDidUpdate: function() {

    //GET VARIABLES FROM STATE
  var stocks = this.props.stocks;
  var height = this.state.height;
  var width = this.state.width;
  var svg = this.state.svg;
  var margin =this.state.margin;

    //REMOVE OLD LINES AND AXES
   d3.selectAll("path.line").remove()
   d3.selectAll(".axis").remove()
   d3.selectAll(".scatterPlotGroup").remove()

    //ADD BEGINNING AXES

     var stockData = []
  stocks.map(function(stock) {
     for (var i = 0; i < stock.data.length; i++) {
    stockData.push(stock.data[i][1])
  }

  });

  stockData.sort(function(a,b) { return a - b;})

  var max = stockData[stockData.length - 1]
  var min = stockData[0]
  var maxDate = getDate(stocks[0].data[0][0])
  var minDate = getDate(stocks[0].data[stocks[0].data.length-1][0])

   //DEFINE SCALE
var y = d3.scale.linear().domain([max, min]).range([0, height]);

var x = d3.time.scale().domain([minDate, maxDate]).range([0, width]);

   //DEFINE AXES

 var xAxis = d3.svg.axis().scale(x).orient("bottom")
 var yAxis = d3.svg.axis().scale(y).orient("left")

  //DECLARE AND BUILD LINES
 var lineFunction = d3.svg.line()
                          .x(function(d, i) { return x(getDate(d[0]));})
                          .y(function(d) { return y(d[1]);})
                          .interpolate("linear")

 stocks.map(function(stock) {
    var lineGraph = svg.append("path")
                            .attr("d", lineFunction(stock.data))
                            .attr("stroke", stock.color)
                            .attr("stroke-width", 2)
                            .attr("fill", "none")
                            .classed("line", true);

      var totalLength = lineGraph.node().getTotalLength();

      lineGraph.attr("stroke-dasharray", totalLength + " " + totalLength)
        .attr("stroke-dashoffset", 0-totalLength)
        .transition()
        .delay(1000)
        .duration(2000)
        .ease("linear")
        .attr("stroke-dashoffset", 0);
        });

     //CREATE TOOLTIP
    var tooltip = d3.select("body").append("div").attr("class", "tooltip").style("opacity", 0)

   //CREATE CIRCLES
    var scatterPlotGroups = svg.selectAll(".scatterPlotGroup")
        .data(stocks)
        .enter().append("g")
        .attr("class", "scatterPlotGroup");

    var circles = scatterPlotGroups.selectAll("circle")
        .data(function(d) { return d.data; })
        .enter().append("circle")
        .attr("cx", function(d) { return x(getDate(d[0])); })
        .attr("cy", function(d) { return y(d[1]) + 1000 })
        .attr("r", 3)
        .attr("fill", "black")

    circles.
        transition()
        .duration(1000)
        .attr("cy", function(d) { return y(d[1])});

//TOOL TIP ANIMATION
    circles.on("mouseover", function (d) {

      tooltip.transition()
            .duration(200)
            .style("opacity", 0.8)

      tooltip.html("Date: " + d[0] + "
Stock: " + d[1])
            .style("left", (d3.event.pageX + 10) + "px")
            .style("top", (d3.event.pageY - 28) + "px");
       })

   circles.on("mouseout", function(d) {
     tooltip.transition()
        .duration(200)
        .style("opacity", 0)
   })

    //BUILD AXES
    svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(" + (0) + "," + height + ")")
        .call(xAxis)
        .classed("axis", true)

    svg.append("g")
        .attr("class", "axis")
        .call(yAxis)
        .classed("axis", true)

        svg.append("path")
                  .attr("d", "M 0 0 L 0 " + height +  " L " + width + " " + height).classed("axes", true)

    addLabels(height, margin, width, svg, stocks);

  },

  render: function(){

    return (

    )
  }

})

//RENDER CONTAINER

ReactDOM.render(<StockContainer />, document.getElementById("stock-container"));
<commit_msg>fixed month issue with february<commit_after>'use strict';

//GET REACT BOOTSTRAP COMPONENTS

var ButtonGroup = ReactBootstrap.ButtonGroup;
var Button  = ReactBootstrap.Button;
var Modal = ReactBootstrap.Modal;
var Input = ReactBootstrap.Input;

//SOCKET.IO SETUP
console.log(window.location.hostname)
var socket = io.connect("/");

//FUNCTIONS

//STOCK FILTER
function filterStocks(stocks, stockName) {

  return stocks.filter(function(stock) {
    return stock.name !== stockName;
  })

}

function getDate(date) {
  return new Date(date)
}

function addLabels(height, margin, width, svg, data) {
  //ADD Y LABEL
   var yLabel = svg.append("text")
     .attr("x", 0 - height/2)
     .attr("y", 0 - margin.left/1.5)
      .style("text-anchor", "middle")
      .text("Stock Price ($)")
      .attr('transform', 'rotate(-90)')
      .classed("label", true)
   //ADD X LABEL
    svg.append("text")
     .attr("x", width / 2)
     .attr("y", height + margin.bottom/1.3)
      .style("text-anchor", "middle")
      .text("Date")
      .classed("label", true)
}

function randomColor() {
  function random() {
    return Math.floor((Math.random() * 255));
  }

  var color = "rgb("+ random() + "," + random() + "," + random()+ ")"
  return color;
}

//CONTAINER TO HOLD COMPONENTS
var StockContainer = React.createClass({

    getInitialState() {

      return {
      stocks: [],
    };

    },

    updateStocks(stock) {
      var component = this;
      socket.on('serverStocks', function (data) {
          component.setState({stocks: data.stocks});
       });
    },

    removeStock(stock) {
    socket.emit('removeStock', {stock: stock});
    var stocks = this.state.stocks;
    filterStocks(stocks, stock)
    this.setState({stocks: filterStocks(stocks, stock)})
    },

    render: function() {

       return (

         <InputBox first={this.state.first} updateStocks={this.updateStocks} stocks={this.state.stocks} removeStock={this.removeStock}/>
          <SVG stocks={this.state.stocks}/>

        );

      }
});

//PANEL FOR EACH RECIPE
var InputBox = React.createClass({

      getInitialState() {
    return {
      showModal: false,
      modalText: "",
      stock: "MSFT"
    };
    },

    componentDidMount: function() {
      this.addStock();
    },

    close: function() {
      this.setState({showModal: false})
    },

    show: function() {
    this.setState({ showModal: true })
    },

    keyPress: function(e) {
     if (e.charCode === 13) {
     	this.addStock()
     }
    },

   addStock: function() {
    console.log("called")
     var stocks = this.props.stocks
     var stock = this.state.stock.toUpperCase()
     //CHECK IF STOCK ALREADY ADDED

     var stockNotAdded = true;
     stocks.map(function(stockObj) {
       if (stock === stockObj.name) {

         this.setState({modalText: "You already added that stock"})
         this.setState({showModal: true})
         stockNotAdded = false;
       }
     }.bind(this))

     //if stock not already added - make ajax request
     if (stockNotAdded) {

       var date = new Date();
       var month = date.getMonth() + 1;

        var url = "https://www.quandl.com/api/v3/datasets/WIKI/" + stock + ".json?api_key=scg9nFzbjxfysc6spmY3&start_date=2016-" + month + "-01&end_date=2016-" + month + "-28"

        $.getJSON(url, function(data) {

        })
        //IF SUCCESS
        .success(function(data) {
          var december = data.dataset.data;
          var closingObj = {};
          closingObj.name = stock;
          closingObj.data = [];
          closingObj.color = randomColor();
            december.map(function(data) {
              closingObj.data.push([data[0], data[4]])
            });
        this.props.updateStocks(closingObj)
         socket.emit('clientStocks', {stock: closingObj});
          }.bind(this))

          //IF ERR
        .error(function() {
          this.setState({modalText: "No Data Found for That Stock, Please Try Again"})
          this.setState({showModal:true})
        }.bind(this))
        }
        this.setState({stock: ""})
  },

  updateState: function(event) {
    this.setState({stock: event.target.value})
  },

  removeStock: function(stockName) {
    this.props.removeStock(stockName);
  },

  render: function() {

    return (

      <Input type="text" placeholder="Enter stock name" className="input" onChange={this.updateState} value={this.state.stock} onKeyPress={this.keyPress}/>
      <Button className="add-btn" onClick={this.addStock}> Add </Button>

      {this.props.stocks.map(function(stock) {
              var stockName = stock.name;
              var buttonStyle = {background: stock.color};
              return <Button key={stock.name} className="stock-button" style={buttonStyle} onClick={this.removeStock.bind(null, stockName)}> {stock.name}   x   </Button>;
            }.bind(this))}

      <ErrorModal show={this.state.showModal} onHide={this.close} text={this.state.modalText}/>

    )
  }

});

//MODAL TO EDIT RECIPE
var ErrorModal = React.createClass({

  getInitialState: function() {
    return {name: this.props.name,
           ingredients: this.props.ingredients,
           }
  },

  render: function() {
    return (

        <Modal show={this.props.show}>

      <Modal.Body>
            {this.props.text}
      </Modal.Body>
      <Modal.Footer>
        <Button bsStyle="primary" className="close-button" onClick={this.props.onHide}>Close</Button>
      </Modal.Footer>
        </Modal>

    )

      }
});

var SVG = React.createClass({

  getInitialState: function() {
      return  {
      margin: {top: 20, right: 70, bottom: 70, left: 70},
    }
  },

  componentDidMount: function() {
       //CREATE SVG MARGIN

   var margin = this.state.margin;

   var width = 800 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    this.setState({height: height, width: width})

    //DEFINE SVG
    var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    this.setState({svg: svg})

  },

  componentDidUpdate: function() {

    //GET VARIABLES FROM STATE
  var stocks = this.props.stocks;
  var height = this.state.height;
  var width = this.state.width;
  var svg = this.state.svg;
  var margin =this.state.margin;

    //REMOVE OLD LINES AND AXES
   d3.selectAll("path.line").remove()
   d3.selectAll(".axis").remove()
   d3.selectAll(".scatterPlotGroup").remove()

    //ADD BEGINNING AXES

     var stockData = []
  stocks.map(function(stock) {
     for (var i = 0; i < stock.data.length; i++) {
    stockData.push(stock.data[i][1])
  }

  });

  stockData.sort(function(a,b) { return a - b;})

  var max = stockData[stockData.length - 1]
  var min = stockData[0]
  var maxDate = getDate(stocks[0].data[0][0])
  var minDate = getDate(stocks[0].data[stocks[0].data.length-1][0])

   //DEFINE SCALE
var y = d3.scale.linear().domain([max, min]).range([0, height]);

var x = d3.time.scale().domain([minDate, maxDate]).range([0, width]);

   //DEFINE AXES

 var xAxis = d3.svg.axis().scale(x).orient("bottom")
 var yAxis = d3.svg.axis().scale(y).orient("left")

  //DECLARE AND BUILD LINES
 var lineFunction = d3.svg.line()
                          .x(function(d, i) { return x(getDate(d[0]));})
                          .y(function(d) { return y(d[1]);})
                          .interpolate("linear")

 stocks.map(function(stock) {
    var lineGraph = svg.append("path")
                            .attr("d", lineFunction(stock.data))
                            .attr("stroke", stock.color)
                            .attr("stroke-width", 2)
                            .attr("fill", "none")
                            .classed("line", true);

      var totalLength = lineGraph.node().getTotalLength();

      lineGraph.attr("stroke-dasharray", totalLength + " " + totalLength)
        .attr("stroke-dashoffset", 0-totalLength)
        .transition()
        .delay(1000)
        .duration(2000)
        .ease("linear")
        .attr("stroke-dashoffset", 0);
        });

     //CREATE TOOLTIP
    var tooltip = d3.select("body").append("div").attr("class", "tooltip").style("opacity", 0)

   //CREATE CIRCLES
    var scatterPlotGroups = svg.selectAll(".scatterPlotGroup")
        .data(stocks)
        .enter().append("g")
        .attr("class", "scatterPlotGroup");

    var circles = scatterPlotGroups.selectAll("circle")
        .data(function(d) { return d.data; })
        .enter().append("circle")
        .attr("cx", function(d) { return x(getDate(d[0])); })
        .attr("cy", function(d) { return y(d[1]) + 1000 })
        .attr("r", 3)
        .attr("fill", "black")

    circles.
        transition()
        .duration(1000)
        .attr("cy", function(d) { return y(d[1])});

//TOOL TIP ANIMATION
    circles.on("mouseover", function (d) {

      tooltip.transition()
            .duration(200)
            .style("opacity", 0.8)

      tooltip.html("Date: " + d[0] + "
Stock: " + d[1])
            .style("left", (d3.event.pageX + 10) + "px")
            .style("top", (d3.event.pageY - 28) + "px");
       })

   circles.on("mouseout", function(d) {
     tooltip.transition()
        .duration(200)
        .style("opacity", 0)
   })

    //BUILD AXES
    svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(" + (0) + "," + height + ")")
        .call(xAxis)
        .classed("axis", true)

    svg.append("g")
        .attr("class", "axis")
        .call(yAxis)
        .classed("axis", true)

        svg.append("path")
                  .attr("d", "M 0 0 L 0 " + height +  " L " + width + " " + height).classed("axes", true)

    addLabels(height, margin, width, svg, stocks);

  },

  render: function(){

    return (

    )
  }

})

//RENDER CONTAINER

ReactDOM.render(<StockContainer />, document.getElementById("stock-container"));
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author paulirish / http://paulirish.com/
 *
 * parameters = {
 *  fov: <float>,
 *  aspect: <float>,
 *  near: <float>,
 *  far: <float>,
 *  target: <THREE.Object3D>,

 *  movementSpeed: <float>,
 *  lookSpeed: <float>,

 *  noFly: <bool>,
 *  lookVertical: <bool>,
 *  autoForward: <bool>,

 *  constrainVertical: <bool>,
 *  verticalMin: <float>,
 *  verticalMax: <float>,

 *  heightSpeed: <bool>,
 *  heightCoef: <float>,
 *  heightMin: <float>,
 *  heightMax: <float>,

 *  domElement: <HTMLElement>,
 * }
 */

THREE.FirstPersonCamera = function ( parameters ) {

	THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target );

	this.movementSpeed = 1.0;
	this.lookSpeed = 0.005;

	this.noFly = false;
	this.lookVertical = true;
	this.autoForward = false;

	this.activeLook = true;

	this.heightSpeed = false;
	this.heightCoef = 1.0;
	this.heightMin = 0.0;

	this.constrainVertical = false;
	this.verticalMin = 0;
	this.verticalMax = 3.14;

	this.domElement = document;

	this.lastUpdate = new Date().getTime();
	this.tdiff = 0;

	if ( parameters ) {

		if ( parameters.movementSpeed !== undefined ) this.movementSpeed = parameters.movementSpeed;
		if ( parameters.lookSpeed !== undefined ) this.lookSpeed  = parameters.lookSpeed;
		if ( parameters.noFly !== undefined ) this.noFly = parameters.noFly;
		if ( parameters.lookVertical !== undefined ) this.lookVertical = parameters.lookVertical;

		if ( parameters.autoForward !== undefined ) this.autoForward = parameters.autoForward;

		if ( parameters.activeLook !== undefined ) this.activeLook = parameters.activeLook;

		if ( parameters.heightSpeed !== undefined ) this.heightSpeed = parameters.heightSpeed;
		if ( parameters.heightCoef !== undefined ) this.heightCoef = parameters.heightCoef;
		if ( parameters.heightMin !== undefined ) this.heightMin = parameters.heightMin;
		if ( parameters.heightMax !== undefined ) this.heightMax = parameters.heightMax;

		if ( parameters.constrainVertical !== undefined ) this.constrainVertical = parameters.constrainVertical;
		if ( parameters.verticalMin !== undefined ) this.verticalMin = parameters.verticalMin;
		if ( parameters.verticalMax !== undefined ) this.verticalMax = parameters.verticalMax;

		if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement;

	}

	this.autoSpeedFactor = 0.0;

	this.mouseX = 0;
	this.mouseY = 0;

	this.lat = 0;
	this.lon = 0;
	this.phi = 0;
	this.theta = 0;

	this.moveForward = false;
	this.moveBackward = false;
	this.moveLeft = false;
	this.moveRight = false;
	this.freeze = false;

	this.mouseDragOn = false;

	if ( this.domElement === document ) {
		this.viewHalfX = window.innerWidth / 2;
		this.viewHalfY = window.innerHeight / 2;
	} else {
		this.viewHalfX = this.domElement.offsetWidth / 2;
		this.viewHalfY = this.domElement.offsetHeight / 2;
		this.domElement.setAttribute( 'tabindex', -1 );
	}

	this.onMouseDown = function ( event ) {

		if ( this.domElement !== document ) {
			this.domElement.focus();
		}

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

		if ( this.activeLook ) {

			switch ( event.button ) {

				case 0: this.moveForward = true; break;
				case 2: this.moveBackward = true; break;

			}

		}

		this.mouseDragOn = true;

	};

	this.onMouseUp = function ( event ) {

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

		if ( this.activeLook ) {

			switch ( event.button ) {

				case 0: this.moveForward = false; break;
				case 2: this.moveBackward = false; break;

			}

		}

		this.mouseDragOn = false;

	};

	this.onMouseMove = function ( event ) {

		if ( this.domElement === document ) {
			this.mouseX = event.pageX - this.viewHalfX;
			this.mouseY = event.pageY - this.viewHalfY;
		} else {
			this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
			this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;
		}

	};

	this.onKeyDown = function ( event ) {

		switch( event.keyCode ) {

			case 38: /*up*/
			case 87: /*W*/ this.moveForward = true; break;

			case 37: /*left*/
			case 65: /*A*/ this.moveLeft = true; break;

			case 40: /*down*/
			case 83: /*S*/ this.moveBackward = true; break;

			case 39: /*right*/
			case 68: /*D*/ this.moveRight = true; break;

			case 82: /*R*/ this.moveUp = true; break;
			case 70: /*F*/ this.moveDown = true; break;

			case 81: this.freeze = !this.freeze; break;

		}

	};

	this.onKeyUp = function ( event ) {

		switch( event.keyCode ) {

			case 38: /*up*/
			case 87: /*W*/ this.moveForward = false; break;

			case 37: /*left*/
			case 65: /*A*/ this.moveLeft = false; break;

			case 40: /*down*/
			case 83: /*S*/ this.moveBackward = false; break;

			case 39: /*right*/
			case 68: /*D*/ this.moveRight = false; break;

			case 82: /*R*/ this.moveUp = false; break;
			case 70: /*F*/ this.moveDown = false; break;

		}

	};

	this.update = function() {

		var now = new Date().getTime();
		this.tdiff = ( now - this.lastUpdate ) / 1000;
		this.lastUpdate = now;

		if ( !this.freeze ) {

			if ( this.heightSpeed ) {

				var y = clamp( this.position.y, this.heightMin, this.heightMax ),
					delta = y - this.heightMin;

				this.autoSpeedFactor = this.tdiff * ( delta * this.heightCoef );

			} else {

				this.autoSpeedFactor = 0.0;

			}

			var actualMoveSpeed = this.tdiff * this.movementSpeed;

			if ( this.moveForward || ( this.autoForward && !this.moveBackward ) ) this.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
			if ( this.moveBackward ) this.translateZ( actualMoveSpeed );

			if ( this.moveLeft ) this.translateX( - actualMoveSpeed );
			if ( this.moveRight ) this.translateX( actualMoveSpeed );

			if ( this.moveUp ) this.translateY( actualMoveSpeed );
			if ( this.moveDown ) this.translateY( - actualMoveSpeed );

			var actualLookSpeed = this.tdiff * this.lookSpeed;

			if ( !this.activeLook ) {

				actualLookSpeed = 0;

			}

			this.lon += this.mouseX * actualLookSpeed;
			if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed;

			this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
			this.phi = ( 90 - this.lat ) * Math.PI / 180;
			this.theta = this.lon * Math.PI / 180;

			var targetPosition = this.target.position,
				position = this.position;

			targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
			targetPosition.y = position.y + 100 * Math.cos( this.phi );
			targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

		}

		var verticalLookRatio = 1;

		if ( this.constrainVertical ) {

			verticalLookRatio = 3.14 / ( this.verticalMax - this.verticalMin );

		}

		this.lon += this.mouseX * actualLookSpeed;
		if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;

		this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
		this.phi = ( 90 - this.lat ) * Math.PI / 180;

		this.theta = this.lon * Math.PI / 180;

		if ( this.constrainVertical ) {

			this.phi = map_linear( this.phi, 0, 3.14, this.verticalMin, this.verticalMax );

		}

		var targetPosition = this.target.position,
			position = this.position;

		targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
		targetPosition.y = position.y + 100 * Math.cos( this.phi );
		targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

		this.supr.update.call( this );

	};

	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

	this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false );
	this.domElement.addEventListener( 'mousedown', bind( this, this.onMouseDown ), false );
	this.domElement.addEventListener( 'mouseup', bind( this, this.onMouseUp ), false );
	this.domElement.addEventListener( 'keydown', bind( this, this.onKeyDown ), false );
	this.domElement.addEventListener( 'keyup', bind( this, this.onKeyUp ), false );

	function bind( scope, fn ) {

		return function () {

			fn.apply( scope, arguments );

		};

	};

	function map_linear( x, sa, sb, ea, eb ) {

		return ( x  - sa ) * ( eb - ea ) / ( sb - sa ) + ea;

	};

	function clamp_bottom( x, a ) {

		return x < a ? a : x;

	};

	function clamp( x, a, b ) {

		return x < a ? a : ( x > b ? b : x );

	};

};

THREE.FirstPersonCamera.prototype = new THREE.Camera();
THREE.FirstPersonCamera.prototype.constructor = THREE.FirstPersonCamera;
THREE.FirstPersonCamera.prototype.supr = THREE.Camera.prototype;

THREE.FirstPersonCamera.prototype.translate = function ( distance, axis ) {

	this.matrix.rotateAxis( axis );

	if ( this.noFly ) {

		axis.y = 0;

	}

	this.position.addSelf( axis.multiplyScalar( distance ) );
	this.target.position.addSelf( axis.multiplyScalar( distance ) );

};
<commit_msg>Math.PI instead of 3.14<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 * @author paulirish / http://paulirish.com/
 *
 * parameters = {
 *  fov: <float>,
 *  aspect: <float>,
 *  near: <float>,
 *  far: <float>,
 *  target: <THREE.Object3D>,

 *  movementSpeed: <float>,
 *  lookSpeed: <float>,

 *  noFly: <bool>,
 *  lookVertical: <bool>,
 *  autoForward: <bool>,

 *  constrainVertical: <bool>,
 *  verticalMin: <float>,
 *  verticalMax: <float>,

 *  heightSpeed: <bool>,
 *  heightCoef: <float>,
 *  heightMin: <float>,
 *  heightMax: <float>,

 *  domElement: <HTMLElement>,
 * }
 */

THREE.FirstPersonCamera = function ( parameters ) {

	THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target );

	this.movementSpeed = 1.0;
	this.lookSpeed = 0.005;

	this.noFly = false;
	this.lookVertical = true;
	this.autoForward = false;

	this.activeLook = true;

	this.heightSpeed = false;
	this.heightCoef = 1.0;
	this.heightMin = 0.0;

	this.constrainVertical = false;
	this.verticalMin = 0;
	this.verticalMax = Math.PI;

	this.domElement = document;

	this.lastUpdate = new Date().getTime();
	this.tdiff = 0;

	if ( parameters ) {

		if ( parameters.movementSpeed !== undefined ) this.movementSpeed = parameters.movementSpeed;
		if ( parameters.lookSpeed !== undefined ) this.lookSpeed  = parameters.lookSpeed;
		if ( parameters.noFly !== undefined ) this.noFly = parameters.noFly;
		if ( parameters.lookVertical !== undefined ) this.lookVertical = parameters.lookVertical;

		if ( parameters.autoForward !== undefined ) this.autoForward = parameters.autoForward;

		if ( parameters.activeLook !== undefined ) this.activeLook = parameters.activeLook;

		if ( parameters.heightSpeed !== undefined ) this.heightSpeed = parameters.heightSpeed;
		if ( parameters.heightCoef !== undefined ) this.heightCoef = parameters.heightCoef;
		if ( parameters.heightMin !== undefined ) this.heightMin = parameters.heightMin;
		if ( parameters.heightMax !== undefined ) this.heightMax = parameters.heightMax;

		if ( parameters.constrainVertical !== undefined ) this.constrainVertical = parameters.constrainVertical;
		if ( parameters.verticalMin !== undefined ) this.verticalMin = parameters.verticalMin;
		if ( parameters.verticalMax !== undefined ) this.verticalMax = parameters.verticalMax;

		if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement;

	}

	this.autoSpeedFactor = 0.0;

	this.mouseX = 0;
	this.mouseY = 0;

	this.lat = 0;
	this.lon = 0;
	this.phi = 0;
	this.theta = 0;

	this.moveForward = false;
	this.moveBackward = false;
	this.moveLeft = false;
	this.moveRight = false;
	this.freeze = false;

	this.mouseDragOn = false;

	if ( this.domElement === document ) {
		this.viewHalfX = window.innerWidth / 2;
		this.viewHalfY = window.innerHeight / 2;
	} else {
		this.viewHalfX = this.domElement.offsetWidth / 2;
		this.viewHalfY = this.domElement.offsetHeight / 2;
		this.domElement.setAttribute( 'tabindex', -1 );
	}

	this.onMouseDown = function ( event ) {

		if ( this.domElement !== document ) {
			this.domElement.focus();
		}

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

		if ( this.activeLook ) {

			switch ( event.button ) {

				case 0: this.moveForward = true; break;
				case 2: this.moveBackward = true; break;

			}

		}

		this.mouseDragOn = true;

	};

	this.onMouseUp = function ( event ) {

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

		if ( this.activeLook ) {

			switch ( event.button ) {

				case 0: this.moveForward = false; break;
				case 2: this.moveBackward = false; break;

			}

		}

		this.mouseDragOn = false;

	};

	this.onMouseMove = function ( event ) {

		if ( this.domElement === document ) {
			this.mouseX = event.pageX - this.viewHalfX;
			this.mouseY = event.pageY - this.viewHalfY;
		} else {
			this.mouseX = event.pageX - this.domElement.offsetLeft - this.viewHalfX;
			this.mouseY = event.pageY - this.domElement.offsetTop - this.viewHalfY;
		}

	};

	this.onKeyDown = function ( event ) {

		switch( event.keyCode ) {

			case 38: /*up*/
			case 87: /*W*/ this.moveForward = true; break;

			case 37: /*left*/
			case 65: /*A*/ this.moveLeft = true; break;

			case 40: /*down*/
			case 83: /*S*/ this.moveBackward = true; break;

			case 39: /*right*/
			case 68: /*D*/ this.moveRight = true; break;

			case 82: /*R*/ this.moveUp = true; break;
			case 70: /*F*/ this.moveDown = true; break;

			case 81: this.freeze = !this.freeze; break;

		}

	};

	this.onKeyUp = function ( event ) {

		switch( event.keyCode ) {

			case 38: /*up*/
			case 87: /*W*/ this.moveForward = false; break;

			case 37: /*left*/
			case 65: /*A*/ this.moveLeft = false; break;

			case 40: /*down*/
			case 83: /*S*/ this.moveBackward = false; break;

			case 39: /*right*/
			case 68: /*D*/ this.moveRight = false; break;

			case 82: /*R*/ this.moveUp = false; break;
			case 70: /*F*/ this.moveDown = false; break;

		}

	};

	this.update = function() {

		var now = new Date().getTime();
		this.tdiff = ( now - this.lastUpdate ) / 1000;
		this.lastUpdate = now;

		if ( !this.freeze ) {

			if ( this.heightSpeed ) {

				var y = clamp( this.position.y, this.heightMin, this.heightMax ),
					delta = y - this.heightMin;

				this.autoSpeedFactor = this.tdiff * ( delta * this.heightCoef );

			} else {

				this.autoSpeedFactor = 0.0;

			}

			var actualMoveSpeed = this.tdiff * this.movementSpeed;

			if ( this.moveForward || ( this.autoForward && !this.moveBackward ) ) this.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
			if ( this.moveBackward ) this.translateZ( actualMoveSpeed );

			if ( this.moveLeft ) this.translateX( - actualMoveSpeed );
			if ( this.moveRight ) this.translateX( actualMoveSpeed );

			if ( this.moveUp ) this.translateY( actualMoveSpeed );
			if ( this.moveDown ) this.translateY( - actualMoveSpeed );

			var actualLookSpeed = this.tdiff * this.lookSpeed;

			if ( !this.activeLook ) {

				actualLookSpeed = 0;

			}

			this.lon += this.mouseX * actualLookSpeed;
			if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed;

			this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
			this.phi = ( 90 - this.lat ) * Math.PI / 180;
			this.theta = this.lon * Math.PI / 180;

			var targetPosition = this.target.position,
				position = this.position;

			targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
			targetPosition.y = position.y + 100 * Math.cos( this.phi );
			targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

		}

		var verticalLookRatio = 1;

		if ( this.constrainVertical ) {

			verticalLookRatio = Math.PI / ( this.verticalMax - this.verticalMin );

		}

		this.lon += this.mouseX * actualLookSpeed;
		if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;

		this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
		this.phi = ( 90 - this.lat ) * Math.PI / 180;

		this.theta = this.lon * Math.PI / 180;

		if ( this.constrainVertical ) {

			this.phi = map_linear( this.phi, 0, Math.PI, this.verticalMin, this.verticalMax );

		}

		var targetPosition = this.target.position,
			position = this.position;

		targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
		targetPosition.y = position.y + 100 * Math.cos( this.phi );
		targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );

		this.supr.update.call( this );

	};

	this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );

	this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false );
	this.domElement.addEventListener( 'mousedown', bind( this, this.onMouseDown ), false );
	this.domElement.addEventListener( 'mouseup', bind( this, this.onMouseUp ), false );
	this.domElement.addEventListener( 'keydown', bind( this, this.onKeyDown ), false );
	this.domElement.addEventListener( 'keyup', bind( this, this.onKeyUp ), false );

	function bind( scope, fn ) {

		return function () {

			fn.apply( scope, arguments );

		};

	};

	function map_linear( x, sa, sb, ea, eb ) {

		return ( x  - sa ) * ( eb - ea ) / ( sb - sa ) + ea;

	};

	function clamp_bottom( x, a ) {

		return x < a ? a : x;

	};

	function clamp( x, a, b ) {

		return x < a ? a : ( x > b ? b : x );

	};

};

THREE.FirstPersonCamera.prototype = new THREE.Camera();
THREE.FirstPersonCamera.prototype.constructor = THREE.FirstPersonCamera;
THREE.FirstPersonCamera.prototype.supr = THREE.Camera.prototype;

THREE.FirstPersonCamera.prototype.translate = function ( distance, axis ) {

	this.matrix.rotateAxis( axis );

	if ( this.noFly ) {

		axis.y = 0;

	}

	this.position.addSelf( axis.multiplyScalar( distance ) );
	this.target.position.addSelf( axis.multiplyScalar( distance ) );

};
<|endoftext|>


<commit_before>// @flow

import path from 'path';
import {
  Compiler,
  DllPlugin
} from 'webpack';
import createDebug from 'debug';
import createResourceMap from './createResourceMap';
import findInstance from './../utilities/findInstance';

const debug = createDebug('isomorphic-webpack');

export default (compiler: Compiler, callback: Function) => {
  const dllPlugin = findInstance(compiler.options.plugins, DllPlugin);
  const manifestPath = dllPlugin.options.path;

  debug('manifestPath', manifestPath);

  const outputFileSystem = compiler.outputFileSystem;

  return (error) => {
    if (error) {
      debug('compiler error:', error);

      return;
    }

    const manifest = JSON.parse(outputFileSystem.readFileSync(manifestPath));

    debug('manifest', manifest);

    const requestMap = createResourceMap(manifest);

    debug('requestMap', requestMap);

    const entryChunkName = Object.keys(compiler.options.entry)[0];

    debug('entryChunkName', entryChunkName);

    const absoluteEntryChunkName = path.resolve(compiler.options.output.path, entryChunkName + '.js');

    const bundleCode = outputFileSystem.readFileSync(absoluteEntryChunkName, 'utf-8');

    callback({
      bundleCode,
      requestMap
    });
  };
};
<commit_msg>fix: abort compilation if there are missing deps<commit_after>// @flow

import path from 'path';
import {
  Compiler,
  DllPlugin
} from 'webpack';
import createDebug from 'debug';
import createResourceMap from './createResourceMap';
import findInstance from './../utilities/findInstance';

const debug = createDebug('isomorphic-webpack');

export default (compiler: Compiler, callback: Function) => {
  const dllPlugin = findInstance(compiler.options.plugins, DllPlugin);
  const manifestPath = dllPlugin.options.path;

  debug('manifestPath', manifestPath);

  const outputFileSystem = compiler.outputFileSystem;

  return (error, stats) => {
    if (error) {
      debug('compiler error:', error);

      return;
    }

    if (stats.compilation.missingDependencies.length) {
      debug('aborting compilation; missing dependencies', stats.compilation.missingDependencies);

      return;
    }

    const manifest = JSON.parse(outputFileSystem.readFileSync(manifestPath));

    debug('manifest', manifest);

    const requestMap = createResourceMap(manifest);

    debug('requestMap', requestMap);

    const entryChunkName = Object.keys(compiler.options.entry)[0];

    debug('entryChunkName', entryChunkName);

    const absoluteEntryChunkName = path.resolve(compiler.options.output.path, entryChunkName + '.js');

    const bundleCode = outputFileSystem.readFileSync(absoluteEntryChunkName, 'utf-8');

    callback({
      bundleCode,
      requestMap
    });
  };
};
<|endoftext|>