<commit_before>'use strict';
var React = require('react');
var _ = require('underscore');
var url = require('url');
var moment = require('moment');
var globals = require('./globals');
var curator = require('./curator');
var modal = require('../libs/bootstrap/modal');
var form = require('../libs/bootstrap/form');
var parseAndLogError = require('./mixins').parseAndLogError;
var RestMixin = require('./rest').RestMixin;
var CurationMixin = require('./curator').CurationMixin;
var parsePubmed = require('../libs/parse-pubmed').parsePubmed;

var Modal = modal.Modal;
var ModalMixin = modal.ModalMixin;
var Form = form.Form;
var FormMixin = form.FormMixin;
var Input = form.Input;
var PmidDoiButtons = curator.PmidDoiButtons;
var RecordHeader = curator.RecordHeader;
var CurationPalette = curator.CurationPalette;
var PmidSummary = curator.PmidSummary;
var queryKeyValue = globals.queryKeyValue;
var external_url_map = globals.external_url_map;
var userMatch = globals.userMatch;

// Curator page content
var CurationCentral = React.createClass({
    mixins: [RestMixin, CurationMixin],

    getInitialState: function() {
        return {
            currPmid: queryKeyValue('pmid', this.props.href),
            currGdm: {}
        };
    },

    // Called when currently selected PMID changes
    currPmidChange: function(pmid) {
        if (pmid !== undefined) {
            var gdm = this.state.currGdm;

            if (Object.keys(gdm).length) {
                // Find the annotation in the GDM matching the given pmid
                var currAnnotation = _(gdm.annotations).find(annotation => {
                    return annotation.article.pmid === pmid;
                });

                if (currAnnotation) {
                    this.setState({currPmid: currAnnotation.article.pmid});
                }
            }
            if (this.state.currGdm && Object.keys(this.state.currGdm).length) {
                window.history.replaceState(window.state, '', '/curation-central/?gdm=' + this.state.currGdm.uuid + '&pmid=' + pmid);
            }
        }
    },

    // Retrieve the GDM object from the DB with the given uuid
    getGdm: function(uuid, pmid) {
        this.getRestData('/gdm/' + uuid).then(gdm => {
            // The GDM object successfully retrieved; set the Curator Central component
            this.setState({currGdm: gdm, currOmimId: gdm.omimId});
            this.currPmidChange(pmid);
        }).catch(parseAndLogError.bind(undefined, 'putRequest'));
    },

    // After the Curator Central page component mounts, grab the uuid from the query string and
    // retrieve the corresponding GDM from the DB.
    componentDidMount: function() {
        var gdmUuid = queryKeyValue('gdm', this.props.href);
        var pmid = queryKeyValue('pmid', this.props.href);
        if (gdmUuid) {
            this.getGdm(gdmUuid, pmid);
        }
    },

    // Add an article whose object is given to the current GDM
    updateGdmArticles: function(article) {
        var newAnnotation;
        var currGdm = this.state.currGdm;

        // Put together a new annotation object with the article reference
        var newAnnotationObj = {
            article: article.pmid,
            active: true
        };

        // Post new annotation to the DB. fetch returns a JS promise.
        this.postRestData('/evidence/', newAnnotationObj).then(data => {
            // Save the new annotation; fetch the currently displayed GDM as an object without its embedded
            // objects; basically the object as it exists in the DB. We'll update that and write it back to the DB.
            return (data['@graph'][0]);
        }).then(newAnnotation => {
            var gdmObj = curator.flatten(currGdm);

            // Add our new annotation reference to the array of annotations in the GDM.
            if (!gdmObj.annotations) {
                gdmObj.annotations = [];
            }
            gdmObj.annotations.push(newAnnotation['@id']);
            return this.putRestData('/gdm/' + currGdm.uuid, gdmObj);
        }).then(data => {
            // Retrieve the updated GDM and set it as the new state GDM to force a rerendering.
            this.getGdm(data['@graph'][0].uuid, article.pmid);
        }).catch(parseAndLogError.bind(undefined, 'putRequest'));
    },

    render: function() {
        var gdm = this.state.currGdm;
        var pmid = this.state.currPmid;

        // Find the GDM's annotation for the article with the curren PMID
        var annotation = gdm.annotations && gdm.annotations.length && _(gdm.annotations).find(function(annotation) {
            return pmid === annotation.article.pmid;
        });
        var currArticle = annotation ? annotation.article : null;

        return (

                <RecordHeader gdm={gdm} omimId={this.state.currOmimId} updateOmimId={this.updateOmimId} />

                            <PmidSelectionList annotations={gdm.annotations} currPmid={pmid} currPmidChange={this.currPmidChange}
                                    protocol={this.props.href_url.protocol} updateGdmArticles={this.updateGdmArticles} />

                            {currArticle ?

                                    <PmidSummary article={currArticle} displayJournal />
                                    <PmidDoiButtons pmid={currArticle.pmid} />
                                    <BetaNote annotation={annotation} session={this.props.session} />
                                    {currArticle.abstract ?

Abstract

{currArticle.abstract}

                                    : null}

                            : null}

                        {currArticle ?

                                <CurationPalette gdm={gdm} annotation={annotation} session={this.props.session} />

                        : null}

        );
    }
});

globals.curator_page.register(CurationCentral, 'curator_page', 'curation-central');

var BetaNote = React.createClass({
    render: function() {
        var annotation = this.props.annotation;
        var session = this.props.session;
        var curatorMatch = annotation && userMatch(annotation.submitted_by, session);

        return (

                {!curatorMatch ?

Currently, only the curator who adds a paper to a Gene-Disease record can associate evidence with that paper.

PMID:{annotation.article.pmid} added by {annotation.submitted_by.title}.

                : null}

        );
    }
});

// Display the list of PubMed articles passed in pmidItems.
var PmidSelectionList = React.createClass({
    mixins: [ModalMixin],

    propTypes: {
        annotations: React.PropTypes.array, // List of PubMed items
        protocol: React.PropTypes.string, // Protocol to use to access PubMed ('http:' or 'https:')
        currPmid: React.PropTypes.string, // PMID of currently selected article
        currPmidChange: React.PropTypes.func, // Function to call when currently selected article changes
        updateGdmArticles: React.PropTypes.func // Function to call when we have an article to add to the GDM
    },

    render: function() {
        var annotations = _(this.props.annotations).sortBy(function(annotation) {
            // Sort list of articles by first author
            return annotation.article.authors[0];
        });

        return (

                    <Modal title='Add new PubMed Article'>
                        <button className="btn btn-primary pmid-selection-add-btn" modal={<AddPmidModal protocol={this.props.protocol} closeModal={this.closeModal} updateGdmArticles={this.props.updateGdmArticles} />}>
                            Add New PMID(s)
                        </button>
                    </Modal>

                {annotations ?

                        {annotations.map(annotation => {
                            var classList = 'pmid-selection-list-item' + (annotation.article.pmid === this.props.currPmid ? ' curr-pmid' : '');

                            return (

                                        <PmidSummary article={annotation.article} />

PMID: {annotation.article.pmid}

                            );
                        })}

                : null}
                {annotations.length === 0 ?

                        Add papers to this Gene-Disease Record using the Add New PMID(s) button; click on any added paper to view its abstract and begin curating evidence from that paper.

                :null }

        );
    }
});

// The content of the Add PMID(s) modal dialog box
var AddPmidModal = React.createClass({
    mixins: [FormMixin, RestMixin],

    propTypes: {
        closeModal: React.PropTypes.func, // Function to call to close the modal
        protocol: React.PropTypes.string, // Protocol to use to access PubMed ('http:' or 'https:')
        updateGdmArticles: React.PropTypes.func // Function to call when we have an article to add to the GDM
    },

    contextTypes: {
        fetch: React.PropTypes.func // Function to perform a search
    },

    // Form content validation
    validateForm: function() {
        // Start with default validation
        var valid = this.validateDefault();

        // Valid if the field has only 10 or fewer digits
        if (valid) {
            valid = this.getFormValue('pmid').match(/^[0-9]{1,10}$/i);
            if (!valid) {
                this.setFormErrors('pmid', 'Only numbers allowed');
            }
        }
        return valid;
    },

    // Called when the modal form’s submit button is clicked. Handles validation and triggering
    // the process to add an article.
    submitForm: function(e) {
        e.preventDefault(); e.stopPropagation(); // Don't run through HTML submit handler
        this.saveFormValue('pmid', this.refs.pmid.getValue());
        if (this.validateForm()) {
            // Form is valid -- we have a good PMID. Fetch the article with that PMID
            var enteredPmid = this.getFormValue('pmid');
            this.getRestData('/articles/' + enteredPmid).then(article => {
                // Close the modal; update the GDM with this article.
                return Promise.resolve(article);
            }, e => {
                var url = this.props.protocol + external_url_map['PubMedSearch'];
                // PubMed article not in our DB; go out to PubMed itself to retrieve it as XML
                return this.getRestDataXml(external_url_map['PubMedSearch'] + enteredPmid).then(xml => {
                    var newArticle = parsePubmed(xml, enteredPmid);
                    return this.postRestData('/articles/', newArticle).then(data => {
                        return Promise.resolve(data['@graph'][0]);
                    });
                });
            }).then(article => {
                this.props.closeModal();
                this.props.updateGdmArticles(article);
            }).catch(function(e) {
                console.log('ERROR %o', e);
            });
        }
    },

    // Called when the modal form's cancel button is clicked. Just closes the modal like
    // nothing happened.
    cancelForm: function(e) {
        e.preventDefault(); e.stopPropagation(); // Don't run through HTML submit handler
        this.props.closeModal();
    },

    render: function() {
        return (
            <Form submitHandler={this.submitForm} formClassName="form-std">

                    <Input type="text" ref="pmid" label="Enter a PubMed ID"
                        error={this.getFormError('pmid')} clearError={this.clrFormErrors.bind(null, 'pmid')}
                        labelClassName="control-label" groupClassName="form-group" required />

                    <Input type="cancel" inputClassName="btn-default btn-inline-spacer" cancelHandler={this.cancelForm} />
                    <Input type="submit" inputClassName="btn-primary btn-inline-spacer" title="Add Article" />

            </Form>
        );
    }
});
<commit_msg>add check to see if pmid is already associated with gdm, regardless of ownership<commit_after>'use strict';
var React = require('react');
var _ = require('underscore');
var url = require('url');
var moment = require('moment');
var globals = require('./globals');
var curator = require('./curator');
var modal = require('../libs/bootstrap/modal');
var form = require('../libs/bootstrap/form');
var parseAndLogError = require('./mixins').parseAndLogError;
var RestMixin = require('./rest').RestMixin;
var CurationMixin = require('./curator').CurationMixin;
var parsePubmed = require('../libs/parse-pubmed').parsePubmed;

var Modal = modal.Modal;
var ModalMixin = modal.ModalMixin;
var Form = form.Form;
var FormMixin = form.FormMixin;
var Input = form.Input;
var PmidDoiButtons = curator.PmidDoiButtons;
var RecordHeader = curator.RecordHeader;
var CurationPalette = curator.CurationPalette;
var PmidSummary = curator.PmidSummary;
var queryKeyValue = globals.queryKeyValue;
var external_url_map = globals.external_url_map;
var userMatch = globals.userMatch;

