<commit_before>/* global $, config, mozRTCPeerConnection, RTCPeerConnection,
    webkitRTCPeerConnection, RTCSessionDescription */
/* jshint -W101 */
var RTC = require('../RTC/RTC');
var RTCBrowserType = require("../RTC/RTCBrowserType");
var RTCEvents = require("../../service/RTC/RTCEvents");
var SSRCReplacement = require("./LocalSSRCReplacement");

function TraceablePeerConnection(ice_config, constraints, session) {
    var self = this;
    var RTCPeerConnectionType = null;
    if (RTCBrowserType.isFirefox()) {
        RTCPeerConnectionType = mozRTCPeerConnection;
    } else if (RTCBrowserType.isTemasysPluginUsed()) {
        RTCPeerConnectionType = RTCPeerConnection;
    } else {
        RTCPeerConnectionType = webkitRTCPeerConnection;
    }
    self.eventEmitter = session.eventEmitter;
    this.peerconnection = new RTCPeerConnectionType(ice_config, constraints);
    this.updateLog = [];
    this.stats = {};
    this.statsinterval = null;
    this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable
    var Interop = require('sdp-interop').Interop;
    this.interop = new Interop();
    var Simulcast = require('sdp-simulcast');
    this.simulcast = new Simulcast({numOfLayers: 2, explodeRemoteSimulcast: false});

    // override as desired
    this.trace = function (what, info) {
        /*console.warn('WTRACE', what, info);
        if (info && RTCBrowserType.isIExplorer()) {
            if (info.length > 1024) {
                console.warn('WTRACE', what, info.substr(1024));
            }
            if (info.length > 2048) {
                console.warn('WTRACE', what, info.substr(2048));
            }
        }*/
        self.updateLog.push({
            time: new Date(),
            type: what,
            value: info || ""
        });
    };
    this.onicecandidate = null;
    this.peerconnection.onicecandidate = function (event) {
        // FIXME: this causes stack overflow with Temasys Plugin
        if (!RTCBrowserType.isTemasysPluginUsed())
            self.trace('onicecandidate', JSON.stringify(event.candidate, null, ' '));
        if (self.onicecandidate !== null) {
            self.onicecandidate(event);
        }
    };
    this.onaddstream = null;
    this.peerconnection.onaddstream = function (event) {
        self.trace('onaddstream', event.stream.id);
        if (self.onaddstream !== null) {
            self.onaddstream(event);
        }
    };
    this.onremovestream = null;
    this.peerconnection.onremovestream = function (event) {
        self.trace('onremovestream', event.stream.id);
        if (self.onremovestream !== null) {
            self.onremovestream(event);
        }
    };
    this.onsignalingstatechange = null;
    this.peerconnection.onsignalingstatechange = function (event) {
        self.trace('onsignalingstatechange', self.signalingState);
        if (self.onsignalingstatechange !== null) {
            self.onsignalingstatechange(event);
        }
    };
    this.oniceconnectionstatechange = null;
    this.peerconnection.oniceconnectionstatechange = function (event) {
        self.trace('oniceconnectionstatechange', self.iceConnectionState);
        if (self.oniceconnectionstatechange !== null) {
            self.oniceconnectionstatechange(event);
        }
    };
    this.onnegotiationneeded = null;
    this.peerconnection.onnegotiationneeded = function (event) {
        self.trace('onnegotiationneeded');
        if (self.onnegotiationneeded !== null) {
            self.onnegotiationneeded(event);
        }
    };
    self.ondatachannel = null;
    this.peerconnection.ondatachannel = function (event) {
        self.trace('ondatachannel', event);
        if (self.ondatachannel !== null) {
            self.ondatachannel(event);
        }
    };
    // XXX: do all non-firefox browsers which we support also support this?
    if (!RTCBrowserType.isFirefox() && this.maxstats) {
        this.statsinterval = window.setInterval(function() {
            self.peerconnection.getStats(function(stats) {
                var results = stats.result();
                var now = new Date();
                for (var i = 0; i < results.length; ++i) {
                    results[i].names().forEach(function (name) {
                        var id = results[i].id + '-' + name;
                        if (!self.stats[id]) {
                            self.stats[id] = {
                                startTime: now,
                                endTime: now,
                                values: [],
                                times: []
                            };
                        }
                        self.stats[id].values.push(results[i].stat(name));
                        self.stats[id].times.push(now.getTime());
                        if (self.stats[id].values.length > self.maxstats) {
                            self.stats[id].values.shift();
                            self.stats[id].times.shift();
                        }
                        self.stats[id].endTime = now;
                    });
                }
            });

        }, 1000);
    }
}

/**
 * Returns a string representation of a SessionDescription object.
 */
var dumpSDP = function(description) {
    if (typeof description === 'undefined' || description === null) {
        return '';
    }

    return 'type: ' + description.type + '\r\n' + description.sdp;
};

/**
 * Takes a SessionDescription object and returns a "normalized" version.
 * Currently it only takes care of ordering the a=ssrc lines.
 */
var normalizePlanB = function(desc) {
    if (typeof desc !== 'object' || desc === null ||
        typeof desc.sdp !== 'string') {
        console.warn('An empty description was passed as an argument.');
        return desc;
    }

    var transform = require('sdp-transform');
    var session = transform.parse(desc.sdp);

    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' &&
        Array.isArray(session.media)) {
        session.media.forEach(function (mLine) {

            // Chrome appears to be picky about the order in which a=ssrc lines
            // are listed in an m-line when rtx is enabled (and thus there are
            // a=ssrc-group lines with FID semantics). Specifically if we have
            // "a=ssrc-group:FID S1 S2" and the "a=ssrc:S2" lines appear before
            // the "a=ssrc:S1" lines, SRD fails.
            // So, put SSRC which appear as the first SSRC in an FID ssrc-group
            // first.
            var firstSsrcs = [];
            var newSsrcLines = [];

            if (typeof mLine.ssrcGroups !== 'undefined' && Array.isArray(mLine.ssrcGroups)) {
                mLine.ssrcGroups.forEach(function (group) {
                    if (typeof group.semantics !== 'undefined' &&
                        group.semantics === 'FID') {
                        if (typeof group.ssrcs !== 'undefined') {
                            firstSsrcs.push(Number(group.ssrcs.split(' ')[0]));
                        }
                    }
                });
            }

            if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {
                var i;
                for (i = 0; i<mLine.ssrcs.length; i++){
                    if (typeof mLine.ssrcs[i] === 'object'
                        && typeof mLine.ssrcs[i].id !== 'undefined'
                        && !$.inArray(mLine.ssrcs[i].id, firstSsrcs)) {
                        newSsrcLines.push(mLine.ssrcs[i]);
                        delete mLine.ssrcs[i];
                    }
                }

                for (i = 0; i<mLine.ssrcs.length; i++){
                    if (typeof mLine.ssrcs[i] !== 'undefined') {
                        newSsrcLines.push(mLine.ssrcs[i]);
                    }
                }

                mLine.ssrcs = newSsrcLines;
            }
        });
    }

    var resStr = transform.write(session);
    return new RTCSessionDescription({
        type: desc.type,
        sdp: resStr
    });
};

if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
    TraceablePeerConnection.prototype.__defineGetter__(
        'signalingState',
        function() { return this.peerconnection.signalingState; });
    TraceablePeerConnection.prototype.__defineGetter__(
        'iceConnectionState',
        function() { return this.peerconnection.iceConnectionState; });
    TraceablePeerConnection.prototype.__defineGetter__(
        'localDescription',
        function() {
            var desc = this.peerconnection.localDescription;

            // TODO this should be after the Unified Plan -> Plan B
            // transformation.
            desc = SSRCReplacement.mungeLocalVideoSSRC(desc);

            this.trace('getLocalDescription::preTransform', dumpSDP(desc));

            // if we're running on FF, transform to Plan B first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                desc = this.interop.toPlanB(desc);
                this.trace('getLocalDescription::postTransform (Plan B)', dumpSDP(desc));
            }
            return desc;
        });
    TraceablePeerConnection.prototype.__defineGetter__(
        'remoteDescription',
        function() {
            var desc = this.peerconnection.remoteDescription;
            this.trace('getRemoteDescription::preTransform', dumpSDP(desc));

            // if we're running on FF, transform to Plan B first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                desc = this.interop.toPlanB(desc);
                this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));
            }
            return desc;
        });
}

TraceablePeerConnection.prototype.addStream = function (stream) {
    this.trace('addStream', stream.id);
    try
    {
        this.peerconnection.addStream(stream);
    }
    catch (e)
    {
        console.error(e);
    }
};

TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
    this.trace('removeStream', stream.id);
    if(stopStreams) {
        RTC.stopMediaStream(stream);
    }

    try {
        // FF doesn't support this yet.
        if (this.peerconnection.removeStream)
            this.peerconnection.removeStream(stream);
    } catch (e) {
        console.error(e);
    }
};

TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
    this.trace('createDataChannel', label, opts);
    return this.peerconnection.createDataChannel(label, opts);
};

TraceablePeerConnection.prototype.setLocalDescription
        = function (description, successCallback, failureCallback) {
    this.trace('setLocalDescription::preTransform', dumpSDP(description));
    // if we're running on FF, transform to Plan A first.
    if (RTCBrowserType.usesUnifiedPlan()) {
        description = this.interop.toUnifiedPlan(description);
        this.trace('setLocalDescription::postTransform (Plan A)', dumpSDP(description));
    }

    var self = this;
    this.peerconnection.setLocalDescription(description,
        function () {
            self.trace('setLocalDescriptionOnSuccess');
            successCallback();
        },
        function (err) {
            self.trace('setLocalDescriptionOnFailure', err);
            self.eventEmitter.emit(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED, err, self.peerconnection);
            failureCallback(err);
        }
    );
    /*
     if (this.statsinterval === null && this.maxstats > 0) {
     // start gathering stats
     }
     */
};