// Curator page content
var CurationCentral = React.createClass({
    mixins: [RestMixin, CurationMixin],

    getInitialState: function() {
        return {
            currPmid: queryKeyValue('pmid', this.props.href),
            currGdm: {}
        };
    },

    // Called when currently selected PMID changes
    currPmidChange: function(pmid) {
        if (pmid !== undefined) {
            var gdm = this.state.currGdm;

            if (Object.keys(gdm).length) {
                // Find the annotation in the GDM matching the given pmid
                var currAnnotation = _(gdm.annotations).find(annotation => {
                    return annotation.article.pmid === pmid;
                });

                if (currAnnotation) {
                    this.setState({currPmid: currAnnotation.article.pmid});
                }
            }
            if (this.state.currGdm && Object.keys(this.state.currGdm).length) {
                window.history.replaceState(window.state, '', '/curation-central/?gdm=' + this.state.currGdm.uuid + '&pmid=' + pmid);
            }
        }
    },

    // Retrieve the GDM object from the DB with the given uuid
    getGdm: function(uuid, pmid) {
        this.getRestData('/gdm/' + uuid).then(gdm => {
            // The GDM object successfully retrieved; set the Curator Central component
            this.setState({currGdm: gdm, currOmimId: gdm.omimId});
            this.currPmidChange(pmid);
        }).catch(parseAndLogError.bind(undefined, 'putRequest'));
    },

    // After the Curator Central page component mounts, grab the uuid from the query string and
    // retrieve the corresponding GDM from the DB.
    componentDidMount: function() {
        var gdmUuid = queryKeyValue('gdm', this.props.href);
        var pmid = queryKeyValue('pmid', this.props.href);
        if (gdmUuid) {
            this.getGdm(gdmUuid, pmid);
        }
    },

    // Add an article whose object is given to the current GDM
    updateGdmArticles: function(article) {
        var newAnnotation;
        var currGdm = this.state.currGdm;
        var addPost = true;

        // Put together a new annotation object with the article reference
        var newAnnotationObj = {
            article: article.pmid,
            active: true
        };

        // check to see if this PMID has already been added to the GDM
        for (var i = 0; i < currGdm.annotations.length; i++) {
            if (currGdm.annotations[i].article.pmid == newAnnotationObj.article) addPost = false;
        }

        if (addPost) {
            // Post new annotation to the DB. fetch returns a JS promise.
            this.postRestData('/evidence/', newAnnotationObj).then(data => {
                // Save the new annotation; fetch the currently displayed GDM as an object without its embedded
                // objects; basically the object as it exists in the DB. We'll update that and write it back to the DB.
                return (data['@graph'][0]);
            }).then(newAnnotation => {
                var gdmObj = curator.flatten(currGdm);

                // Add our new annotation reference to the array of annotations in the GDM.
                if (!gdmObj.annotations) {
                    gdmObj.annotations = [];
                }
                gdmObj.annotations.push(newAnnotation['@id']);
                return this.putRestData('/gdm/' + currGdm.uuid, gdmObj);
            }).then(data => {
                // Retrieve the updated GDM and set it as the new state GDM to force a rerendering.
                this.getGdm(data['@graph'][0].uuid, article.pmid);
            }).catch(parseAndLogError.bind(undefined, 'putRequest'));
        }
        else {
            // if the PMID is already in the GDM, just select it
            this.getGdm(currGdm.uuid, article.pmid);
        }
    },

    render: function() {
        var gdm = this.state.currGdm;
        var pmid = this.state.currPmid;

        // Find the GDM's annotation for the article with the curren PMID
        var annotation = gdm.annotations && gdm.annotations.length && _(gdm.annotations).find(function(annotation) {
            return pmid === annotation.article.pmid;
        });
        var currArticle = annotation ? annotation.article : null;

        return (

                <RecordHeader gdm={gdm} omimId={this.state.currOmimId} updateOmimId={this.updateOmimId} />

                            <PmidSelectionList annotations={gdm.annotations} currPmid={pmid} currPmidChange={this.currPmidChange}
                                    protocol={this.props.href_url.protocol} updateGdmArticles={this.updateGdmArticles} />

                            {currArticle ?

                                    <PmidSummary article={currArticle} displayJournal />
                                    <PmidDoiButtons pmid={currArticle.pmid} />
                                    <BetaNote annotation={annotation} session={this.props.session} />
                                    {currArticle.abstract ?

Abstract

{currArticle.abstract}

                                    : null}

                            : null}

                        {currArticle ?

                                <CurationPalette gdm={gdm} annotation={annotation} session={this.props.session} />

                        : null}

        );
    }
});

globals.curator_page.register(CurationCentral, 'curator_page', 'curation-central');

var BetaNote = React.createClass({
    render: function() {
        var annotation = this.props.annotation;
        var session = this.props.session;
        var curatorMatch = annotation && userMatch(annotation.submitted_by, session);

        return (

                {!curatorMatch ?

Currently, only the curator who adds a paper to a Gene-Disease record can associate evidence with that paper.

PMID:{annotation.article.pmid} added by {annotation.submitted_by.title}.

                : null}

        );
    }
});

// Display the list of PubMed articles passed in pmidItems.
var PmidSelectionList = React.createClass({
    mixins: [ModalMixin],

    propTypes: {
        annotations: React.PropTypes.array, // List of PubMed items
        protocol: React.PropTypes.string, // Protocol to use to access PubMed ('http:' or 'https:')
        currPmid: React.PropTypes.string, // PMID of currently selected article
        currPmidChange: React.PropTypes.func, // Function to call when currently selected article changes
        updateGdmArticles: React.PropTypes.func // Function to call when we have an article to add to the GDM
    },

    render: function() {
        var annotations = _(this.props.annotations).sortBy(function(annotation) {
            // Sort list of articles by first author
            return annotation.article.authors[0];
        });

        return (

                    <Modal title='Add new PubMed Article'>
                        <button className="btn btn-primary pmid-selection-add-btn" modal={<AddPmidModal protocol={this.props.protocol} closeModal={this.closeModal} updateGdmArticles={this.props.updateGdmArticles} />}>
                            Add New PMID(s)
                        </button>
                    </Modal>

                {annotations ?

                        {annotations.map(annotation => {
                            var classList = 'pmid-selection-list-item' + (annotation.article.pmid === this.props.currPmid ? ' curr-pmid' : '');

                            return (

                                        <PmidSummary article={annotation.article} />

PMID: {annotation.article.pmid}

                            );
                        })}

                : null}
                {annotations.length === 0 ?

                        Add papers to this Gene-Disease Record using the Add New PMID(s) button; click on any added paper to view its abstract and begin curating evidence from that paper.

                :null }

        );
    }
});

// The content of the Add PMID(s) modal dialog box
var AddPmidModal = React.createClass({
    mixins: [FormMixin, RestMixin],

    propTypes: {
        closeModal: React.PropTypes.func, // Function to call to close the modal
        protocol: React.PropTypes.string, // Protocol to use to access PubMed ('http:' or 'https:')
        updateGdmArticles: React.PropTypes.func // Function to call when we have an article to add to the GDM
    },

    contextTypes: {
        fetch: React.PropTypes.func // Function to perform a search
    },

    // Form content validation
    validateForm: function() {
        // Start with default validation
        var valid = this.validateDefault();

        // Valid if the field has only 10 or fewer digits
        if (valid) {
            valid = this.getFormValue('pmid').match(/^[0-9]{1,10}$/i);
            if (!valid) {
                this.setFormErrors('pmid', 'Only numbers allowed');
            }
        }
        return valid;
    },

    // Called when the modal form’s submit button is clicked. Handles validation and triggering
    // the process to add an article.
    submitForm: function(e) {
        e.preventDefault(); e.stopPropagation(); // Don't run through HTML submit handler
        this.saveFormValue('pmid', this.refs.pmid.getValue());
        if (this.validateForm()) {
            // Form is valid -- we have a good PMID. Fetch the article with that PMID
            var enteredPmid = this.getFormValue('pmid');
            this.getRestData('/articles/' + enteredPmid).then(article => {
                // Close the modal; update the GDM with this article.
                return Promise.resolve(article);
            }, e => {
                var url = this.props.protocol + external_url_map['PubMedSearch'];
                // PubMed article not in our DB; go out to PubMed itself to retrieve it as XML
                return this.getRestDataXml(external_url_map['PubMedSearch'] + enteredPmid).then(xml => {
                    var newArticle = parsePubmed(xml, enteredPmid);
                    return this.postRestData('/articles/', newArticle).then(data => {
                        return Promise.resolve(data['@graph'][0]);
                    });
                });
            }).then(article => {
                this.props.closeModal();
                this.props.updateGdmArticles(article);
            }).catch(function(e) {
                console.log('ERROR %o', e);
            });
        }
    },

    // Called when the modal form's cancel button is clicked. Just closes the modal like
    // nothing happened.
    cancelForm: function(e) {
        e.preventDefault(); e.stopPropagation(); // Don't run through HTML submit handler
        this.props.closeModal();
    },

    render: function() {
        return (
            <Form submitHandler={this.submitForm} formClassName="form-std">

                    <Input type="text" ref="pmid" label="Enter a PubMed ID"
                        error={this.getFormError('pmid')} clearError={this.clrFormErrors.bind(null, 'pmid')}
                        labelClassName="control-label" groupClassName="form-group" required />

                    <Input type="cancel" inputClassName="btn-default btn-inline-spacer" cancelHandler={this.cancelForm} />
                    <Input type="submit" inputClassName="btn-primary btn-inline-spacer" title="Add Article" />

            </Form>
        );
    }
});
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @constructor
 * @extends {WebInspector.DataGrid}
 * @param {!Array.<!WebInspector.DataGrid.ColumnDescriptor>} columnsArray
 * @param {function(!WebInspector.DataGridNode, string, string, string)=} editCallback
 * @param {function(!WebInspector.DataGridNode)=} deleteCallback
 * @param {function()=} refreshCallback
 * @param {function(!WebInspector.ContextMenu, !WebInspector.DataGridNode)=} contextMenuCallback
 */
WebInspector.ViewportDataGrid = function(columnsArray, editCallback, deleteCallback, refreshCallback, contextMenuCallback)
{
    WebInspector.DataGrid.call(this, columnsArray, editCallback, deleteCallback, refreshCallback, contextMenuCallback);
    this._scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true);
    this._scrollContainer.addEventListener("mousewheel", this._onWheel.bind(this), true);
    /** @type {!Array.<!WebInspector.ViewportDataGridNode>} */
    this._visibleNodes = [];
    /** @type {boolean} */
    this._updateScheduled = false;
    /** @type {boolean} */
    this._inline = false;

    // Wheel target shouldn't be removed from DOM to preserve native kinetic scrolling.
    /** @type {?Node} */
    this._wheelTarget = null;

    // Element that was hidden earlier, but hasn't been removed yet.
    /** @type {?Node} */
    this._hiddenWheelTarget = null;

    this.setRootNode(new WebInspector.ViewportDataGridNode());
}

WebInspector.ViewportDataGrid.prototype = {
    /**
     * @override
     */
    onResize: function()
    {
        this.scheduleUpdate();
    },

    /**
     * @param {?Event} event
     */
    _onWheel: function(event)
    {
        this._wheelTarget = event.target ? event.target.enclosingNodeOrSelfWithNodeName("tr") : null;
    },

    /**
     * @param {?Event} event
     */
    _onScroll: function(event)
    {
        this.scheduleUpdate();
    },

    /**
     * @protected
     */
    scheduleUpdate: function() {
        if (this._updateScheduled)
            return;
        this._updateScheduled = true;
        window.requestAnimationFrame(this._update.bind(this));
    },

    /**
     * @override
     */
    renderInline: function()
    {
        this._inline = true;
        WebInspector.DataGrid.prototype.renderInline.call(this);
        this._update();
    },

    /**
     * @param {number} scrollHeight
     * @param {number} scrollTop
     * @return {{topPadding: number, bottomPadding: number, visibleNodes: !Array.<!WebInspector.ViewportDataGridNode>}}
     */
    _calculateVisibleNodes: function(scrollHeight, scrollTop)
    {
        var nodes = this._rootNode.children;
        if (this._inline)
            return {topPadding: 0, bottomPadding: 0, visibleNodes: nodes};

        var size = nodes.length;
        var i = 0;
        var y = 0;

        for (; i < size && y + nodes[i].nodeSelfHeight() < scrollTop; ++i)
            y += nodes[i].nodeSelfHeight();
        var start = i;
        var topPadding = y;

        for (; i < size && y < scrollTop + scrollHeight; ++i)
            y += nodes[i].nodeSelfHeight();
        var end = i;

        var bottomPadding = 0;
        for (; i < size; ++i)
            bottomPadding += nodes[i].nodeSelfHeight();

        return {topPadding: topPadding, bottomPadding: bottomPadding, visibleNodes: nodes.slice(start, end)};
    },

    _update: function()
    {
        this._updateScheduled = false;

        var viewportState = this._calculateVisibleNodes(this._scrollContainer.offsetHeight, this._scrollContainer.scrollTop);
        var visibleNodes = viewportState.visibleNodes;
        var visibleNodesSet = Set.fromArray(visibleNodes);

        if (this._hiddenWheelTarget && this._hiddenWheelTarget !== this._wheelTarget) {
            this._hiddenWheelTarget.remove();
            this._hiddenWheelTarget = null;
        }

        for (var i = 0; i < this._visibleNodes.length; ++i) {
            var oldNode = this._visibleNodes[i];
            if (!visibleNodesSet.contains(oldNode)) {
                var element = oldNode.element();
                if (element === this._wheelTarget)
                    this._hiddenWheelTarget = oldNode.abandonElement();
                else
                    element.remove();
                oldNode.wasDetached();
            }
        }

        var previousElement = this._topFillerRow;
        if (previousElement.nextSibling === this._hiddenWheelTarget)
            previousElement = this._hiddenWheelTarget;
        var tBody = this.dataTableBody;
        for (var i = 0; i < visibleNodes.length; ++i) {
            var element = visibleNodes[i].element();
            tBody.insertBefore(element, previousElement.nextSibling);
            previousElement = element;
        }

        this.setVerticalPadding(viewportState.topPadding, viewportState.bottomPadding);
        this._visibleNodes = visibleNodes;
    },

    __proto__: WebInspector.DataGrid.prototype
}

/**
 * @constructor
 * @extends {WebInspector.DataGridNode}
 * @param {?Object.<string, *>=} data
 */
WebInspector.ViewportDataGridNode = function(data)
{
    WebInspector.DataGridNode.call(this, data, false);
    /** @type {boolean} */
    this._stale = false;
}

WebInspector.ViewportDataGridNode.prototype = {
    /**
     * @override
     * @return {!Element}
     */
    element: function()
    {
        if (!this._element) {
            this.createElement();
            this.createCells();
            this._stale = false;
        }

        if (this._stale) {
            this.createCells();
            this._stale = false;
        }

        return /** @type {!Element} */ (this._element);
    },

    /**
     * @override
     * @param {!WebInspector.DataGridNode} child
     * @param {number} index
     */
    insertChild: function(child, index)
    {
        child.dataGrid = this.dataGrid;
        this.children.splice(index, 0, child);
        child.recalculateSiblings(index);
        this.dataGrid.scheduleUpdate();
    },

    /**
     * @override
     * @param {!WebInspector.DataGridNode} child
     */
    removeChild: function(child)
    {
        child.deselect();
        this.children.remove(child, true);

        if (child.previousSibling)
            child.previousSibling.nextSibling = child.nextSibling;
        if (child.nextSibling)
            child.nextSibling.previousSibling = child.previousSibling;

        this.dataGrid.scheduleUpdate();
    },

    /**
     * @override
     */
    removeChildren: function()
    {
        for (var i = 0; i < this.children.length; ++i)
            this.children[i].deselect();
        this.children = [];

        this.dataGrid.scheduleUpdate();
    },

    /**
     * @override
     */
    expand: function()
    {
    },

    /**
     * @override
     */
    refresh: function()
    {
        if (this._element && this._element.parentElement) {
            this._stale = true;
            this.dataGrid.scheduleUpdate();
        } else {
            this._element = null;
        }
    },

    /**
     * @return {?Element}
     */
     abandonElement: function()
     {
        var result = this._element;
        if (result)
            result.style.display = "none";
        this._element = null;
        return result;
     },

    __proto__: WebInspector.DataGridNode.prototype
}
<commit_msg>DevTools: keyboard navigation broken in the viewported Network panel<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @constructor
 * @extends {WebInspector.DataGrid}
 * @param {!Array.<!WebInspector.DataGrid.ColumnDescriptor>} columnsArray
 * @param {function(!WebInspector.DataGridNode, string, string, string)=} editCallback
 * @param {function(!WebInspector.DataGridNode)=} deleteCallback
 * @param {function()=} refreshCallback
 * @param {function(!WebInspector.ContextMenu, !WebInspector.DataGridNode)=} contextMenuCallback
 */
WebInspector.ViewportDataGrid = function(columnsArray, editCallback, deleteCallback, refreshCallback, contextMenuCallback)
{
    WebInspector.DataGrid.call(this, columnsArray, editCallback, deleteCallback, refreshCallback, contextMenuCallback);
    this._scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true);
    this._scrollContainer.addEventListener("mousewheel", this._onWheel.bind(this), true);
    /** @type {!Array.<!WebInspector.ViewportDataGridNode>} */
    this._visibleNodes = [];
    /** @type {boolean} */
    this._updateScheduled = false;
    /** @type {boolean} */
    this._inline = false;

    // Wheel target shouldn't be removed from DOM to preserve native kinetic scrolling.
    /** @type {?Node} */
    this._wheelTarget = null;

    // Element that was hidden earlier, but hasn't been removed yet.
    /** @type {?Node} */
    this._hiddenWheelTarget = null;

    this.setRootNode(new WebInspector.ViewportDataGridNode());
}

WebInspector.ViewportDataGrid.prototype = {
    /**
     * @override
     */
    onResize: function()
    {
        this.scheduleUpdate();
    },

    /**
     * @param {?Event} event
     */
    _onWheel: function(event)
    {
        this._wheelTarget = event.target ? event.target.enclosingNodeOrSelfWithNodeName("tr") : null;
    },

    /**
     * @param {?Event} event
     */
    _onScroll: function(event)
    {
        this.scheduleUpdate();
    },

    /**
     * @protected
     */
    scheduleUpdate: function()
    {
        if (this._updateScheduled)
            return;
        this._updateScheduled = true;
        window.requestAnimationFrame(this._update.bind(this));
    },

    /**
     * @override
     */
    renderInline: function()
    {
        this._inline = true;
        WebInspector.DataGrid.prototype.renderInline.call(this);
        this._update();
    },

    /**
     * @param {number} scrollHeight
     * @param {number} scrollTop
     * @return {{topPadding: number, bottomPadding: number, visibleNodes: !Array.<!WebInspector.ViewportDataGridNode>}}
     */
    _calculateVisibleNodes: function(scrollHeight, scrollTop)
    {
        var nodes = this._rootNode.children;
        if (this._inline)
            return {topPadding: 0, bottomPadding: 0, visibleNodes: nodes};

        var size = nodes.length;
        var i = 0;
        var y = 0;

        for (; i < size && y + nodes[i].nodeSelfHeight() < scrollTop; ++i)
            y += nodes[i].nodeSelfHeight();
        var start = i;
        var topPadding = y;

        for (; i < size && y < scrollTop + scrollHeight; ++i)
            y += nodes[i].nodeSelfHeight();
        var end = i;

        var bottomPadding = 0;
        for (; i < size; ++i)
            bottomPadding += nodes[i].nodeSelfHeight();

        return {topPadding: topPadding, bottomPadding: bottomPadding, visibleNodes: nodes.slice(start, end)};
    },

    _update: function()
    {
        this._updateScheduled = false;

        var viewportState = this._calculateVisibleNodes(this._scrollContainer.offsetHeight, this._scrollContainer.scrollTop);
        var visibleNodes = viewportState.visibleNodes;
        var visibleNodesSet = Set.fromArray(visibleNodes);

        if (this._hiddenWheelTarget && this._hiddenWheelTarget !== this._wheelTarget) {
            this._hiddenWheelTarget.remove();
            this._hiddenWheelTarget = null;
        }

        for (var i = 0; i < this._visibleNodes.length; ++i) {
            var oldNode = this._visibleNodes[i];
            if (!visibleNodesSet.contains(oldNode)) {
                var element = oldNode.element();
                if (element === this._wheelTarget)
                    this._hiddenWheelTarget = oldNode.abandonElement();
                else
                    element.remove();
                oldNode.wasDetached();
            }
        }

        var previousElement = this._topFillerRow;
        if (previousElement.nextSibling === this._hiddenWheelTarget)
            previousElement = this._hiddenWheelTarget;
        var tBody = this.dataTableBody;
        for (var i = 0; i < visibleNodes.length; ++i) {
            var element = visibleNodes[i].element();
            tBody.insertBefore(element, previousElement.nextSibling);
            previousElement = element;
        }

        this.setVerticalPadding(viewportState.topPadding, viewportState.bottomPadding);
        this._visibleNodes = visibleNodes;
    },

    /**
     * @param {!WebInspector.ViewportDataGridNode} node
     */
    _revealViewportNode: function(node)
    {
        var nodes = this._rootNode.children;
        var index = nodes.indexOf(node);
        if (index === -1)
            return;
        var fromY = 0;
        for (var i = 0; i < index; ++i)
            fromY += nodes[i].nodeSelfHeight();
        var toY = fromY + node.nodeSelfHeight();

        var scrollTop = this._scrollContainer.scrollTop;
        if (scrollTop > fromY)
            scrollTop = fromY;
        else if (scrollTop + this._scrollContainer.offsetHeight < toY)
            scrollTop = toY - this._scrollContainer.offsetHeight;
        this._scrollContainer.scrollTop = scrollTop;
    },

    __proto__: WebInspector.DataGrid.prototype
}