TraceablePeerConnection.prototype.setRemoteDescription
        = function (description, successCallback, failureCallback) {
    this.trace('setRemoteDescription::preTransform', dumpSDP(description));
    // TODO the focus should squeze or explode the remote simulcast
    description = this.simulcast.mungeRemoteDescription(description);
    this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(description));

    // if we're running on FF, transform to Plan A first.
    if (RTCBrowserType.usesUnifiedPlan()) {
        description = this.interop.toUnifiedPlan(description);
        this.trace('setRemoteDescription::postTransform (Plan A)', dumpSDP(description));
    }

    if (RTCBrowserType.usesPlanB()) {
        description = normalizePlanB(description);
    }

    var self = this;
    this.peerconnection.setRemoteDescription(description,
        function () {
            self.trace('setRemoteDescriptionOnSuccess');
            successCallback();
        },
        function (err) {
            self.trace('setRemoteDescriptionOnFailure', err);
            self.eventEmitter.emit(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED, err, self.peerconnection);
            failureCallback(err);
        }
    );
    /*
     if (this.statsinterval === null && this.maxstats > 0) {
     // start gathering stats
     }
     */
};

TraceablePeerConnection.prototype.close = function () {
    this.trace('stop');
    if (this.statsinterval !== null) {
        window.clearInterval(this.statsinterval);
        this.statsinterval = null;
    }
    this.peerconnection.close();
};

TraceablePeerConnection.prototype.createOffer
        = function (successCallback, failureCallback, constraints) {
    var self = this;
    this.trace('createOffer', JSON.stringify(constraints, null, ' '));
    this.peerconnection.createOffer(
        function (offer) {
            self.trace('createOfferOnSuccess::preTransform', dumpSDP(offer));
            // NOTE this is not tested because in meet the focus generates the
            // offer.

            // if we're running on FF, transform to Plan B first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                offer = self.interop.toPlanB(offer);
                self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
            }

            offer = SSRCReplacement.mungeLocalVideoSSRC(offer);

            if (config.enableSimulcast && self.simulcast.isSupported()) {
                offer = self.simulcast.mungeLocalDescription(offer);
                self.trace('createOfferOnSuccess::postTransform (simulcast)', dumpSDP(offer));
            }
            successCallback(offer);
        },
        function(err) {
            self.trace('createOfferOnFailure', err);
            self.eventEmitter.emit(RTCEvents.CREATE_OFFER_FAILED, err, self.peerconnection);
            failureCallback(err);
        },
        constraints
    );
};

TraceablePeerConnection.prototype.createAnswer
        = function (successCallback, failureCallback, constraints) {
    var self = this;
    this.trace('createAnswer', JSON.stringify(constraints, null, ' '));
    this.peerconnection.createAnswer(
        function (answer) {
            self.trace('createAnswerOnSuccess::preTransform', dumpSDP(answer));
            // if we're running on FF, transform to Plan A first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                answer = self.interop.toPlanB(answer);
                self.trace('createAnswerOnSuccess::postTransform (Plan B)', dumpSDP(answer));
            }

            // munge local video SSRC
            answer = SSRCReplacement.mungeLocalVideoSSRC(answer);

            if (config.enableSimulcast && self.simulcast.isSupported()) {
                answer = self.simulcast.mungeLocalDescription(answer);
                self.trace('createAnswerOnSuccess::postTransform (simulcast)', dumpSDP(answer));
            }
            successCallback(answer);
        },
        function(err) {
            self.trace('createAnswerOnFailure', err);
            self.eventEmitter.emit(RTCEvents.CREATE_ANSWER_FAILED, err, self.peerconnection);
            failureCallback(err);
        },
        constraints
    );
};

TraceablePeerConnection.prototype.addIceCandidate
        = function (candidate, successCallback, failureCallback) {
    //var self = this;
    this.trace('addIceCandidate', JSON.stringify(candidate, null, ' '));
    this.peerconnection.addIceCandidate(candidate);
    /* maybe later
     this.peerconnection.addIceCandidate(candidate,
     function () {
     self.trace('addIceCandidateOnSuccess');
     successCallback();
     },
     function (err) {
     self.trace('addIceCandidateOnFailure', err);
     failureCallback(err);
     }
     );
     */
};

TraceablePeerConnection.prototype.getStats = function(callback, errback) {
    // TODO: Is this the correct way to handle Opera, Temasys?
    if (RTCBrowserType.isFirefox()) {
        // ignore for now...
        if(!errback)
            errback = function () {};
        this.peerconnection.getStats(null, callback, errback);
    } else {
        this.peerconnection.getStats(callback);
    }
};

module.exports = TraceablePeerConnection;
<commit_msg>Revert "Sets up simulcast for 2 layers."<commit_after>/* global $, config, mozRTCPeerConnection, RTCPeerConnection,
    webkitRTCPeerConnection, RTCSessionDescription */
/* jshint -W101 */
var RTC = require('../RTC/RTC');
var RTCBrowserType = require("../RTC/RTCBrowserType");
var RTCEvents = require("../../service/RTC/RTCEvents");
var SSRCReplacement = require("./LocalSSRCReplacement");

function TraceablePeerConnection(ice_config, constraints, session) {
    var self = this;
    var RTCPeerConnectionType = null;
    if (RTCBrowserType.isFirefox()) {
        RTCPeerConnectionType = mozRTCPeerConnection;
    } else if (RTCBrowserType.isTemasysPluginUsed()) {
        RTCPeerConnectionType = RTCPeerConnection;
    } else {
        RTCPeerConnectionType = webkitRTCPeerConnection;
    }
    self.eventEmitter = session.eventEmitter;
    this.peerconnection = new RTCPeerConnectionType(ice_config, constraints);
    this.updateLog = [];
    this.stats = {};
    this.statsinterval = null;
    this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable
    var Interop = require('sdp-interop').Interop;
    this.interop = new Interop();
    var Simulcast = require('sdp-simulcast');
    this.simulcast = new Simulcast({numOfLayers: 3, explodeRemoteSimulcast: false});

    // override as desired
    this.trace = function (what, info) {
        /*console.warn('WTRACE', what, info);
        if (info && RTCBrowserType.isIExplorer()) {
            if (info.length > 1024) {
                console.warn('WTRACE', what, info.substr(1024));
            }
            if (info.length > 2048) {
                console.warn('WTRACE', what, info.substr(2048));
            }
        }*/
        self.updateLog.push({
            time: new Date(),
            type: what,
            value: info || ""
        });
    };
    this.onicecandidate = null;
    this.peerconnection.onicecandidate = function (event) {
        // FIXME: this causes stack overflow with Temasys Plugin
        if (!RTCBrowserType.isTemasysPluginUsed())
            self.trace('onicecandidate', JSON.stringify(event.candidate, null, ' '));
        if (self.onicecandidate !== null) {
            self.onicecandidate(event);
        }
    };
    this.onaddstream = null;
    this.peerconnection.onaddstream = function (event) {
        self.trace('onaddstream', event.stream.id);
        if (self.onaddstream !== null) {
            self.onaddstream(event);
        }
    };
    this.onremovestream = null;
    this.peerconnection.onremovestream = function (event) {
        self.trace('onremovestream', event.stream.id);
        if (self.onremovestream !== null) {
            self.onremovestream(event);
        }
    };
    this.onsignalingstatechange = null;
    this.peerconnection.onsignalingstatechange = function (event) {
        self.trace('onsignalingstatechange', self.signalingState);
        if (self.onsignalingstatechange !== null) {
            self.onsignalingstatechange(event);
        }
    };
    this.oniceconnectionstatechange = null;
    this.peerconnection.oniceconnectionstatechange = function (event) {
        self.trace('oniceconnectionstatechange', self.iceConnectionState);
        if (self.oniceconnectionstatechange !== null) {
            self.oniceconnectionstatechange(event);
        }
    };
    this.onnegotiationneeded = null;
    this.peerconnection.onnegotiationneeded = function (event) {
        self.trace('onnegotiationneeded');
        if (self.onnegotiationneeded !== null) {
            self.onnegotiationneeded(event);
        }
    };
    self.ondatachannel = null;
    this.peerconnection.ondatachannel = function (event) {
        self.trace('ondatachannel', event);
        if (self.ondatachannel !== null) {
            self.ondatachannel(event);
        }
    };
    // XXX: do all non-firefox browsers which we support also support this?
    if (!RTCBrowserType.isFirefox() && this.maxstats) {
        this.statsinterval = window.setInterval(function() {
            self.peerconnection.getStats(function(stats) {
                var results = stats.result();
                var now = new Date();
                for (var i = 0; i < results.length; ++i) {
                    results[i].names().forEach(function (name) {
                        var id = results[i].id + '-' + name;
                        if (!self.stats[id]) {
                            self.stats[id] = {
                                startTime: now,
                                endTime: now,
                                values: [],
                                times: []
                            };
                        }
                        self.stats[id].values.push(results[i].stat(name));
                        self.stats[id].times.push(now.getTime());
                        if (self.stats[id].values.length > self.maxstats) {
                            self.stats[id].values.shift();
                            self.stats[id].times.shift();
                        }
                        self.stats[id].endTime = now;
                    });
                }
            });

        }, 1000);
    }
}

/**
 * Returns a string representation of a SessionDescription object.
 */
var dumpSDP = function(description) {
    if (typeof description === 'undefined' || description === null) {
        return '';
    }

    return 'type: ' + description.type + '\r\n' + description.sdp;
};

/**
 * Takes a SessionDescription object and returns a "normalized" version.
 * Currently it only takes care of ordering the a=ssrc lines.
 */
var normalizePlanB = function(desc) {
    if (typeof desc !== 'object' || desc === null ||
        typeof desc.sdp !== 'string') {
        console.warn('An empty description was passed as an argument.');
        return desc;
    }

    var transform = require('sdp-transform');
    var session = transform.parse(desc.sdp);

    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' &&
        Array.isArray(session.media)) {
        session.media.forEach(function (mLine) {

            // Chrome appears to be picky about the order in which a=ssrc lines
            // are listed in an m-line when rtx is enabled (and thus there are
            // a=ssrc-group lines with FID semantics). Specifically if we have
            // "a=ssrc-group:FID S1 S2" and the "a=ssrc:S2" lines appear before
            // the "a=ssrc:S1" lines, SRD fails.
            // So, put SSRC which appear as the first SSRC in an FID ssrc-group
            // first.
            var firstSsrcs = [];
            var newSsrcLines = [];

            if (typeof mLine.ssrcGroups !== 'undefined' && Array.isArray(mLine.ssrcGroups)) {
                mLine.ssrcGroups.forEach(function (group) {
                    if (typeof group.semantics !== 'undefined' &&
                        group.semantics === 'FID') {
                        if (typeof group.ssrcs !== 'undefined') {
                            firstSsrcs.push(Number(group.ssrcs.split(' ')[0]));
                        }
                    }
                });
            }

            if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {
                var i;
                for (i = 0; i<mLine.ssrcs.length; i++){
                    if (typeof mLine.ssrcs[i] === 'object'
                        && typeof mLine.ssrcs[i].id !== 'undefined'
                        && !$.inArray(mLine.ssrcs[i].id, firstSsrcs)) {
                        newSsrcLines.push(mLine.ssrcs[i]);
                        delete mLine.ssrcs[i];
                    }
                }

                for (i = 0; i<mLine.ssrcs.length; i++){
                    if (typeof mLine.ssrcs[i] !== 'undefined') {
                        newSsrcLines.push(mLine.ssrcs[i]);
                    }
                }

                mLine.ssrcs = newSsrcLines;
            }
        });
    }

    var resStr = transform.write(session);
    return new RTCSessionDescription({
        type: desc.type,
        sdp: resStr
    });
};

if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
    TraceablePeerConnection.prototype.__defineGetter__(
        'signalingState',
        function() { return this.peerconnection.signalingState; });
    TraceablePeerConnection.prototype.__defineGetter__(
        'iceConnectionState',
        function() { return this.peerconnection.iceConnectionState; });
    TraceablePeerConnection.prototype.__defineGetter__(
        'localDescription',
        function() {
            var desc = this.peerconnection.localDescription;

            desc = SSRCReplacement.mungeLocalVideoSSRC(desc);

            this.trace('getLocalDescription::preTransform', dumpSDP(desc));

            // if we're running on FF, transform to Plan B first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                desc = this.interop.toPlanB(desc);
                this.trace('getLocalDescription::postTransform (Plan B)', dumpSDP(desc));
            }
            return desc;
        });
    TraceablePeerConnection.prototype.__defineGetter__(
        'remoteDescription',
        function() {
            var desc = this.peerconnection.remoteDescription;
            this.trace('getRemoteDescription::preTransform', dumpSDP(desc));

            // if we're running on FF, transform to Plan B first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                desc = this.interop.toPlanB(desc);
                this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));
            }
            return desc;
        });
}

TraceablePeerConnection.prototype.addStream = function (stream) {
    this.trace('addStream', stream.id);
    try
    {
        this.peerconnection.addStream(stream);
    }
    catch (e)
    {
        console.error(e);
    }
};

TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
    this.trace('removeStream', stream.id);
    if(stopStreams) {
        RTC.stopMediaStream(stream);
    }

    try {
        // FF doesn't support this yet.
        if (this.peerconnection.removeStream)
            this.peerconnection.removeStream(stream);
    } catch (e) {
        console.error(e);
    }
};

TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
    this.trace('createDataChannel', label, opts);
    return this.peerconnection.createDataChannel(label, opts);
};

TraceablePeerConnection.prototype.setLocalDescription
        = function (description, successCallback, failureCallback) {
    this.trace('setLocalDescription::preTransform', dumpSDP(description));
    // if we're running on FF, transform to Plan A first.
    if (RTCBrowserType.usesUnifiedPlan()) {
        description = this.interop.toUnifiedPlan(description);
        this.trace('setLocalDescription::postTransform (Plan A)', dumpSDP(description));
    }

    var self = this;
    this.peerconnection.setLocalDescription(description,
        function () {
            self.trace('setLocalDescriptionOnSuccess');
            successCallback();
        },
        function (err) {
            self.trace('setLocalDescriptionOnFailure', err);
            self.eventEmitter.emit(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED, err, self.peerconnection);
            failureCallback(err);
        }
    );
    /*
     if (this.statsinterval === null && this.maxstats > 0) {
     // start gathering stats
     }
     */
};

TraceablePeerConnection.prototype.setRemoteDescription
        = function (description, successCallback, failureCallback) {
    this.trace('setRemoteDescription::preTransform', dumpSDP(description));
    // TODO the focus should squeze or explode the remote simulcast
    description = this.simulcast.mungeRemoteDescription(description);
    this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(description));

    // if we're running on FF, transform to Plan A first.
    if (RTCBrowserType.usesUnifiedPlan()) {
        description = this.interop.toUnifiedPlan(description);
        this.trace('setRemoteDescription::postTransform (Plan A)', dumpSDP(description));
    }

    if (RTCBrowserType.usesPlanB()) {
        description = normalizePlanB(description);
    }

    var self = this;
    this.peerconnection.setRemoteDescription(description,
        function () {
            self.trace('setRemoteDescriptionOnSuccess');
            successCallback();
        },
        function (err) {
            self.trace('setRemoteDescriptionOnFailure', err);
            self.eventEmitter.emit(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED, err, self.peerconnection);
            failureCallback(err);
        }
    );
    /*
     if (this.statsinterval === null && this.maxstats > 0) {
     // start gathering stats
     }
     */
};

TraceablePeerConnection.prototype.close = function () {
    this.trace('stop');
    if (this.statsinterval !== null) {
        window.clearInterval(this.statsinterval);
        this.statsinterval = null;
    }
    this.peerconnection.close();
};

TraceablePeerConnection.prototype.createOffer
        = function (successCallback, failureCallback, constraints) {
    var self = this;
    this.trace('createOffer', JSON.stringify(constraints, null, ' '));
    this.peerconnection.createOffer(
        function (offer) {
            self.trace('createOfferOnSuccess::preTransform', dumpSDP(offer));
            // NOTE this is not tested because in meet the focus generates the
            // offer.

            // if we're running on FF, transform to Plan B first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                offer = self.interop.toPlanB(offer);
                self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
            }

            offer = SSRCReplacement.mungeLocalVideoSSRC(offer);

            if (config.enableSimulcast && self.simulcast.isSupported()) {
                offer = self.simulcast.mungeLocalDescription(offer);
                self.trace('createOfferOnSuccess::postTransform (simulcast)', dumpSDP(offer));
            }
            successCallback(offer);
        },
        function(err) {
            self.trace('createOfferOnFailure', err);
            self.eventEmitter.emit(RTCEvents.CREATE_OFFER_FAILED, err, self.peerconnection);
            failureCallback(err);
        },
        constraints
    );
};

TraceablePeerConnection.prototype.createAnswer
        = function (successCallback, failureCallback, constraints) {
    var self = this;
    this.trace('createAnswer', JSON.stringify(constraints, null, ' '));
    this.peerconnection.createAnswer(
        function (answer) {
            self.trace('createAnswerOnSuccess::preTransform', dumpSDP(answer));
            // if we're running on FF, transform to Plan A first.
            if (RTCBrowserType.usesUnifiedPlan()) {
                answer = self.interop.toPlanB(answer);
                self.trace('createAnswerOnSuccess::postTransform (Plan B)', dumpSDP(answer));
            }

            // munge local video SSRC
            answer = SSRCReplacement.mungeLocalVideoSSRC(answer);

            if (config.enableSimulcast && self.simulcast.isSupported()) {
                answer = self.simulcast.mungeLocalDescription(answer);
                self.trace('createAnswerOnSuccess::postTransform (simulcast)', dumpSDP(answer));
            }
            successCallback(answer);
        },
        function(err) {
            self.trace('createAnswerOnFailure', err);
            self.eventEmitter.emit(RTCEvents.CREATE_ANSWER_FAILED, err, self.peerconnection);
            failureCallback(err);
        },
        constraints
    );
};

TraceablePeerConnection.prototype.addIceCandidate
        = function (candidate, successCallback, failureCallback) {
    //var self = this;
    this.trace('addIceCandidate', JSON.stringify(candidate, null, ' '));
    this.peerconnection.addIceCandidate(candidate);
    /* maybe later
     this.peerconnection.addIceCandidate(candidate,
     function () {
     self.trace('addIceCandidateOnSuccess');
     successCallback();
     },
     function (err) {
     self.trace('addIceCandidateOnFailure', err);
     failureCallback(err);
     }
     );
     */
};

TraceablePeerConnection.prototype.getStats = function(callback, errback) {
    // TODO: Is this the correct way to handle Opera, Temasys?
    if (RTCBrowserType.isFirefox()) {
        // ignore for now...
        if(!errback)
            errback = function () {};
        this.peerconnection.getStats(null, callback, errback);
    } else {
        this.peerconnection.getStats(callback);
    }
};