/**
 * @constructor
 * @extends {WebInspector.DataGridNode}
 * @param {?Object.<string, *>=} data
 */
WebInspector.ViewportDataGridNode = function(data)
{
    WebInspector.DataGridNode.call(this, data, false);
    /** @type {boolean} */
    this._stale = false;
}

WebInspector.ViewportDataGridNode.prototype = {
    /**
     * @override
     * @return {!Element}
     */
    element: function()
    {
        if (!this._element) {
            this.createElement();
            this.createCells();
            this._stale = false;
        }

        if (this._stale) {
            this.createCells();
            this._stale = false;
        }

        return /** @type {!Element} */ (this._element);
    },

    /**
     * @override
     * @param {!WebInspector.DataGridNode} child
     * @param {number} index
     */
    insertChild: function(child, index)
    {
        child.parent = this;
        child.dataGrid = this.dataGrid;
        this.children.splice(index, 0, child);
        child.recalculateSiblings(index);
        this.dataGrid.scheduleUpdate();
    },

    /**
     * @override
     * @param {!WebInspector.DataGridNode} child
     */
    removeChild: function(child)
    {
        child.deselect();
        this.children.remove(child, true);

        if (child.previousSibling)
            child.previousSibling.nextSibling = child.nextSibling;
        if (child.nextSibling)
            child.nextSibling.previousSibling = child.previousSibling;

        this.dataGrid.scheduleUpdate();
    },

    /**
     * @override
     */
    removeChildren: function()
    {
        for (var i = 0; i < this.children.length; ++i)
            this.children[i].deselect();
        this.children = [];

        this.dataGrid.scheduleUpdate();
    },

    /**
     * @override
     */
    expand: function()
    {
    },

    /**
     * @override
     */
    refresh: function()
    {
        if (this._element && this._element.parentElement) {
            this._stale = true;
            this.dataGrid.scheduleUpdate();
        } else {
            this._element = null;
        }
    },

    /**
     * @return {?Element}
     */
     abandonElement: function()
     {
        var result = this._element;
        if (result)
            result.style.display = "none";
        this._element = null;
        return result;
     },

    reveal: function()
    {
        this.dataGrid._revealViewportNode(this);
    },

    __proto__: WebInspector.DataGridNode.prototype
}
<|endoftext|>