module.exports = TraceablePeerConnection;
<|endoftext|>


<commit_before>/**
 * Created by Cyril on 13-10-27.
 */
"use strict";
window.showBox = function showBox (message, action, showCb, closeCb ){
    var _x, _y;
    var dragable = false;
    var body = $('body').on('mouseleave', function(){
        if (dragable){
            template.removeAttr('style');
        }
        dragable = false;
    });
    var template =$('

×
' +
        '
'+message+'
' +
        '
' +
        '<button class="button close">取消</button>' +
        '<button class="button action">确定</button>' +
        '

')
        .appendTo(body)
        .find('.close').click(function(){
            template.removeClass('show');
            dropback.removeClass('show');
            window.setTimeout(function(){
                template.remove();
                dropback.remove();
                if (typeof closeCb === "function"){
                    closeCb();
                }
            },300);
        }).end().find('.action').click(function(){
            if (typeof action === 'function'){
                action();
            }
            template.removeClass('show');
            dropback.removeClass('show');
            window.setTimeout(function(){
                template.remove();
                dropback.remove();
                if (typeof closeCb === "function"){
                    closeCb();
                }
            },300);
        }).end()
        .find('.confirm_header').on('mousedown',function(e){
            dragable = true;
            _x=e.pageX-parseInt(template.css("left"));
            _y=e.pageY-parseInt(template.css("top"));
        })
        .on('mousemove', function(e){
            if(dragable){
                var x=e.pageX-_x,y=e.pageY-_y;
                template.css({top:y,left:x});
            }
        })
        .on('mouseup',function(){
            dragable = false;
        }).end();
    var dropback = $('
').appendTo(body).click(function(){
        $(this).removeClass('show');
        template.removeClass('show');
        window.setTimeout(function(){
            template.remove();
            $(this).remove();
            if (typeof closeCb === "function"){
                closeCb();
            }
        },300);
    });
    window.setTimeout(function(){
        template.addClass('show');
        if (typeof showCb === "function"){
            showCb();
        }
    },1); // hack for -webkit-transition
    $( window ).resize(function() {
        template.removeAttr('style');
        dragable = false;
    });
};

function updateTagsDom (elem){
    var _this = elem|| $("#newTag");
    $('' +
        ''+$(_this).val().trim()+'' +
        '×' +
        '\n\r').insertBefore($(_this))
        .on("click",function(){
            $(this).remove();
            updateTags();
        });
    $(_this).val(" ");
}

function showDialog(url,data,really){
    if(!really){
        return confirm(data.confirm)? window.location = url :false;
    }else{
        var newDiv=document.createElement("div");
        newDiv.className="confirm";
        newDiv.innerHTML='×' +
            '
'+data.confirm+'
' +
            '
' +
            '<button class="button close">取消</button>' +
            '确定' +
            '
';
        document.body.appendChild(newDiv);
        setTimeout(function(){
            newDiv.className+=" show";
        },1);
        $(".backdrops").addClass('show');
        return false;
    }
}

function initFlash () {
    $(".flash_error,.flash_success").addClass("show");

    window.setTimeout(function(){
        $(".flash_error,.flash_success").removeClass("show");
    },5000);
    updateTags();
    $("#tags-container").click(function(){
        $("#newTag").focus();
    });
}

function updateTags(){
    var tags=[];
    $(".tag_name").each(function(){
        tags.push($(this).text());
    });
    $("#post_tags").val(tags.join("|"));
}

function close_box(){
    $('div.confirm,.show_box,.backdrops').removeClass("show");
    setTimeout(function(){
        $("div.confirm,.show_box").remove();
    },300);
}

function toggleFullscreen($markdownContainer) {
    var element = $markdownContainer.get(0);
    if ($markdownContainer.hasClass('fullscreen')){
        console.log("Exit Fullscreen!");
        if(document.exitFullscreen) {
            document.exitFullscreen();
        } else if(document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if(document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        }
    }else{
        console.log('Goto Fullscreen!');
        if(element.requestFullscreen) {
            element.requestFullscreen();
        } else if(element.mozRequestFullScreen) {
            element.mozRequestFullScreen();
        } else if(element.webkitRequestFullscreen) {
            element.webkitRequestFullscreen();
        } else if(element.msRequestFullscreen) {
            element.msRequestFullscreen();
        }
    }
    $markdownContainer.off("mozfullscreenerror webkitfullscreenchange fullscreenchange");
    $markdownContainer.on("mozfullscreenerror webkitfullscreenchange fullscreenchange",function(event){
        console.debug(event);
        $markdownContainer.toggleClass('fullscreen', !$markdownContainer.hasClass("fullscreen"));
    });
}

function renderPreview(text){
    if(window.marked){
        window.marked.setOptions({
            gfm: true
        });
        window.marked(text, function (err, content) {
            if (err){
                console.debug(err);
            }
            $(".markdown_preview").html(content);
            highlight();
        });
    }
}

//    Highlight Code
//    Powered By Highlight.js
window.hljs.configure({useBR: false});
function highlight(){
    var code = $('.container pre code');
    Array.prototype.map.call(code, function(e){
        window.hljs.highlightBlock(e);
    });
}

function syncScroll(){
    var $text = $(".markdown_text");
    var $html = $(".markdown_html");
    $text.scroll(function(event) {
        var top = $text.scrollTop();
        var winHeight = $(window).height();
        var textHeight= $(".CodeMirror").height() + 120;
        var htmlHeight = $(".markdown_preview").height() + 120;
        var scrollTop = top * ( htmlHeight - winHeight ) / ( textHeight - winHeight );
        console.debug(top, winHeight, textHeight, htmlHeight, scrollTop);
        $html.scrollTop(scrollTop);
    });
}

$(document).ready(function(){
    var newTag = $('#newTag');
    window.submitPost = function(){
        if(!$('#post-title-input').val()){
            alert("Title Can't be Blank");
            return false;
        }
        var form=$("#post");
        if(newTag.val().trim()){
            updateTagsDom(newTag);
        }
        updateTags();
        form.submit();
        return false;
    };

    newTag.on( 'keypress', '.input_class', function (e) {
        if (13 === e.charCode) {
            return false;
        }
        return false;
    });
    newTag.on("keyup",function(e) {
    console.log(e);
        var _this = this;
        if(e.which === 32&&$(_this).val().trim()&& $(_this).val().split('').pop()===" "){
            updateTagsDom(_this);
            updateTags();
            return false;
        }else if(e.which === 8&&$('#newTag').val()===""){
            e.preventDefault();
            $(".tag-span").last().remove();
            $(_this).val(" ");
            updateTags();
        }
        e.preventDefault();
        return false;
    });

    $("a.confirm").click(function(){
        console.log(111);
        var url=this.getAttribute("href"),
            data = {
                confirm:this.getAttribute('data-confirm'),
                method: this.getAttribute('data-method')
            };
        console.log(data);
        showDialog(url,data,!!1);
        return false;
    });
    $(".tag-span").click(function(){
        $(this).remove();
        updateTags();
    });

    $('.backdrops').click(close_box);
    $(document).on("click",".confirm .close,.show_box .close",function(){
        close_box();
    });

    initFlash ();

    $(".header_navs .has_sub>a").on('touchstart',function(e){
        e.preventDefault();
        $(this).parent().toggleClass('open');
        return false;
    });
    $("header .toggle_sidebar").on("touchstart click",function(e){
        e.preventDefault();
        $('header').toggleClass("show");
        $('html').toggleClass('toggled');
    });
    $('body').on('click','main,.logo,.footer',function(){
        if($("html").hasClass('toggled')){
            $('header').removeClass('show');
            $('html').removeClass('toggled');
        }
    });

   // window.hljs.configure({useBR: true});
    highlight();

    // Call Full Screen
    $("#fullscreen").click(function(){
        toggleFullscreen($("#markdown-container"));
    });

    renderPreview($("#post_content").val());
    if(window.editor){
        console.debug("Has Editor");
        window.editor.on('change', function(event){
            renderPreview(event.doc.getValue());
        });
    }
    syncScroll();
});
<commit_msg>[feature/markdown] fix showbox function<commit_after>/**
 * Created by Cyril on 13-10-27.
 */
"use strict";
function showBox (option){
    var _x, _y;
    var dragable = false;
    var body = $('body').on('mouseleave', function(){
        if (dragable){
            template.removeAttr('style');
        }
        dragable = false;
    });
    function closeBox(){
        template.removeClass('show');
        dropback.removeClass('show');
        window.setTimeout(function(){
            template.remove();
            dropback.remove();
            template.trigger("close");
        },300);
    }
    var template =$('

×
' +
        '
'+option.template+'
' +
        '
' +
        '<button class="button action">确定</button>' +
        '<button class="button close">取消</button>' +
        '

')
        .appendTo(body)
        .find('.close').click(closeBox).end().find('.action').click(function(){
            template.trigger('confirm');
            closeBox();
        }).end()
        .find('.box-header').on('mousedown',function(e){
            dragable = true;
            _x=e.pageX-parseInt(template.css("left"));
            _y=e.pageY-parseInt(template.css("top"));
        })
        .on('mousemove', function(e){
            if(dragable){
                var x=e.clientX-_x,y=e.clientY-_y;
                template.css({top:y,left:x});
            }
        })
        .on('mouseup',function(){
            dragable = false;
        }).end();
    var dropback = $('
').appendTo(body).click(function(){
        closeBox();
    });
    window.setTimeout(function(){
        template.addClass('show');
        template.trigger('show');
    },1); // hack for -webkit-transition
    $( window ).resize(function() {
        template.removeAttr('style');
        dragable = false;
    });
    return template;
}

function updateTagsDom (elem){
    var _this = elem|| $("#newTag");
    $('' +
        ''+$(_this).val().trim()+'' +
        '×' +
        '\n\r').insertBefore($(_this))
        .on("click",function(){
            $(this).remove();
            updateTags();
        });
    $(_this).val(" ");
}

function initFlash () {
    $(".flash_error,.flash_success").addClass("show");

    window.setTimeout(function(){
        $(".flash_error,.flash_success").removeClass("show");
    },5000);
    updateTags();
    $("#tags-container").click(function(){
        $("#newTag").focus();
    });
}

function updateTags(){
    var tags=[];
    $(".tag_name").each(function(){
        tags.push($(this).text());
    });
    $("#post_tags").val(tags.join("|"));
}

function close_box(){
    $('.show-box,.backdrops').removeClass("show");
    setTimeout(function(){
        $(".show-box").remove();
    },300);
}

function toggleFullscreen($markdownContainer) {
    var element = $markdownContainer.get(0);
    if ($markdownContainer.hasClass('fullscreen')){
        console.log("Exit Fullscreen!");
        if(document.exitFullscreen) {
            document.exitFullscreen();
        } else if(document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if(document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        }
    }else{
        console.log('Goto Fullscreen!');
        if(element.requestFullscreen) {
            element.requestFullscreen();
        } else if(element.mozRequestFullScreen) {
            element.mozRequestFullScreen();
        } else if(element.webkitRequestFullscreen) {
            element.webkitRequestFullscreen();
        } else if(element.msRequestFullscreen) {
            element.msRequestFullscreen();
        }
    }
    $markdownContainer.off("mozfullscreenerror webkitfullscreenchange fullscreenchange");
    $markdownContainer.on("mozfullscreenerror webkitfullscreenchange fullscreenchange",function(event){
        console.debug(event);
        $markdownContainer.toggleClass('fullscreen', !$markdownContainer.hasClass("fullscreen"));
    });
}

function renderPreview(text){
    if(window.marked){
        window.marked.setOptions({
            gfm: true
        });
        window.marked(text, function (err, content) {
            if (err){
                console.debug(err);
            }
            $(".markdown_preview").html(content);
            highlight();
        });
    }
}

//    Highlight Code
//    Powered By Highlight.js
window.hljs.configure({useBR: false});
function highlight(){
    var code = $('.container pre code');
    Array.prototype.map.call(code, function(e){
        window.hljs.highlightBlock(e);
    });
}

function syncScroll(){
    var $text = $(".markdown_text");
    var $html = $(".markdown_html");
    $text.scroll(function() {
        var top = $text.scrollTop();
        var winHeight = $(window).height();
        var textHeight= $(".CodeMirror").height() + 120;
        var htmlHeight = $(".markdown_preview").height() + 120;
        var scrollTop = top * ( htmlHeight - winHeight ) / ( textHeight - winHeight );
        console.debug(top, winHeight, textHeight, htmlHeight, scrollTop);
        $html.scrollTop(scrollTop);
    });
}

$(document).ready(function(){
    var newTag = $('#newTag');
    window.submitPost = function(){
        if(!$('#post-title-input').val()){
            alert("Title Can't be Blank");
            return false;
        }
        var form=$("#post");
        if(newTag.val().trim()){
            updateTagsDom(newTag);
        }
        updateTags();
        form.submit();
        return false;
    };

    newTag.on( 'keypress', '.input_class', function (e) {
        if (13 === e.charCode) {
            return false;
        }
        return false;
    });
    newTag.on("keyup",function(e) {
    console.log(e);
        var _this = this;
        if(e.which === 32&&$(_this).val().trim()&& $(_this).val().split('').pop()===" "){
            updateTagsDom(_this);
            updateTags();
            return false;
        }else if(e.which === 8&&$('#newTag').val()===""){
            e.preventDefault();
            $(".tag-span").last().remove();
            $(_this).val(" ");
            updateTags();
        }
        e.preventDefault();
        return false;
    });

    $("a.confirm").click(function(){
        console.log(111);
        var url=this.getAttribute("href"),
            data = {
                confirm:this.getAttribute('data-confirm'),
                method: this.getAttribute('data-method')
            };
        console.log(data);
        showBox(url,data,!!1);
        return false;
    });
    $(".tag-span").click(function(){
        $(this).remove();
        updateTags();
    });

    $('.backdrops').click(close_box);

    initFlash ();

    $(".header_navs .has_sub>a").on('touchstart',function(e){
        e.preventDefault();
        $(this).parent().toggleClass('open');
        return false;
    });
    $("header .toggle_sidebar").on("touchstart click",function(e){
        e.preventDefault();
        $('header').toggleClass("show");
        $('html').toggleClass('toggled');
    });
    $('body').on('click','main,.logo,.footer',function(){
        if($("html").hasClass('toggled')){
            $('header').removeClass('show');
            $('html').removeClass('toggled');
        }
    });

   // window.hljs.configure({useBR: true});
    highlight();

    // Call Full Screen
    $("#fullscreen").click(function(){
        toggleFullscreen($("#markdown-container"));
    });

    renderPreview($("#post_content").val());
    if(window.editor){
        console.debug("Has Editor");
        window.editor.on('change', function(event){
            renderPreview(event.doc.getValue());
        });
    }
    syncScroll();
});
<|endoftext|>


<commit_before>import BaseListener from './base-listener';
import ErrorDescriptor from '../error-descriptor';

export default BaseListener.extend({

    listen(manager) {

        // window listener
        window.onerror = (message, file, line, column, error) => {
            if (!error) {
                error = {
                    message: message,
                    name: String(error),
                    stack: message + ' at ' + "\n" + file + ':' + line + ':' + column
                };
            }

            manager.consume(
                ErrorDescriptor.create({
                    source: 'window',
                    listener: this,
                    error
                })
            );
            return true;
        };

        // unhandled promise listener
        window.addEventListener('unhandledrejection', function (event) {
            let error = event.reason;
            if (!error) {
                error = {
                    message: message,
                    name: String(error),
                    stack: ''
                };
            }
            manager.consume(
                ErrorDescriptor.create({
                    source: 'window',
                    listener: this,
                    error
                })
            );
        });
    }
});

<commit_msg>Remove native logging for unhandledrejection<commit_after>import BaseListener from './base-listener';
import ErrorDescriptor from '../error-descriptor';

export default BaseListener.extend({

    listen(manager) {

        // window listener
        window.onerror = (message, file, line, column, error) => {
            if (!error) {
                error = {
                    message: message,
                    name: String(error),
                    stack: message + ' at ' + "\n" + file + ':' + line + ':' + column
                };
            }

            manager.consume(
                ErrorDescriptor.create({
                    source: 'window',
                    listener: this,
                    error
                })
            );
            return true;
        };

        // unhandled promise listener
        window.addEventListener('unhandledrejection', function (event) {
            let error = event.reason;
            if (!error) {
                error = {
                    message: message,
                    name: String(error),
                    stack: ''
                };
            }
            manager.consume(
                ErrorDescriptor.create({
                    source: 'window',
                    listener: this,
                    error
                })
            );

            event.preventDefault();
        });
    }
});

<|endoftext|>


<commit_before>var express = require('express')
var router = express.Router()
var orgService = require('../service/orgService')
var logSercice = require('../service/logService')

// 获取组织机构
router.get('/getOrgs', function (req, res, next) {
  let opts = req.query
  orgService.getOrgs(opts, result => {
    res.json(result)
  })
})
// 添加组织机构
router.post('/addOrg', function (req, res, next) {
  let opts = req.body
  orgService.addOrg(opts, result => {
    logSercice.log(req.userId, 'addOrg', result.status === false ? result.message : '')
    res.json(result)
  })
})
// 更新组织机构
router.post('/editOrg', function (req, res, next) {
  let opts = req.body
  orgService.editOrg(opts, result => {
    logSercice.log(req.userId, 'editOrg', result.status === false ? result.message : '')
    res.json(result)
  })
})

module.exports = router<commit_msg>修改：获取、添加、更新组织机构增加管理员权限验证中间件<commit_after>var express = require('express')
var router = express.Router()
var orgService = require('../service/orgService')
var logSercice = require('../service/logService')
var checkAdmin = require('../bin/middleware/checkAdmin')

// 获取组织机构
router.get('/getOrgs', checkAdmin, function (req, res, next) {
  let opts = req.query
  orgService.getOrgs(opts, result => {
    res.json(result)
  })
})
// 添加组织机构
router.post('/addOrg', checkAdmin, function (req, res, next) {
  let opts = req.body
  orgService.addOrg(opts, result => {
    logSercice.log(req.userId, 'addOrg', result.status === false ? result.message : `orgName:${opts.orgname}`)
    res.json(result)
  })
})
// 更新组织机构
router.post('/editOrg', checkAdmin, function (req, res, next) {
  let opts = req.body
  orgService.editOrg(opts, result => {
    logSercice.log(req.userId, 'editOrg', result.status === false ? result.message : `orgName:${opts.orgname}`)
    res.json(result)
  })
})

module.exports = router<|endoftext|>


<commit_before>const html = require('yo-yo')
const cuid = require('cuid')

module.exports = (props) => {
  // const classes = props.active ? 'BrowserTable-row is-active' : 'BrowserTable-row'
  const uniqueId = cuid()

  return html`

          <input type="checkbox"
                 role="option"
                 tabindex="0"
                 id=${uniqueId}
                 checked=${props.isChecked}
                 disabled=${props.isDisabled}
                 onchange=${props.handleCheckboxClick} />

        <button class="BrowserTable-item" tabindex="0" onclick=${props.handleClick}>${props.getItemIcon()} ${props.title}</button>

  `
}
<commit_msg>add `type="button"` to button, important not to submit forms<commit_after>const html = require('yo-yo')
const cuid = require('cuid')

module.exports = (props) => {
  // const classes = props.active ? 'BrowserTable-row is-active' : 'BrowserTable-row'
  const uniqueId = cuid()

  return html`

          <input type="checkbox"
                 role="option"
                 tabindex="0"
                 aria-label="Select file: ${props.title}"
                 id=${uniqueId}
                 checked=${props.isChecked}
                 disabled=${props.isDisabled}
                 onchange=${props.handleCheckboxClick} />

        <button type="button" class="BrowserTable-item" aria-label="Select file: ${props.title}" tabindex="0" onclick=${props.handleClick}>
          ${props.getItemIcon()} ${props.title}
        </button>

  `
}
<|endoftext|>


<commit_before>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    markings: [],
    graphlabels: [],
    ranges: {},

    setRange: function(range) {
        this.ranges = range;
    },
    plot: function() {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (this.ranges.xaxis != undefined) {
            min = this.ranges.xaxis.from;
            max = this.ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (dataset in this.datasets) {

                series = this.datasets[dataset]['data']

                for (k in series) {
                    if (min >= series[k][0]) {
                        minIndex = k;
                    }
                    if (max <= series[k][0]) {
                        maxIndex = k;
                        break;
                    }
                }
                break;
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key]) {
                if (key == 'hr') {
                    //that.datasets[key]['constraints'] = that.hrconstraints;
                    //
                  that.datasets[key]['threshold']= that.newhrconstraints;
                }
                else if (key == 'altitude') {
                    //that.datasets[key]['constraints'] = segmentconstraints;

                }

                if (key != 'lon' && key != 'lat') { // lon and lat doesn't go in the graph
                    data.push(that.datasets[key]);
                }
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#exercisegraph"), data, {
                series: {
                    lines: {
                        lineWidth: 2, // less cluttere
                    },
                    shadowSize: 3 //drawing is faster without shadoes
                },
                yaxes: [
                    { tickFormatter: axisformatters['speed'] },
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: axisformatters['hr'] },
                    { position: "right", tickFormatter: axisformatters['power']},
                    { tickFormatter: axisformatters['altitude']} ,
                    { tickFormatter: axisformatters['temp']},
                    { tickFormatter: axisformatters['cadence']}
                    ],
                xaxis: xaxisattrs,
                legend: {
                    labelFormatter: function(label, series) {
                        // series is the series object for the label
                        return label;
                    },
                    position: 'se',
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    backgroundColor: { colors: ["#fff", "#eee"] },
                    markings: this.markings,
                    markingsLineWidth: 1,
                },
                crosshair: { mode: "x" },
                selection: { mode: "x" }
            });
        }

        this.drawGraphText();

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);

            var segment_link = $("#segment_add");
            segment_link.attr('href' , segment_link.attr('href')+ '&start=' + minIndex + '&stop=' + maxIndex);
            $("#segment_add").removeClass("hidden");

            //window.location.hash = 'graph-zoom-' + Math.round(min*10)/10 + '-' + Math.round(max*10)/10;
            window.location.hash = 'graph-zoom-' + min + '-' + max;

            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = avgs[key];
                            if (val) {
                                if (typeof(val) == 'number') {
                                    val = Math.round(val * 10) / 10;
                                }
                                e.text(val);
                                e.parents(".hidden").removeClass("hidden");
                                e.attr('title', key.replace(/_/g, ' '))
                                e.parents('li').attr('title', key.replace(/_/g, ' '))
                            }
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

    },
    updateLegend: function(pos) {
        this.updateLegendTimeout = null;
       // var pos = this.latestPosition;
        var axes = plot.getAxes();
        if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
            pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
            return;

        var i, j, dataset = plot.getData();
        for (i = 0; i < dataset.length; ++i) {
            var series = dataset[i];

            // find the nearest points, x-wise
            for (j = 0; j < series.data.length; ++j)
                if (series.data[j]) {
                    if (series.data[j][0] > pos.x)
                        break;
                }

            // now interpolate
            var y, p1 = series.data[j - 1], p2 = series.data[j];

            if (p1 == null)
                y = p2[1];
            else if (p2 == null)
                y = p1[1];
            else
                y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

            this.legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
        }
    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            padding: '10px',
            opacity: 0.9
        }).appendTo("body").delay(200).fadeIn(200);
    },
    addGraphText: function(x, text) {
        this.graphlabels.push([x,text] );
    },
    drawGraphText: function() {
        var ymax = plot.getAxes().yaxis.max;
        for (key in this.graphlabels) {
            var o= plot.pointOffset({ x: this.graphlabels[key][0], y: ymax});
            var placeholder = plot.getPlaceholder()
            placeholder.append('
' + this.graphlabels[key][1] + '
');
        }
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = axisformatters[args.xaxisformatter];
        this.posFeature = null;
        this.fullscreen = false;
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.hrconstraints = [{
                threshold: this.max_hr*0.6,
                color: colors[0],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.72,
                color: colors[1],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.82,
                color: colors[2],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.87,
                color: colors[3],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.92,
                color: colors[4],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.97,
                color: colors[5],
                evaluate : evaluate
        }]

        this.newhrconstraints = [{
                below: this.max_hr*0.6,
                color: colors[0]
            },
            {
                below: this.max_hr*0.72,
                color: colors[1]
            },
            {
                below: this.max_hr*0.82,
                color: colors[2]
            },
            {
                below: this.max_hr*0.87,
                color: colors[3]
            },
            {
                below: this.max_hr*0.92,
                color: colors[4]
            },
            {
                below: this.max_hr*0.97,
                color: colors[5]
        }]

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            var checked = "checked = checked";
            if (key == 'cadence')
                checked = ''
            if (key == 'temp')
                checked = ''
            if (key == 'power')
                checked = ''

            if (key != 'lon' && key != 'lat') {

                that.choiceContainer.append('<input type="checkbox" name="' + key +
                    '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
            }
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            that.setRange({});
            that.plot();
        });
        $(window).bind("keyup", function(evt) { if (evt.keyCode == 70) { $('#enlarge').click() } });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            // Press escape to leave fullscreen
            $(window).bind("keyup", function(evt) { if (evt.keyCode == 27) { $('#enlarge').click() } });
            if(!that.fullscreen) {
                //$("#scrollhack").css("overflow", "scroll");
                //$("#exercisegraph").width( $("#exercisegraph").width()*4);
                $("#exercisegraph").appendTo('body');
                $("#exercisegraph").css("position", "absolute"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").addClass('exercisegraphoverlay');
                $("#exercisegraph").removeClass('exercisegraph');
                $("#exercisegraph").css("overflow", "hidden");

                $("#averages").addClass('extraoverlay');
                $("#averages").appendTo('body');
                that.fullscreen = true;
            }
            else {
                $("#exercisegraph").removeClass('exercisegraphoverlay');
                $("#exercisegraph").addClass('exercisegraph');
                $("#exercisegraph").css("position", "relative"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").appendTo($('#graphcontainer'));

                $("#averages").removeClass('extraoverlay');
                $("#averages").appendTo($('#graphcontainer'));
                that.fullscreen = false;
            }
        /* resize.js plugin does this
            plot.resize();
            plot.setupGrid();
            plot.draw();
        */
        });
        //$("#segment_add").bind("click", function(evt) {
        //});
        this.choiceContainer.find("input").bind("change", function(evt) {
                that.plot();
        });
        $('.legendColorBox > div').each(function(i){
            $(this).clone().prependTo(that.choiceContainer.find("li").eq(i));
        });

        this.legends = $(".legendLabel");
        this.legends.each(function () {
            // fix the widths so they don't jump around
            $(this).css('width', $(this).width());
        });

        var previousPoint = null;
        this.updateLegendTimeout = null;
        this.latestPosition = null;
        $("#exercisegraph").bind("plothover", function (event, pos, item) {
            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
            //that.updateLegend(pos);

            $("#gtooltip").remove();
            var axes = plot.getAxes();
            // Just retrn if we're hovering around outside the graph area
            if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
                return;

            var posIndex = 0;
            for (serieskey in that.datasets) { // Find first and best series that we got
                var series = that.datasets[serieskey]['data'];
                for (key in series) {
                    if (series[key][0] >= pos.x) {
                        var posIndex = key;
                        break;
                    }
                }
                break;
            }
            if (posIndex <= 0)  // No index found
                return;

            // Move marker to current pos
            if (Mapper.map != null || Mapper.posLayer != undefined) {
                var route_lon = that.datasets['lon'];
                var route_lat = that.datasets['lat'];
                if (route_lon.length >= posIndex) {
                    var x = route_lon[posIndex];
                    var y = route_lat[posIndex];
                    if (!this.posFeature) {
                        this.posFeature = Mapper.createFeature(Mapper.posLayer, x, y, 0);
                    }
                    // Mapper.updatePosMarker(x, y);
                    Mapper.moveFeature(this.posFeature, x, y, 0); // Hardcoded to 0 degrees
                }
            }

            var x = pos.x;
            var highlightedseries = null;
            if (item)
                highlightedseries = item.series.label;

            var tooltipHtml = '
'+ that.xaxisformatter(x, plot.getAxes().xaxis) + '

';
            for (skey in that.datasets) {
                if (skey == 'lon' || skey == 'lat')
                    continue;
                var series = that.datasets[skey];
                var label = series['label'];
                var tickFormatter = axisformatters[skey];
                if (skey == 'poweravg30s')
                    tickFormatter = axisformatters['power'];
                var val = series['data'][posIndex][1]; // Must fetch this from datasets rather thatn the graph data itself because of multiple treshold splits up the indexes
                if(tickFormatter != undefined)
                    val = tickFormatter(val, plot.getAxes().xaxis);
                var color = plot.getOptions().colors[series['color']];
                if(label == highlightedseries) // Highlight if item selected
                    skey += ' selected'
                tooltipHtml += '
' + label + ': ' + val + '
';
            }
            tooltipHtml += '
';
            that.showTooltip(pos.pageX, pos.pageY, tooltipHtml);

        });
        $("#exercisegraph").bind("plotclick", function (event, pos, item) {
            if (item) {
                plot.highlight(item.series, item.datapoint);
            }
            // reset zoom on click
            that.setRange({});
            that.plot();
        });

        $("#exercisegraph").bind("plotselected", function (event, ranges) {
            that.setRange(ranges);
            that.plot();
        });
    }
};