<commit_before>
define([
  "dojo/_base/declare",
  "dojo/_base/lang",
  "dojo/_base/json",
  "dojo/_base/fx",

  "dijit/form/Form",
  "dijit/_WidgetBase",
  "dijit/_TemplatedMixin",
  "dijit/_WidgetsInTemplateMixin",
  "dijit/layout/TabContainer",
  "dijit/layout/StackContainer",
  "dijit/layout/ContentPane",
  "dijit/layout/BorderContainer",
  "dijit/form/Button",
  "dijit/form/ValidationTextBox",
  "dijit/form/CheckBox",

  "hotplate/hotDojoSubmit/defaultSubmit",
  "hotplate/hotDojoStores/stores",
  "hotplate/hotDojoLogger/logger",
  "hotplate/hotDojoHooks/_TemplatedHooksMixin",
  "dojo/text!hotplate/hotDojoAuth/templates/LoginForm.html",

  "hotplate/hotDojoAuth/ValidationUsername",
  "hotplate/hotDojoAuth/ValidationPassword",
  "hotplate/hotDojoAuth/ValidationEmail",

  "hotplate/hotDojoWidgets/AlertBar",
  "hotplate/hotDojoWidgets/StackFading",
  "hotplate/hotDojoWidgets/TabFading",
  "hotplate/hotDojoWidgets/BusyButton",

   ], function(
     declare
     , lang
     , json
     , baseFx

     , Form
     , _WidgetBase
     , _TemplatedMixin
     , _WidgetsInTemplateMixin
     , TabContainer
     , StackContainer
     , ContentPane
     , BorderContainer
     , Button
     , ValidationTextBox
     , CheckBox

     , ds
     , stores
     , logger
     , _TemplatedHooksMixin
     , templateString

     , ValidationUsername
     , ValidationPassword
     , ValidationEmail
     , AlertBar

     , StackFading
     , TabFading
     , BusyButton
 ){
    // Create the "login" pane, based on a normal ContentPane
    return declare('hotplate.hotDojoAuth.LoginForm', [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _TemplatedHooksMixin ], {

      widgetsInTemplate: true,

      templateString:  templateString,

      // Hooks to switch tabs when clicking
      _onLoginClick: function(e){
        this.tabContainer.selectChild(this.loginPane);
      },

      _onRecoverClick: function(e){
        this.tabContainer.selectChild(this.recoverPane);
      },

      postCreate: function(){
        var that = this;

        //  If the global variable hotDojoAuth.login is set, then set the login name to
        //  the right value, and focus on the password widget
        if( vars.hotDojoAuth.login ){
          this.login.set( 'value', vars.hotDojoAuth.login );
          this.password.focus();
        } else {
          this.login.focus();
        }

        // Don't ACTUALLY submit the form
        this.recoverForm.onSubmit = ds.defaultSubmit(this.recoverForm, this.recoverButton, function(){

          // Get the form values
          var data = that.recoverForm.getValues();

          // Submit the info
          stores('recoverAnon').put(data).then(
            ds.UIMsg('ok', that.recoverForm, that.recoverButton, that.recoverAlertBar, true),
            ds.UIMsg('error', that.recoverForm, that.recoverButton, that.recoverAlertBar, true)
          ).then(
            function(res){

              // Show the alertbar's message that everything is OK
              that.recoverAlertBar.set('message', "Recovery email sent!");
              that.recoverAlertBar.show(3000);

              // Reset the form and button
              that.recoverForm.reset();
              that.recoverButton.cancel();
            }

          ); // stores('recoverAnon').put(data)

        }); // this.recoverForm.onSUbmit

        // Submit function
        this.loginForm.onSubmit = ds.defaultSubmit(this.loginForm, this.loginButton, function(){

          // Get the form's values, adding workspaceNameValue (which comes from the page)
          var data = that.loginForm.getValues();

          // Gets the workspaceName from the URL
          data.workspaceName = window.location.pathname.split(/\//)[3];

          // Store the data
          stores('loginAnon').put(data).then(
            ds.UIMsg('ok', that.loginForm, that.loginButton, that.loginAlertBar ),
            ds.UIMsg('error', that.loginForm, that.loginButton, that.loginAlertBar )
          ).then(
            function(res){
              if( typeof(that.onLogin) == 'function'){
                 that.onLogin(res);
              }
            },
            function(err){
              // Password incorrect, set it to nothing, give it the focus!
              that.password.set('value','');
              that.password.focus();
              that.password.reset();
            }
          );  // stores('loginanon').put(data)

        }); // this.loginform.onSubmit

     }, // postcreate

  });

});

<commit_msg>ACTUALLY Fixed problem where field with focus lose manually added tooltip straight away.<commit_after>
define([
  "dojo/_base/declare",
  "dojo/_base/lang",
  "dojo/_base/json",
  "dojo/_base/fx",
  "dojo/on",

  "dijit/form/Form",
  "dijit/_WidgetBase",
  "dijit/_TemplatedMixin",
  "dijit/_WidgetsInTemplateMixin",
  "dijit/layout/TabContainer",
  "dijit/layout/StackContainer",
  "dijit/layout/ContentPane",
  "dijit/layout/BorderContainer",
  "dijit/form/Button",
  "dijit/form/ValidationTextBox",
  "dijit/form/CheckBox",

  "hotplate/hotDojoSubmit/defaultSubmit",
  "hotplate/hotDojoStores/stores",
  "hotplate/hotDojoLogger/logger",
  "hotplate/hotDojoHooks/_TemplatedHooksMixin",
  "dojo/text!hotplate/hotDojoAuth/templates/LoginForm.html",

  "hotplate/hotDojoAuth/ValidationUsername",
  "hotplate/hotDojoAuth/ValidationPassword",
  "hotplate/hotDojoAuth/ValidationEmail",

  "hotplate/hotDojoWidgets/AlertBar",
  "hotplate/hotDojoWidgets/StackFading",
  "hotplate/hotDojoWidgets/TabFading",
  "hotplate/hotDojoWidgets/BusyButton",

   ], function(
     declare
     , lang
     , json
     , baseFx
     , on

     , Form
     , _WidgetBase
     , _TemplatedMixin
     , _WidgetsInTemplateMixin
     , TabContainer
     , StackContainer
     , ContentPane
     , BorderContainer
     , Button
     , ValidationTextBox
     , CheckBox

     , ds
     , stores
     , logger
     , _TemplatedHooksMixin
     , templateString

     , ValidationUsername
     , ValidationPassword
     , ValidationEmail
     , AlertBar

     , StackFading
     , TabFading
     , BusyButton
 ){
    // Create the "login" pane, based on a normal ContentPane
    return declare('hotplate.hotDojoAuth.LoginForm', [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _TemplatedHooksMixin ], {

      widgetsInTemplate: true,

      templateString:  templateString,

      // Hooks to switch tabs when clicking
      _onLoginClick: function(e){
        this.tabContainer.selectChild(this.loginPane);
      },

      _onRecoverClick: function(e){
        this.tabContainer.selectChild(this.recoverPane);
      },

      postCreate: function(){
        var that = this;

        //  If the global variable hotDojoAuth.login is set, then set the login name to
        //  the right value, and focus on the password widget
        if( vars.hotDojoAuth.login ){
          this.login.set( 'value', vars.hotDojoAuth.login );
          this.password.focus();
        } else {
          this.login.focus();
        }

        // If the password is in an erroneous state, reset it when user
        // clicks on the field. NOT before, as it would invalidate
        // the error message!
        this.password.on('click', function() {
          if( this.state === 'Error' ){
            this.set('value', '');
          }
        }),

        //this.password.onClick = function(){
        //};

        // Don't ACTUALLY submit the form
        this.recoverForm.onSubmit = ds.defaultSubmit(this.recoverForm, this.recoverButton, function(){

          // Get the form values
          var data = that.recoverForm.getValues();

          // Submit the info
          stores('recoverAnon').put(data).then(
            ds.UIMsg('ok', that.recoverForm, that.recoverButton, that.recoverAlertBar, true),
            ds.UIMsg('error', that.recoverForm, that.recoverButton, that.recoverAlertBar, true)
          ).then(
            function(res){

              // Show the alertbar's message that everything is OK
              that.recoverAlertBar.set('message', "Recovery email sent!");
              that.recoverAlertBar.show(3000);

              // Reset the form and button
              that.recoverForm.reset();
              that.recoverButton.cancel();
            }

          ); // stores('recoverAnon').put(data)

        }); // this.recoverForm.onSUbmit

        // Submit function
        this.loginForm.onSubmit = ds.defaultSubmit(this.loginForm, this.loginButton, function(){

          // Get the form's values, adding workspaceNameValue (which comes from the page)
          var data = that.loginForm.getValues();

          // Gets the workspaceName from the URL
          data.workspaceName = window.location.pathname.split(/\//)[3];

          // Store the data
          stores('loginAnon').put(data).then(
            ds.UIMsg('ok', that.loginForm, that.loginButton, that.loginAlertBar ),
            ds.UIMsg('error', that.loginForm, that.loginButton, that.loginAlertBar )
          ).then(
            function(res){
              if( typeof(that.onLogin) == 'function'){
                 that.onLogin(res);
              }
            },
            function(err){
              // Password incorrect, set it to nothing, give it the focus!
              // that.password.set('value','');
              // that.password.focus();
            }
          );  // stores('loginanon').put(data)

        }); // this.loginform.onSubmit

     }, // postcreate

  });

});

<|endoftext|>


<commit_before>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import classnames from 'classnames';

export default class DirectorySearchBox extends React.Component {
    constructor() {
        super();
        this.collectInput = this.collectInput.bind(this);
        this.onClearClick = this.onClearClick.bind(this);
        this.onChange = this.onChange.bind(this);
        this.onKeyUp = this.onKeyUp.bind(this);
        this.onJoinButtonClick = this.onJoinButtonClick.bind(this);

        this.input = null;

        this.state = {
            value: '',
        };
    }

    collectInput(e) {
        this.input = e;
    }

    onClearClick() {
        this.setState({value: ''});

        if (this.input) {
            this.input.focus();

            if (this.props.onClear) {
                this.props.onClear();
            }
        }
    }

    onChange(ev) {
        if (!this.input) return;
        this.setState({value: ev.target.value});

        if (this.props.onChange) {
            this.props.onChange(this.state.value);
        }
    }

    onKeyUp(ev) {
        if (ev.key == 'Enter') {
            if (this.props.onJoinClick) {
                this.props.onJoinClick(this.state.value);
            }
        }
    }

    onJoinButtonClick() {
        if (this.props.onJoinClick) {
            this.props.onJoinClick(this.state.value);
        }
    }

    _contentLooksLikeAlias() {
        if (!this.input) return false;

        // liberal test for things that look like room aliases
        return /^#.+:.+/.test(this.state.value);
    }

    render() {
        const searchbox_classes = {
            mx_DirectorySearchBox: true,
        };
        searchbox_classes[this.props.className] = true;

        let join_button;
        if (this._contentLooksLikeAlias()) {
            join_button =
                Join
            ;
        }

        return

                <input type="text" value={this.state.value}
                    className="mx_DirectorySearchBox_input"
                    ref={this.collectInput}
                    onChange={this.onChange} onKeyUp={this.onKeyUp}
                    placeholder="Find a room by keyword or room ID (#matrix:matrix.org)"
                />
                {join_button}

        ;
    }
}

DirectorySearchBox.propTypes = {
    className: React.PropTypes.string,
    onChange: React.PropTypes.func,
    onClear: React.PropTypes.func,
    onJoinClick: React.PropTypes.func,
};
<commit_msg>Give react callbacks underscores too<commit_after>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import classnames from 'classnames';

export default class DirectorySearchBox extends React.Component {
    constructor() {
        super();
        this._collectInput = this._collectInput.bind(this);
        this._onClearClick = this._onClearClick.bind(this);
        this._onChange = this._onChange.bind(this);
        this._onKeyUp = this._onKeyUp.bind(this);
        this._onJoinButtonClick = this._onJoinButtonClick.bind(this);

        this.input = null;

        this.state = {
            value: '',
        };
    }

    _collectInput(e) {
        this.input = e;
    }

    _onClearClick() {
        this.setState({value: ''});

        if (this.input) {
            this.input.focus();

            if (this.props.onClear) {
                this.props.onClear();
            }
        }
    }

    _onChange(ev) {
        if (!this.input) return;
        this.setState({value: ev.target.value});

        if (this.props.onChange) {
            this.props.onChange(this.state.value);
        }
    }

    _onKeyUp(ev) {
        if (ev.key == 'Enter') {
            if (this.props.onJoinClick) {
                this.props.onJoinClick(this.state.value);
            }
        }
    }

    _onJoinButtonClick() {
        if (this.props.onJoinClick) {
            this.props.onJoinClick(this.state.value);
        }
    }

    _contentLooksLikeAlias() {
        if (!this.input) return false;

        // liberal test for things that look like room aliases
        return /^#.+:.+/.test(this.state.value);
    }

    render() {
        const searchbox_classes = {
            mx_DirectorySearchBox: true,
        };
        searchbox_classes[this.props.className] = true;

        let join_button;
        if (this._contentLooksLikeAlias()) {
            join_button =
                Join
            ;
        }

        return

                <input type="text" value={this.state.value}
                    className="mx_DirectorySearchBox_input"
                    ref={this._collectInput}
                    onChange={this._onChange} onKeyUp={this._onKeyUp}
                    placeholder="Find a room by keyword or room ID (#matrix:matrix.org)"
                />
                {join_button}

        ;
    }
}

DirectorySearchBox.propTypes = {
    className: React.PropTypes.string,
    onChange: React.PropTypes.func,
    onClear: React.PropTypes.func,
    onJoinClick: React.PropTypes.func,
};
<|endoftext|>


<commit_before>// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.

//Run this command to package up application for distribution
//electron-packager .

var dataModels = [];

var showFreq = true;
var showTime = true;

function UserException(message) {
    this.message = message;
    this.name = 'UserException';
}

function showFreqDomain() {
    showFreq = !showFreq;
    if (showFreq == true) {
        $('#showFreqDomain').text("Show Freq Domain")
        document.getElementById('spectrum').style.display = "none"; // Hide Landing Page
    }
    if (showFreq == false) {
        $('#showFreqDomain').text("Hide Freq Domain")
        document.getElementById('spectrum').style.display = "inline"; // Hide Landing Page
    }
}

function showTimeDomain() {

}

function newData() {
    const { dialog } = require('electron').remote;

    var path = dialog.showOpenDialog({
        filters: [

            { name: 'text', extensions: ['txt'] }

        ],
        properties: ['openFile']
    });

    dataModels.push(new dataModel(path.toString()));
    console.log("New Data Model created");

    document.getElementById('DataSection').style.display = "inline"; //Show Data Page
    document.getElementById('LandingPage').style.display = "none"; // Hide Landing Page

}

class dataModel {

    constructor(pathToFile) {

        $('#FileOutput').text(pathToFile)

        //public variables
        this.pathToFile = pathToFile;
        this.rawData = this.readDataIn(this.pathToFile);
        this.fftData = this.fft(this.rawData);
        this.fftDataMag = this.magDataDb(this.fftData);
        this.harmonics = this.calcHarmonics(this.fftDataMag);
        this.THD = this.calcTHD(this.fftData, this.harmonics);
        this.THDN = this.calcTHDN(this.fftData, this.harmonics[1]);
        this.SNR = this.calcSNR(this.THDN, this.fftDataMag[this.harmonics[1]]);
        this.DC = this.fftDataMag[0];

        console.log("Fund" + this.fftData[this.harmonics[1]])

        //Move to Controller along with harmonic data
        $('#THD').text(this.THD.toString())
        $('#THDN').text(this.THDN.toString())
        $('#SNR').text(this.SNR.toString())
        $('#DC').text(this.DC.toString())

        this.plotData(this.fftDataMag, 'spectrum');
        this.plotData(this.rawData, 'timeDomain')
    }

    A_WeightedFrequencies(waveform) {
        //https://www.npmjs.com/package/a-weighting
        var aWeight = require('a-weighting/a');
        var ft = require('fourier-transform');
        var frequencies = ft(waveform).map(function (magnitude, i, data) {
            var frequency = 22050 * i / data;

            return aWeight(frequency) * magnitude;
        });
        return (frequencies)
    }

    readDataIn(pathToFile) {

        const fs = require("fs");

        var data = fs.readFileSync(pathToFile);

        //Convert string of Data to Array of Floats
        var arrayOfData = data.toString().split(/\r\n|\r|\n/g).map(function (i) {
            return parseFloat(i);
        })

        //Clean Array of floats to remove NaN error at last place
        arrayOfData.splice(arrayOfData.length - 1, 1)

        return (arrayOfData);
    }

    fft(rawData) {
        var ft = require('fourier-transform');
        var db = require('decibels');

        var spectrum = ft(rawData);

        return (spectrum)
    }

    magDataDb(fftData) {
        //convert to decibels
        var db = require('decibels');
        var decibels = fftData.map((value) => db.fromGain(value))

        return (decibels);
    }

    calcHarmonics(fftDataArray) {

        //Find the Fundemental Freq by searching for largest freq besides DC
        var largestValueIndex = -1;
        var largestValue = -200;
        for (var i = 1; i < fftDataArray.length - 1; i++) {
            if (fftDataArray[i] > largestValue) {
                largestValue = fftDataArray[i];
                largestValueIndex = i;
            }
        }

        //index 1 has fundemental, going upward
        var harmonicIndex = [];
        harmonicIndex.push(0);
        harmonicIndex.push(largestValueIndex);

        //Search for harmonic in range
        function findLargestValueIndexInRange(array, range, searchIndex) {

            //if Search index is greater than array, the harmonic is out of range
            if (searchIndex + range > array.length) {
                return (-1);
            }

            var largestValueInRange = -200; //-Infinity
            var largestValueInRangeIndex = searchIndex;
            for (var i = searchIndex - range; i <= searchIndex + range; i++) {
                if (array[i] > largestValueInRange) {
                    largestValueInRange = array[i];
                    largestValueInRangeIndex = i;
                }
            }
            return (largestValueInRangeIndex);
        }

        var numberOfHarmonics = 10
        for (var i = 2; i <= numberOfHarmonics; i++) {

            var sampleHarmonic = findLargestValueIndexInRange(fftDataArray, 5, harmonicIndex[1] * i);

            if (sampleHarmonic == -1) {
                //quit for loop
                i = numberOfHarmonics + 1;
            }
            else {
                harmonicIndex.push(sampleHarmonic);
            }
        }

        for (var i = 1; i < harmonicIndex.length; i++) {
            console.log(i + ": " + harmonicIndex[i] + " " + fftDataArray[harmonicIndex[i]].toString())
            $('#' + i + 'Harmonic').text(fftDataArray[harmonicIndex[i]].toString())
        }

        return (harmonicIndex);
    }

    calcTHD(data, harmonicIndex) {
        var THD = -300;

        var HarmonicAmplitudesSquared = 0;
        for (var i = 2; i < harmonicIndex.length; i++) {
            HarmonicAmplitudesSquared = HarmonicAmplitudesSquared + Math.pow(data[harmonicIndex[i]], 2)
        }

        THD = Math.sqrt(HarmonicAmplitudesSquared);

        THD = THD / data[harmonicIndex[1]];

        THD = 20 * Math.log10(THD);

        if (THD == -300) {
            console.log("THD Calculation Failed");
        }
        else {
            console.log("THD: " + THD);
            return (THD);
        }
    }

    calcTHDN(data, fundementalIndex) {

        var SumOfAmplitudes = 0;
        //Start after the DC bin
        for (var i = 1; i < data.length; i++) {
            if (i != fundementalIndex && i != fundementalIndex + 1 && i != fundementalIndex - 1) {
                SumOfAmplitudes = SumOfAmplitudes + Math.pow(data[i], 2)
            }
        }

        var THDN = Math.sqrt(SumOfAmplitudes);

        THDN = THDN / data[fundementalIndex];

        THDN = 20 * Math.log10(THDN)

        if (THDN == -300) {
            console.log("THDN Calculation Failed");
        }
        else {
            console.log("THDN: " + THDN);
            return (THDN);
        }
    }

    calcSNR(THDN, fundemental) {
        return (THDN / fundemental);
    }

    plotData(spectrum, element) {
        var x = [];

        for (var i = 0; i < spectrum.length - 1; i++) {
            x.push(i);
        }

        var trace = {
            type: 'scatter',                    // set the chart type
            mode: 'lines',                      // connect points with lines
            x: x,
            y: spectrum,
            line: {                             // set the width of the line.
                width: 2,
                color: 'rgb(71,23,246)'
            }
        };

        var layout = {
            yaxis: {
                title: "dB",
                color: 'rgb(231,223,221)'
            },
            xaxis: {
                title: "Bin",
                showgrid: false,
                color: 'rgb(231,223,221)'
            },
            margin: {                           // update the left, bottom, right, top margin
                l: 40, b: 40, r: 40, t: 40
            },
            paper_bgcolor: 'rgba(0,0,0,0)',
            plot_bgcolor: 'rgba(0,0,0,0)'
        };

        Plotly.plot(document.getElementById(element), [trace], layout, { showLink: false });

        /*
        var TESTER = document.getElementById(element);
        Plotly.plot( TESTER, [{
        x: x,
        y: spectrum,
        mode: "lines",
        type: "scatter",
        title: "Spectum Plot"
        }], {
            margin: { t: 0 }
        } );*/
    }

    plotData2(decibels) {

        var x = [];

        for (var i = 0; i < decibels.length - 1; i++) {
            x.push(i);
        }
    }

}
<commit_msg>The controller begins<commit_after>// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.

//Run this command to package up application for distribution
//electron-packager .

var dataModels = [];

var showFreq = true;
var showTime = true;

function UserException(message) {
    this.message = message;
    this.name = 'UserException';
}

function showFreqDomain() {
    showFreq = !showFreq;
    if (showFreq == true) {
        $('#showFreqDomain').text("Show Freq Domain")
        document.getElementById('spectrum').style.display = "none"; // Hide Landing Page
    }
    if (showFreq == false) {
        $('#showFreqDomain').text("Hide Freq Domain")
        document.getElementById('spectrum').style.display = "inline"; // Hide Landing Page
    }
}

function showTimeDomain() {

}

class controller {
    //Begin
}

/*
    Known problems:

    * Not sure if actual fft function is correct. Data from it does not compare the same to Richards and R studio, or Unison for that matter.
    * Many things that should be done with the controller are done here. This needs to change.

*/

function newData() {
    const { dialog } = require('electron').remote;

    var path = dialog.showOpenDialog({
        filters: [

            { name: 'text', extensions: ['txt'] }

        ],
        properties: ['openFile']
    });

    dataModels.push(new dataModel(path.toString()));
    console.log("New Data Model created");

    document.getElementById('DataSection').style.display = "inline"; //Show Data Page
    document.getElementById('LandingPage').style.display = "none"; // Hide Landing Page

}

class dataModel {

    constructor(pathToFile) {

        $('#FileOutput').text(pathToFile)

        //public variables
        this.pathToFile = pathToFile;
        this.rawData = this.readDataIn(this.pathToFile);
        this.fftData = this.fft(this.rawData);
        this.fftDataMag = this.magDataDb(this.fftData);
        this.harmonics = this.calcHarmonics(this.fftDataMag);
        this.THD = this.calcTHD(this.fftData, this.harmonics);
        this.THDN = this.calcTHDN(this.fftData, this.harmonics[1]);
        this.SNR = this.calcSNR(this.THDN, this.fftDataMag[this.harmonics[1]]);
        this.DC = this.fftDataMag[0];

        console.log("Fund" + this.fftData[this.harmonics[1]])

        //Move to Controller along with harmonic data
        $('#THD').text(this.THD.toString())
        $('#THDN').text(this.THDN.toString())
        $('#SNR').text(this.SNR.toString())
        $('#DC').text(this.DC.toString())

        this.plotData(this.fftDataMag, 'spectrum');
        this.plotData(this.rawData, 'timeDomain')
    }

    A_WeightedFrequencies(waveform) {
        //https://www.npmjs.com/package/a-weighting
        var aWeight = require('a-weighting/a');
        var ft = require('fourier-transform');
        var frequencies = ft(waveform).map(function (magnitude, i, data) {
            var frequency = 22050 * i / data;

            return aWeight(frequency) * magnitude;
        });
        return (frequencies)
    }

    readDataIn(pathToFile) {

        const fs = require("fs");

        var data = fs.readFileSync(pathToFile);

        //Convert string of Data to Array of Floats
        var arrayOfData = data.toString().split(/\r\n|\r|\n/g).map(function (i) {
            return parseFloat(i);
        })

        //Clean Array of floats to remove NaN error at last place
        arrayOfData.splice(arrayOfData.length - 1, 1)

        return (arrayOfData);
    }

    fft(rawData) {
        var ft = require('fourier-transform');
        var db = require('decibels');

        var spectrum = ft(rawData);

        return (spectrum)
    }

    magDataDb(fftData) {
        //convert to decibels
        var db = require('decibels');
        var decibels = fftData.map((value) => db.fromGain(value))

        return (decibels);
    }

    calcHarmonics(fftDataArray) {

        //Find the Fundemental Freq by searching for largest freq besides DC
        var largestValueIndex = -1;
        var largestValue = -200;
        for (var i = 1; i < fftDataArray.length - 1; i++) {
            if (fftDataArray[i] > largestValue) {
                largestValue = fftDataArray[i];
                largestValueIndex = i;
            }
        }

        //index 1 has fundemental, going upward
        var harmonicIndex = [];
        harmonicIndex.push(0);
        harmonicIndex.push(largestValueIndex);

        //Search for harmonic in range
        function findLargestValueIndexInRange(array, range, searchIndex) {

            //if Search index is greater than array, the harmonic is out of range
            if (searchIndex + range > array.length) {
                return (-1);
            }

            var largestValueInRange = -200; //-Infinity
            var largestValueInRangeIndex = searchIndex;
            for (var i = searchIndex - range; i <= searchIndex + range; i++) {
                if (array[i] > largestValueInRange) {
                    largestValueInRange = array[i];
                    largestValueInRangeIndex = i;
                }
            }
            return (largestValueInRangeIndex);
        }

        var numberOfHarmonics = 10
        for (var i = 2; i <= numberOfHarmonics; i++) {

            var sampleHarmonic = findLargestValueIndexInRange(fftDataArray, 5, harmonicIndex[1] * i);

            if (sampleHarmonic == -1) {
                //quit for loop
                i = numberOfHarmonics + 1;
            }
            else {
                harmonicIndex.push(sampleHarmonic);
            }
        }

        for (var i = 1; i < harmonicIndex.length; i++) {
            console.log(i + ": " + harmonicIndex[i] + " " + fftDataArray[harmonicIndex[i]].toString())
            $('#' + i + 'Harmonic').text(fftDataArray[harmonicIndex[i]].toString())
        }

        return (harmonicIndex);
    }

    calcTHD(data, harmonicIndex) {
        var THD = -300;

        var HarmonicAmplitudesSquared = 0;
        for (var i = 2; i < harmonicIndex.length; i++) {
            HarmonicAmplitudesSquared = HarmonicAmplitudesSquared + Math.pow(data[harmonicIndex[i]], 2)
        }

        THD = Math.sqrt(HarmonicAmplitudesSquared);

        THD = THD / data[harmonicIndex[1]];

        THD = 20 * Math.log10(THD);

        if (THD == -300) {
            console.log("THD Calculation Failed");
        }
        else {
            console.log("THD: " + THD);
            return (THD);
        }
    }

    calcTHDN(data, fundementalIndex) {

        var SumOfAmplitudes = 0;
        //Start after the DC bin
        for (var i = 1; i < data.length; i++) {
            if (i != fundementalIndex && i != fundementalIndex + 1 && i != fundementalIndex - 1) {
                SumOfAmplitudes = SumOfAmplitudes + Math.pow(data[i], 2)
            }
        }

        var THDN = Math.sqrt(SumOfAmplitudes);

        THDN = THDN / data[fundementalIndex];

        THDN = 20 * Math.log10(THDN)

        if (THDN == -300) {
            console.log("THDN Calculation Failed");
        }
        else {
            console.log("THDN: " + THDN);
            return (THDN);
        }
    }

    calcSNR(THDN, fundemental) {
        return (THDN / fundemental);
    }

    plotData(spectrum, element) {
        var x = [];

        for (var i = 0; i < spectrum.length - 1; i++) {
            x.push(i);
        }

        var trace = {
            type: 'scatter',                    // set the chart type
            mode: 'lines',                      // connect points with lines
            x: x,
            y: spectrum,
            line: {                             // set the width of the line.
                width: 2,
                color: 'rgb(71,23,246)'
            }
        };

        var layout = {
            yaxis: {
                title: "dB",
                color: 'rgb(231,223,221)'
            },
            xaxis: {
                title: "Bin",
                showgrid: false,
                color: 'rgb(231,223,221)'
            },
            margin: {                           // update the left, bottom, right, top margin
                l: 40, b: 40, r: 40, t: 40
            },
            paper_bgcolor: 'rgba(0,0,0,0)',
            plot_bgcolor: 'rgba(0,0,0,0)'
        };

        Plotly.plot(document.getElementById(element), [trace], layout, { showLink: false });

        /*
        var TESTER = document.getElementById(element);
        Plotly.plot( TESTER, [{
        x: x,
        y: spectrum,
        mode: "lines",
        type: "scatter",
        title: "Spectum Plot"
        }], {
            margin: { t: 0 }
        } );*/
    }

    plotData2(decibels) {

        var x = [];

        for (var i = 0; i < decibels.length - 1; i++) {
            x.push(i);
        }
    }

}
<|endoftext|>


<commit_before>import EligibleClients from '/imports/api/eligibleClients/eligibleClients';
import { fullName, getClientSchemaFromLinks } from '/imports/api/utils';
import { TableDom } from '/imports/ui/dataTable/helpers';
import './eligibleClientsListView.html';

const tableOptions = {
  columns: [
    {
      data: 'client',
      title: 'Client',
      minWidth: 160,
      render(client) {
        const url = Router.path('viewClient',
          { _id: client.id },
          { query: `schema=${client.schema}` }
        );
        return `<a href="${url}">${fullName(client)}</a>`;
      },
      filterMethod(filter, eligibleClient /* , column*/) {
        const { client } = eligibleClient;
        const clientDetails = client || { loading: true };
        // TODO: trigger client data load if no data coming from subscription
        let value = '';
        if (clientDetails.loading) {
          value = 'Loading...';
        } else {
          value = fullName(clientDetails) || client.clientId;
        }
        return value.toLowerCase().includes(filter.value.toLowerCase());
      },
    },
    {
      title: 'Score',
      data: 'surveyScore',
      minWidth: 80,
      render(value, type, doc) {
        const client = doc.client;
        // console.log(client);
        const query = {
          clientId: doc.clientId,
          schema: client.schema,
        };
        if (client.schema) {
          const url = Router.path('adminDashboardresponsesView', {},
            { query }
          );
          return `<a href="${url}">${value}</a>`;
        }
        return value;
      },
    },
    {
      title: 'Survey Date',
      data: 'surveyDate',
      minWidth: 150,
    },
    {
      title: 'Match Status',
      data: 'matched',
      render(value) { return `${value}`; },
    },
  ],
  order: [
    [0, 'asc'],
  ],
  dom: TableDom,
};

Template.eligibleClientsListView.helpers({
  hasData() {
    return EligibleClients.find().count() > 0;
  },
  tableData() {
    return () => EligibleClients.find({}).fetch();
  },
  tableOptions() {
    return tableOptions;
  },
  loadData() {
    return () => ((pageNumber, pageSize, sort, order, callback) => {
      // console.log('callback', pageNumber, pageSize, sort, order, callback);
      const sortBy = Array.isArray(sort) ? sort[0] : sort;
      const orderBy = Array.isArray(order) ? order[0] : order;
      // return Meteor.subscribe('eligibleClients.page', pageNumber, pageSize, sortBy, orderBy);
      return Meteor.call('getEligibleClientsPage', pageNumber, pageSize, sortBy, orderBy,
        (err, res) => {
          res.content.forEach(eligibleClient => {
            const schema = getClientSchemaFromLinks(eligibleClient.links, 'v2015');
            Object.assign(eligibleClient.client, { schema });
            EligibleClients._collection.update(eligibleClient._id || eligibleClient.clientId, eligibleClient, {upsert: true}); // eslint-disable-line
          });
          const data = EligibleClients.find({}).fetch();
          const pages = res.page.totalPages;
          if (callback) callback({ data, pages });
        });
    });
  },
});

Template.eligibleClientsListView.events(
  {
    'click .postHousingMatchScores': () => {
      Meteor.call(
        'postHousingMatchScores', (err, res) => {
          if (err) {
            Bert.alert(err.reason || err.error || err.message, 'danger', 'growl-top-right');
          } else {
            Bert.alert(`${res}`, 'success', 'growl-top-right');
          }
        }
      );
    },
  }
);
<commit_msg>update active list to show bonus score and total score<commit_after>import EligibleClients from '/imports/api/eligibleClients/eligibleClients';
import { fullName, getClientSchemaFromLinks } from '/imports/api/utils';
import { TableDom } from '/imports/ui/dataTable/helpers';
import './eligibleClientsListView.html';

const tableOptions = {
  columns: [
    {
      data: 'client',
      title: 'Client',
      minWidth: 160,
      render(client) {
        const url = Router.path('viewClient',
          { _id: client.id },
          { query: `schema=${client.schema}` }
        );
        return `<a href="${url}">${fullName(client)}</a>`;
      },
      filterMethod(filter, eligibleClient /* , column*/) {
        const { client } = eligibleClient;
        const clientDetails = client || { loading: true };
        // TODO: trigger client data load if no data coming from subscription
        let value = '';
        if (clientDetails.loading) {
          value = 'Loading...';
        } else {
          value = fullName(clientDetails) || client.clientId;
        }
        return value.toLowerCase().includes(filter.value.toLowerCase());
      },
    },
    {
      title: 'Survey Score',
      data: 'surveyScore',
      render(value, type, doc) {
        const client = doc.client;
        // console.log(client);
        const query = {
          clientId: doc.clientId,
          schema: client.schema,
        };
        if (client.schema) {
          const url = Router.path('adminDashboardresponsesView', {},
            { query }
          );
          return `<a href="${url}">${value}</a>`;
        }
        return value;
      },
    },
    {
      title: 'Bonus Score',
      data: 'bonusScore',
    },
    {
      title: 'Total Score',
      data: 'totalScore',
    },
    {
      title: 'Survey Date',
      data: 'surveyDate',
    },
    {
      title: 'Match Status',
      data: 'matched',
      render(value) { return `${value}`; },
    },
  ],
  order: [
    [0, 'asc'],
  ],
  dom: TableDom,
};

Template.eligibleClientsListView.helpers({
  hasData() {
    return EligibleClients.find().count() > 0;
  },
  tableData() {
    return () => EligibleClients.find({}).fetch();
  },
  tableOptions() {
    return tableOptions;
  },
  loadData() {
    return () => ((pageNumber, pageSize, sort, order, callback) => {
      // console.log('callback', pageNumber, pageSize, sort, order, callback);
      const sortBy = Array.isArray(sort) ? sort[0] : sort;
      const orderBy = Array.isArray(order) ? order[0] : order;
      // return Meteor.subscribe('eligibleClients.page', pageNumber, pageSize, sortBy, orderBy);
      return Meteor.call('getEligibleClientsPage', pageNumber, pageSize, sortBy, orderBy,
        (err, res) => {
          res.content.forEach(eligibleClient => {
            const schema = getClientSchemaFromLinks(eligibleClient.links, 'v2015');
            Object.assign(eligibleClient.client, { schema });
            EligibleClients._collection.update(eligibleClient._id || eligibleClient.clientId, eligibleClient, {upsert: true}); // eslint-disable-line
          });
          const data = EligibleClients.find({}).fetch();
          const pages = res.page.totalPages;
          if (callback) callback({ data, pages });
        });
    });
  },
});

Template.eligibleClientsListView.events(
  {
    'click .postHousingMatchScores': () => {
      Meteor.call(
        'postHousingMatchScores', (err, res) => {
          if (err) {
            Bert.alert(err.reason || err.error || err.message, 'danger', 'growl-top-right');
          } else {
            Bert.alert(`${res}`, 'success', 'growl-top-right');
          }
        }
      );
    },
  }
);
<|endoftext|>


<commit_before>import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { Meteor } from 'meteor/meteor';

import { templetize, getImage } from '/imports/ui/templates/layout/templater';
import { animatePopup } from '/imports/ui/modules/popup';
import { searchJSON } from '/imports/ui/modules/JSON';
import { token } from '/lib/token';
import { createPoll, removePoll } from '/imports/startup/both/modules/Contract';
import { Contracts } from '/imports/api/contracts/Contracts';
import { getCoin } from '/imports/api/blockchain/modules/web3Util';

import '/imports/ui/templates/widgets/setting/setting.js';
import '/imports/ui/templates/components/decision/coin/coin.html';

const Web3 = require('web3');

const web3 = new Web3();

/**
* @summary save data on contract
*/
const _save = () => {
  const draft = Session.get('draftContract');
  const coin = Session.get('newCoin');

  draft.constituency = _.reject(draft.constituency, (rule) => { return (rule.kind === 'TOKEN'); });

  if (coin && coin !== '') {
    draft.constituency.push({
      kind: 'TOKEN',
      code: coin.code,
      check: 'EQUAL',
    });
    draft.wallet.currency = coin.code;
    draft.blockchain.coin.code = coin.code;
  }

  if (draft.constituency.length === 0) {
    draft.constituencyEnabled = false;
  }

  draft.blockchain.publicAddress = document.getElementById('editBlockchainAddress').value;
  draft.blockchain.votePrice = '1';
  for (let i = 0; i < token.coin.length; i += 1) {
    if (token.coin[i].code === coin.code) {
      draft.blockchain.votePrice = token.coin[i].defaultVote;
      break;
    }
  }

  draft.rules = Session.get('cachedDraft').rules;
  if (draft.rules && draft.rules.pollVoting === true) {
    draft.poll = createPoll(draft).poll;
  } else {
    if (draft.rules && !draft.rules.pollVoting && draft.poll.length > 0) {
      removePoll(draft);
    }
    draft.poll = [];
  }

  Session.set('draftContract', draft);
};

/**
* @summary checks if there's an issue with lockchain address
* @return {boolean} true or false baby
*/
const _verifyBlockchainAddress = () => {
  const draft = Session.get('draftContract');
  if (draft.blockchain.coin.code !== 'STX') {
    return !Session.get('checkBlockchainAddress');
  }
  return false;
};

/**
* @summary check form inputs are ok
* @return {boolean} true or false baby
*/
const _checkInputs = () => {
  return !(Session.get('noCoinFound')
    || Session.get('newCoin') === ''
    || (Session.get('draftContract').blockchain.publicAddress && !Session.get('checkBlockchainAddress'))
    || (!Meteor.user().profile.wallet.reserves && Session.get('draftContract').blockchain.coin.code !== 'WEB VOTE')
    || (_verifyBlockchainAddress() && Session.get('newCoin') && Session.get('newCoin').code !== 'WEB VOTE'));
};

Template.coin.onCreated(() => {
  Session.set('showTokens', false);
  Session.set('suggestDisplay', '');

  Template.instance().currentCoin = new ReactiveVar();
  Template.instance().showAdvanced = new ReactiveVar(false);
  Template.instance().imageTemplate = new ReactiveVar();
  templetize(Template.instance());
});

Template.coin.onRendered(function () {
  // show current coin set in draft
  const draft = Session.get('draftContract');
  for (let i = 0; i < draft.constituency.length; i += 1) {
    if (draft.constituency[i].kind === 'TOKEN') {
      for (let j = 0; j < token.coin.length; j += 1) {
        if (token.coin[j].code === draft.constituency[i].code) {
          Session.set('newCoin', token.coin[j]);
          break;
        }
      }
      break;
    }
  }

  // let advancedSettings = false;
  // _.find(Session.get('draftContract').rules, function (num) { if (num) { advancedSettings = true; } });
  // Template.instance().showAdvanced.set(advancedSettings);
  Template.instance().showAdvanced.set((Session.get('draftContract').rules.quadraticVoting === true));

  Session.set('cachedDraft', Session.get('draftContract'));
});

Template.coin.helpers({
  showTokens() {
    return (Session.get('suggestDisplay') === 'TOKEN');
  },
  token() {
    if (Session.get('newCoin') !== undefined) {
      return Session.get('newCoin').name;
    }
    return undefined;
  },
  address() {
    const draft = Session.get('draftContract');
    if (draft.blockchain && draft.blockchain.publicAddress && Session.get('newCoin').code !== 'WEB VOTE') {
      Session.set('checkBlockchainAddress', web3.utils.isAddress(draft.blockchain.publicAddress));
      return draft.blockchain.publicAddress;
    }
    return '';
  },
  price() {
    const draft = Session.get('draftContract');
    if (draft.blockchain.votePrice) {
      return draft.blockchain.votePrice;
    }
    return '';
  },
  contract() {
    return Session.get('draftContract');
  },
  balanceVoting() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      if (!coin.editor.allowBalanceToggle) {
        const cache = Session.get('cachedDraft');
        cache.rules.balanceVoting = false;
        Session.set('cachedDraft', cache);
      }
      return Session.get('cachedDraft').rules ? (Session.get('cachedDraft').rules.balanceVoting && coin.editor.allowBalanceToggle) : false;
    }
    return false;
  },
  quadraticVoting() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      if (!coin.editor.allowQuadraticToggle) {
        const cache = Session.get('cachedDraft');
        cache.rules.quadraticVoting = false;
        Session.set('cachedDraft', cache);
      }
      return Session.get('cachedDraft').rules ? (Session.get('cachedDraft').rules.quadraticVoting && coin.editor.allowQuadraticToggle) : false;
    }
    return false;
  },
  pollVoting() {
    return (Session.get('cachedDraft') && Session.get('cachedDraft').rules) ? Session.get('cachedDraft').rules.pollVoting : false;
  },
  allowBalance() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      return coin.editor.allowBalanceToggle;
    }
    return false;
  },
  allowQuadratic() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      return coin.editor.allowQuadraticToggle;
    }
    return false;
  },
  wrongAddress() {
    return _verifyBlockchainAddress();
  },
  addressStyle() {
    if (Session.get('newCoin') && Session.get('newCoin').code === 'WEB VOTE') {
      return 'display: none;';
    }
    return '';
  },
  buttonDisable() {
    if (!_checkInputs()) {
      return 'button-disabled';
    }
    return '';
  },
  getImage(pic) {
    return getImage(Template.instance().imageTemplate.get(), pic);
  },
  showAdvanced() {
    return Template.instance().showAdvanced.get();
  },
  showReserves() {
    if (Meteor.user() && Meteor.user().profile.wallet.reserves) {
      return 'display:auto;';
    }
    return 'display:none;';
  },
});

Template.coin.events({
  'click #cancel-coin'() {
    animatePopup(false, 'blockchain-popup');
    Session.set('showCoinSettings', false);
  },
  'click #advanced'(event) {
    event.preventDefault();
    const advanced = Template.instance().showAdvanced.get();
    Template.instance().showAdvanced.set(!advanced);
  },
  'click #execute-coin'() {
    if (_checkInputs()) {
      _save();
      animatePopup(false, 'blockchain-popup');
      Session.set('showCoinSettings', false);
    }
  },
  'input #editBlockchainAddress'() {
    if (document.getElementById('editBlockchainAddress')) {
      const address = document.getElementById('editBlockchainAddress').value;
      Session.set('checkBlockchainAddress', web3.utils.isAddress(address));
    }
  },
  'input #editVotePrice'() {
    if (document.getElementById('editVotePrice')) {
      const price = document.getElementById('editVotePrice').value;
      if (price.toNumber() < 0) {
        document.getElementById('editVotePrice').value = '';
      }
    }
  },
  'input .token-search'(event) {
    if (event.target.value !== '') {
      Session.set('filteredCoins', searchJSON(token.coin, event.target.value));
    } else {
      Session.set('filteredCoins', token.coin);
      Session.set('newCoin', '');
    }
  },
  'focus .token-search'() {
    Session.set('suggestDisplay', 'TOKEN');
  },
});
<commit_msg>prevent blockchain tokens to be edited without an address<commit_after>import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { Meteor } from 'meteor/meteor';