<commit_msg>draw text last<commit_after>/**
 * Class for handeling graph plotting of pulse data.
 * Still needs loads of work and is only a cut/paste from template for now
 */
var plot;
var GraphPlotter = {
    choiceContainer: null,
    datasets: null,
    backendUrl: null,
    max_hr: 200,
    markings: [],
    graphlabels: [],
    ranges: {},

    setRange: function(range) {
        this.ranges = range;
    },
    plot: function() {
        data = [];
        var that = this;
        var minIndex = null;
        var maxIndex = null;
        var min = null;
        var max = null;
        var xaxisattrs = {
            tickDecimals: 0,
            tickFormatter: this.xaxisformatter
        };
        if (this.ranges.xaxis != undefined) {
            min = this.ranges.xaxis.from;
            max = this.ranges.xaxis.to;
            xaxisattrs.min = min;
            xaxisattrs.max = max;

            for (dataset in this.datasets) {

                series = this.datasets[dataset]['data']

                for (k in series) {
                    if (min >= series[k][0]) {
                        minIndex = k;
                    }
                    if (max <= series[k][0]) {
                        maxIndex = k;
                        break;
                    }
                }
                break;
            }
        }
        $("#choices").find("input:checked").each(function () {
            var key = $(this).attr("name");
            if (key && that.datasets[key]) {
                if (key == 'hr') {
                    //that.datasets[key]['constraints'] = that.hrconstraints;
                    //
                  that.datasets[key]['threshold']= that.newhrconstraints;
                }
                else if (key == 'altitude') {
                    //that.datasets[key]['constraints'] = segmentconstraints;

                }

                if (key != 'lon' && key != 'lat') { // lon and lat doesn't go in the graph
                    data.push(that.datasets[key]);
                }
            }
        });

        if (data.length > 0) {
            plot = $.plot($("#exercisegraph"), data, {
                series: {
                    lines: {
                        lineWidth: 2, // less cluttere
                    },
                    shadowSize: 3 //drawing is faster without shadoes
                },
                yaxes: [
                    { tickFormatter: axisformatters['speed'] },
                    { position: "right", min: 80, max: this.max_hr, tickFormatter: axisformatters['hr'] },
                    { position: "right", tickFormatter: axisformatters['power']},
                    { tickFormatter: axisformatters['altitude']} ,
                    { tickFormatter: axisformatters['temp']},
                    { tickFormatter: axisformatters['cadence']}
                    ],
                xaxis: xaxisattrs,
                legend: {
                    labelFormatter: function(label, series) {
                        // series is the series object for the label
                        return label;
                    },
                    position: 'se',
                    noColumns: 15
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    backgroundColor: { colors: ["#fff", "#eee"] },
                    markings: this.markings,
                    markingsLineWidth: 1,
                },
                crosshair: { mode: "x" },
                selection: { mode: "x" }
            });
        }

        if (minIndex != null && maxIndex != null) {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(minIndex, maxIndex);

            var segment_link = $("#segment_add");
            segment_link.attr('href' , segment_link.attr('href')+ '&start=' + minIndex + '&stop=' + maxIndex);
            $("#segment_add").removeClass("hidden");

            //window.location.hash = 'graph-zoom-' + Math.round(min*10)/10 + '-' + Math.round(max*10)/10;
            window.location.hash = 'graph-zoom-' + min + '-' + max;

            $.getJSON(this.backendUrl, { start: minIndex, stop: maxIndex }, function (avgs) {
                var items = $("#averages ul .data");
                $("#averages h4").removeClass("hidden");

                $.each(items, function (i, elem) {
                    var classlist = elem.className.split(" ");
                    for (k in classlist) {
                        if (classlist[k] in avgs) {
                            var key = classlist[k];
                            var e = $(elem);
                            var val = avgs[key];
                            if (val) {
                                if (typeof(val) == 'number') {
                                    val = Math.round(val * 10) / 10;
                                }
                                e.text(val);
                                e.parents(".hidden").removeClass("hidden");
                                e.attr('title', key.replace(/_/g, ' '))
                                e.parents('li').attr('title', key.replace(/_/g, ' '))
                            }
                        }
                    }
                });
            });
        }
        else {
            if (typeof(Mapper) != "undefined")
                Mapper.loadGeoJSON(0, 0);
            $("#averages ul li").addClass("hidden");
            $("#averages h4").addClass("hidden");
        }

        this.drawGraphText();
    },
    updateLegend: function(pos) {
        this.updateLegendTimeout = null;
       // var pos = this.latestPosition;
        var axes = plot.getAxes();
        if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
            pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
            return;

        var i, j, dataset = plot.getData();
        for (i = 0; i < dataset.length; ++i) {
            var series = dataset[i];

            // find the nearest points, x-wise
            for (j = 0; j < series.data.length; ++j)
                if (series.data[j]) {
                    if (series.data[j][0] > pos.x)
                        break;
                }

            // now interpolate
            var y, p1 = series.data[j - 1], p2 = series.data[j];

            if (p1 == null)
                y = p2[1];
            else if (p2 == null)
                y = p1[1];
            else
                y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);

            this.legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
        }
    },
    showTooltip: function (x, y, contents) {
        $('
' + contents + '
').css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            padding: '10px',
            opacity: 0.9
        }).appendTo("body").delay(200).fadeIn(200);
    },
    addGraphText: function(x, text) {
        this.graphlabels.push([x,text] );
    },
    drawGraphText: function() {
        var ymax = plot.getAxes().yaxis.max;
        for (key in this.graphlabels) {
            var o= plot.pointOffset({ x: this.graphlabels[key][0], y: ymax});
            var placeholder = plot.getPlaceholder()
            placeholder.append('
' + this.graphlabels[key][1] + '
');
        }
    },
    init: function(args) {
        this.datasets = args.datasets;
        var backendUrl = args.backendUrl;
        this.max_hr = args.max_hr;
        this.markings = args.markings;
        this.xaxisformatter = axisformatters[args.xaxisformatter];
        this.posFeature = null;
        this.fullscreen = false;
        function evaluate(y,threshold) {
            return y < threshold;
        }
        this.hrconstraints = [{
                threshold: this.max_hr*0.6,
                color: colors[0],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.72,
                color: colors[1],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.82,
                color: colors[2],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.87,
                color: colors[3],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.92,
                color: colors[4],
                evaluate : evaluate
            },
            {
                threshold: this.max_hr*0.97,
                color: colors[5],
                evaluate : evaluate
        }]

        this.newhrconstraints = [{
                below: this.max_hr*0.6,
                color: colors[0]
            },
            {
                below: this.max_hr*0.72,
                color: colors[1]
            },
            {
                below: this.max_hr*0.82,
                color: colors[2]
            },
            {
                below: this.max_hr*0.87,
                color: colors[3]
            },
            {
                below: this.max_hr*0.92,
                color: colors[4]
            },
            {
                below: this.max_hr*0.97,
                color: colors[5]
        }]

        var that = this;
        this.backendUrl = backendUrl;
        this.choiceContainer = $("#choices");

        $.each(this.datasets, function(key, val) {
            var checked = "checked = checked";
            if (key == 'cadence')
                checked = ''
            if (key == 'temp')
                checked = ''
            if (key == 'power')
                checked = ''

            if (key != 'lon' && key != 'lat') {

                that.choiceContainer.append('<input type="checkbox" name="' + key +
                    '" ' + checked + ' id="chk_' + key + '">' + val.label + '</input>');
            }
        });
        $("#reset_zoom").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            that.setRange({});
            that.plot();
        });
        $(window).bind("keyup", function(evt) { if (evt.keyCode == 70) { $('#enlarge').click() } });
        $("#enlarge").bind("click", function(evt) {
            evt.preventDefault();
            $("#gtooltip").remove(); // tooltips messes up pos
            // Press escape to leave fullscreen
            $(window).bind("keyup", function(evt) { if (evt.keyCode == 27) { $('#enlarge').click() } });
            if(!that.fullscreen) {
                //$("#scrollhack").css("overflow", "scroll");
                //$("#exercisegraph").width( $("#exercisegraph").width()*4);
                $("#exercisegraph").appendTo('body');
                $("#exercisegraph").css("position", "absolute"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").addClass('exercisegraphoverlay');
                $("#exercisegraph").removeClass('exercisegraph');
                $("#exercisegraph").css("overflow", "hidden");

                $("#averages").addClass('extraoverlay');
                $("#averages").appendTo('body');
                that.fullscreen = true;
            }
            else {
                $("#exercisegraph").removeClass('exercisegraphoverlay');
                $("#exercisegraph").addClass('exercisegraph');
                $("#exercisegraph").css("position", "relative"); // Somehow needed, even though it's set in the css
                $("#exercisegraph").appendTo($('#graphcontainer'));

                $("#averages").removeClass('extraoverlay');
                $("#averages").appendTo($('#graphcontainer'));
                that.fullscreen = false;
            }
        /* resize.js plugin does this
            plot.resize();
            plot.setupGrid();
            plot.draw();
        */
        });
        //$("#segment_add").bind("click", function(evt) {
        //});
        this.choiceContainer.find("input").bind("change", function(evt) {
                that.plot();
        });
        $('.legendColorBox > div').each(function(i){
            $(this).clone().prependTo(that.choiceContainer.find("li").eq(i));
        });

        this.legends = $(".legendLabel");
        this.legends.each(function () {
            // fix the widths so they don't jump around
            $(this).css('width', $(this).width());
        });

        var previousPoint = null;
        this.updateLegendTimeout = null;
        this.latestPosition = null;
        $("#exercisegraph").bind("plothover", function (event, pos, item) {
            that.latestPosition = pos;
  //          if (!that.updateLegendTimeout) that.updateLegendTimeout = setTimeout(that.updateLegend, 50);
            //that.updateLegend(pos);

            $("#gtooltip").remove();
            var axes = plot.getAxes();
            // Just retrn if we're hovering around outside the graph area
            if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
                return;

            var posIndex = 0;
            for (serieskey in that.datasets) { // Find first and best series that we got
                var series = that.datasets[serieskey]['data'];
                for (key in series) {
                    if (series[key][0] >= pos.x) {
                        var posIndex = key;
                        break;
                    }
                }
                break;
            }
            if (posIndex <= 0)  // No index found
                return;

            // Move marker to current pos
            if (Mapper.map != null || Mapper.posLayer != undefined) {
                var route_lon = that.datasets['lon'];
                var route_lat = that.datasets['lat'];
                if (route_lon.length >= posIndex) {
                    var x = route_lon[posIndex];
                    var y = route_lat[posIndex];
                    if (!this.posFeature) {
                        this.posFeature = Mapper.createFeature(Mapper.posLayer, x, y, 0);
                    }
                    // Mapper.updatePosMarker(x, y);
                    Mapper.moveFeature(this.posFeature, x, y, 0); // Hardcoded to 0 degrees
                }
            }

            var x = pos.x;
            var highlightedseries = null;
            if (item)
                highlightedseries = item.series.label;

            var tooltipHtml = '
'+ that.xaxisformatter(x, plot.getAxes().xaxis) + '

';
            for (skey in that.datasets) {
                if (skey == 'lon' || skey == 'lat')
                    continue;
                var series = that.datasets[skey];
                var label = series['label'];
                var tickFormatter = axisformatters[skey];
                if (skey == 'poweravg30s')
                    tickFormatter = axisformatters['power'];
                var val = series['data'][posIndex][1]; // Must fetch this from datasets rather thatn the graph data itself because of multiple treshold splits up the indexes
                if(tickFormatter != undefined)
                    val = tickFormatter(val, plot.getAxes().xaxis);
                var color = plot.getOptions().colors[series['color']];
                if(label == highlightedseries) // Highlight if item selected
                    skey += ' selected'
                tooltipHtml += '
' + label + ': ' + val + '
';
            }
            tooltipHtml += '
';
            that.showTooltip(pos.pageX, pos.pageY, tooltipHtml);

        });
        $("#exercisegraph").bind("plotclick", function (event, pos, item) {
            if (item) {
                plot.highlight(item.series, item.datapoint);
            }
            // reset zoom on click
            that.setRange({});
            that.plot();
        });

        $("#exercisegraph").bind("plotselected", function (event, ranges) {
            that.setRange(ranges);
            that.plot();
        });
    }
};