import { templetize, getImage } from '/imports/ui/templates/layout/templater';
import { animatePopup } from '/imports/ui/modules/popup';
import { searchJSON } from '/imports/ui/modules/JSON';
import { token } from '/lib/token';
import { createPoll, removePoll } from '/imports/startup/both/modules/Contract';
import { Contracts } from '/imports/api/contracts/Contracts';
import { getCoin } from '/imports/api/blockchain/modules/web3Util';

import '/imports/ui/templates/widgets/setting/setting.js';
import '/imports/ui/templates/components/decision/coin/coin.html';

const Web3 = require('web3');

const web3 = new Web3();

/**
* @summary save data on contract
*/
const _save = () => {
  const draft = Session.get('draftContract');
  const coin = Session.get('newCoin');

  draft.constituency = _.reject(draft.constituency, (rule) => { return (rule.kind === 'TOKEN'); });

  if (coin && coin !== '') {
    draft.constituency.push({
      kind: 'TOKEN',
      code: coin.code,
      check: 'EQUAL',
    });
    draft.wallet.currency = coin.code;
    draft.blockchain.coin.code = coin.code;
  }

  if (draft.constituency.length === 0) {
    draft.constituencyEnabled = false;
  }

  draft.blockchain.publicAddress = document.getElementById('editBlockchainAddress').value;
  draft.blockchain.votePrice = '1';
  for (let i = 0; i < token.coin.length; i += 1) {
    if (token.coin[i].code === coin.code) {
      draft.blockchain.votePrice = token.coin[i].defaultVote;
      break;
    }
  }

  draft.rules = Session.get('cachedDraft').rules;
  if (draft.rules && draft.rules.pollVoting === true) {
    draft.poll = createPoll(draft).poll;
  } else {
    if (draft.rules && !draft.rules.pollVoting && draft.poll.length > 0) {
      removePoll(draft);
    }
    draft.poll = [];
  }

  Session.set('draftContract', draft);
};

/**
* @summary checks if there's an issue with lockchain address
* @return {boolean} true or false baby
*/
const _verifyBlockchainAddress = () => {
  const draft = Session.get('draftContract');
  if (draft.blockchain.coin.code !== 'STX') {
    return !Session.get('checkBlockchainAddress');
  }
  return false;
};

/**
* @summary check form inputs are ok
* @return {boolean} true or false baby
*/
const _checkInputs = () => {
  return !(Session.get('noCoinFound')
    || Session.get('newCoin') === ''
    || (Session.get('draftContract').blockchain.publicAddress && !Session.get('checkBlockchainAddress'))
    || (!Meteor.user().profile.wallet.reserves && Session.get('draftContract').blockchain.coin.code !== 'WEB VOTE')
    || (_verifyBlockchainAddress() && Session.get('newCoin') && Session.get('newCoin').code !== 'WEB VOTE'));
};

Template.coin.onCreated(() => {
  Session.set('showTokens', false);
  Session.set('suggestDisplay', '');

  Template.instance().currentCoin = new ReactiveVar();
  Template.instance().showAdvanced = new ReactiveVar(false);
  Template.instance().imageTemplate = new ReactiveVar();
  templetize(Template.instance());
});

Template.coin.onRendered(function () {
  // show current coin set in draft
  const draft = Session.get('draftContract');
  for (let i = 0; i < draft.constituency.length; i += 1) {
    if (draft.constituency[i].kind === 'TOKEN') {
      for (let j = 0; j < token.coin.length; j += 1) {
        if (token.coin[j].code === draft.constituency[i].code) {
          Session.set('newCoin', token.coin[j]);
          break;
        }
      }
      break;
    }
  }

  // let advancedSettings = false;
  // _.find(Session.get('draftContract').rules, function (num) { if (num) { advancedSettings = true; } });
  // Template.instance().showAdvanced.set(advancedSettings);
  Template.instance().showAdvanced.set((Session.get('draftContract').rules.quadraticVoting === true));

  Session.set('cachedDraft', Session.get('draftContract'));
});

Template.coin.helpers({
  showTokens() {
    return (Session.get('suggestDisplay') === 'TOKEN');
  },
  token() {
    if (Session.get('newCoin') !== undefined) {
      return Session.get('newCoin').name;
    }
    return undefined;
  },
  address() {
    const draft = Session.get('draftContract');
    if (draft.blockchain && draft.blockchain.publicAddress && Session.get('newCoin').code !== 'WEB VOTE') {
      Session.set('checkBlockchainAddress', web3.utils.isAddress(draft.blockchain.publicAddress));
      return draft.blockchain.publicAddress;
    }
    return '';
  },
  price() {
    const draft = Session.get('draftContract');
    if (draft.blockchain.votePrice) {
      return draft.blockchain.votePrice;
    }
    return '';
  },
  contract() {
    return Session.get('draftContract');
  },
  balanceVoting() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      if (!coin.editor.allowBalanceToggle) {
        const cache = Session.get('cachedDraft');
        cache.rules.balanceVoting = false;
        Session.set('cachedDraft', cache);
      }
      return Session.get('cachedDraft').rules ? (Session.get('cachedDraft').rules.balanceVoting && coin.editor.allowBalanceToggle) : false;
    }
    return false;
  },
  quadraticVoting() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      if (!coin.editor.allowQuadraticToggle) {
        const cache = Session.get('cachedDraft');
        cache.rules.quadraticVoting = false;
        Session.set('cachedDraft', cache);
      }
      return Session.get('cachedDraft').rules ? (Session.get('cachedDraft').rules.quadraticVoting && coin.editor.allowQuadraticToggle) : false;
    }
    return false;
  },
  pollVoting() {
    return (Session.get('cachedDraft') && Session.get('cachedDraft').rules) ? Session.get('cachedDraft').rules.pollVoting : false;
  },
  allowBalance() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      return coin.editor.allowBalanceToggle;
    }
    return false;
  },
  allowQuadratic() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      return coin.editor.allowQuadraticToggle;
    }
    return false;
  },
  wrongAddress() {
    if (Session.get('newCoin')) {
      const coin = getCoin(Session.get('newCoin').code);
      if (coin.type === 'ERC20') {
        if (document.getElementById('editBlockchainAddress') && document.getElementById('editBlockchainAddress').value === '') {
          Session.set('checkBlockchainAddress', false);
        }
        return _verifyBlockchainAddress();
      }
    }
    return false;
  },
  addressStyle() {
    if (Session.get('newCoin') && Session.get('newCoin').code === 'WEB VOTE') {
      return 'display: none;';
    }
    return '';
  },
  buttonDisable() {
    if (!_checkInputs()) {
      return 'button-disabled';
    }
    return '';
  },
  getImage(pic) {
    return getImage(Template.instance().imageTemplate.get(), pic);
  },
  showAdvanced() {
    return Template.instance().showAdvanced.get();
  },
  showReserves() {
    if (Meteor.user() && Meteor.user().profile.wallet.reserves) {
      return 'display:auto;';
    }
    return 'display:none;';
  },
});

Template.coin.events({
  'click #cancel-coin'() {
    animatePopup(false, 'blockchain-popup');
    Session.set('showCoinSettings', false);
  },
  'click #advanced'(event) {
    event.preventDefault();
    const advanced = Template.instance().showAdvanced.get();
    Template.instance().showAdvanced.set(!advanced);
  },
  'click #execute-coin'() {
    if (_checkInputs()) {
      _save();
      animatePopup(false, 'blockchain-popup');
      Session.set('showCoinSettings', false);
    }
  },
  'input #editBlockchainAddress'() {
    if (document.getElementById('editBlockchainAddress')) {
      const address = document.getElementById('editBlockchainAddress').value;
      Session.set('checkBlockchainAddress', web3.utils.isAddress(address));
    }
  },
  'input #editVotePrice'() {
    if (document.getElementById('editVotePrice')) {
      const price = document.getElementById('editVotePrice').value;
      if (price.toNumber() < 0) {
        document.getElementById('editVotePrice').value = '';
      }
    }
  },
  'input .token-search'(event) {
    if (event.target.value !== '') {
      Session.set('filteredCoins', searchJSON(token.coin, event.target.value));
    } else {
      Session.set('filteredCoins', token.coin);
      Session.set('newCoin', '');
    }
  },
  'focus .token-search'() {
    Session.set('suggestDisplay', 'TOKEN');
  },
});
<|endoftext|>