<|endoftext|>


<commit_before>//lets store all the information that we will need to send.
var CurrentUrl = escape(document.location.href);
var CurrentTitle = escape(document.title);
var CurrentVersion = '1';
//var Server = "http://localhost:3000"; //development
var Server = "http://tellmypolitician.com"; //production

//set some constants just so I don't have to change them in 5 places
var bookmarkletWidth = '645px';
var bookmarkletHeight = '399px';

//we need a place on this page to put everything.
var ELcontainer = document.createElement('div');
ELcontainer.id = 'tmp_holder';
ELcontainer.style.width = bookmarkletWidth;
ELcontainer.style.height = bookmarkletHeight;

//we need a iframe that will load data from tmp.com
var ELframe = document.createElement('iframe');
ELframe.id = 'tmp_iframe';
ELframe.src = Server + '/bookmarklet/search?u='+ CurrentUrl + '&title=' + CurrentTitle + '&client=' + CurrentVersion;
ELframe.width='100%';
ELframe.height='100%';
ELframe.setAttribute('scrolling','no');
ELframe.setAttribute('frameborder','0');
ELcontainer.appendChild(ELframe);

//next we need a div that can hold the logo
var ELlogo = document.createElement('div');
ELlogo.id = 'tmp_logo';

//we need a close button as well
var ELcloseImage = document.createElement('img');
ELcloseImage.src = Server + '/images/bookmarklet/close.png';

if (window.addEventListener) { 	// Mozilla, Netscape, Firefox
       ELcloseImage.addEventListener('click', closeBookmarklet, false);
}
else {	// IE
	ELcloseImage.attachEvent('onClick', closeBookmarklet);
}

ELcontainer.appendChild(ELcloseImage);
ELcontainer.appendChild(ELlogo);
document.body.appendChild(ELcontainer);

var ELsheet = document.createElement('style')
var sheet = "#tmp_holder { position:absolute; top:10px; right:10px; z-index:100000; padding:15px; background-color:#001937; border:5px solid #8F0F30; -moz-border-radius:30px; -webkit-border-radius: 30px; }";
sheet += "#tmp_logo{ background:url('" + Server + "/images/design/TMP_LOGO.png') no-repeat; width:387px; height:100px; margin:0px auto; position:relative; top:-42px; }";
sheet += "#tmp_holder img { position:absolute; top:-10px; right:-12px; z-index:10000; }";
sheet += "#tmp_holder iframe { -moz-border-radius:30px; -webkit-border-radius: 30px; overflow : hidden; }";
ELsheet.innerHTML= sheet;
document.body.appendChild(ELsheet);

self.scrollTo(0,0);

function closeBookmarklet()
{
	//ok we need to get rid of our stuff from the page.
	var ELholder = document.getElementById("tmp_holder");
	//to do this we first hide it, because other things may not work later?
        ELholder.style.visibility="hidden";
	//then we remove it from the page.
	document.body.removeChild(ELholder);
}
<commit_msg>changes for bookmarklet in IE 8<commit_after>//lets store all the information that we will need to send.
var CurrentUrl = escape(document.location.href);
var CurrentTitle = escape(document.title);
var CurrentVersion = '1';
//var Server = "http://localhost:3000"; //development
var Server = "http://tellmypolitician.com"; //production

//set some constants just so I don't have to change them in 5 places
var bookmarkletWidth = '645px';
var bookmarkletHeight = '399px';

//we need a place on this page to put everything.
var ELcontainer = document.createElement('div');
ELcontainer.id = 'tmp_holder';
ELcontainer.style.width = bookmarkletWidth;
ELcontainer.style.height = bookmarkletHeight;

//we need a iframe that will load data from tmp.com
var ELframe = document.createElement('iframe');
ELframe.id = 'tmp_iframe';
ELframe.src = Server + '/bookmarklet/search?u='+ CurrentUrl + '&title=' + CurrentTitle + '&client=' + CurrentVersion;
ELframe.width='100%';
ELframe.height='100%';
ELframe.setAttribute('scrolling','no');
ELframe.setAttribute('frameborder','0');
ELcontainer.appendChild(ELframe);

//next we need a div that can hold the logo
var ELlogo = document.createElement('div');
ELlogo.id = 'tmp_logo';

//we need a close button as well
var ELcloseImage = document.createElement('img');
ELcloseImage.src = Server + '/images/bookmarklet/close.png';

if (window.addEventListener) { 	// Mozilla, Netscape, Firefox
       ELcloseImage.addEventListener('click', closeBookmarklet, false);
}
else {	// IE
	ELcloseImage.attachEvent('onClick', closeBookmarklet);
}

ELcontainer.appendChild(ELcloseImage);
ELcontainer.appendChild(ELlogo);
document.body.appendChild(ELcontainer);

var ELsheet = document.createElement('style')
var sheet = "#tmp_holder { position:absolute; top:10px; right:10px; z-index:100000; padding:15px; background-color:#001937; border:5px solid #8F0F30; -moz-border-radius:30px; -webkit-border-radius: 30px; }";
sheet += "#tmp_logo{ background:url('" + Server + "/images/design/TMP_LOGO.png') no-repeat; width:387px; height:100px; margin:0px auto; position:relative; top:-42px; }";
sheet += "#tmp_holder img { position:absolute; top:-10px; right:-12px; z-index:10000; }";
sheet += "#tmp_holder iframe { -moz-border-radius:30px; -webkit-border-radius: 30px; overflow : hidden; }";
ELsheet.appendChild( sheet);
//ELsheet.innerHTML= sheet;
document.body.appendChild(ELsheet);

self.scrollTo(0,0);

function closeBookmarklet()
{
	//ok we need to get rid of our stuff from the page.
	var ELholder = document.getElementById("tmp_holder");
	//to do this we first hide it, because other things may not work later?
        ELholder.style.visibility="hidden";
	//then we remove it from the page.
	document.body.removeChild(ELholder);
}
<|endoftext|>