<commit_before>/**
 * This class controls a gameplay experiment where the player is
 * invited to play all the games, one after another, while
 * some data are collected (facial expressions, etc).
 */

 var FTG = FTG || {};

 FTG.Experiment = function() {
     this.mUid;
     this.mCurrentGame;
     this.mRestTime;
     this.mEnableFaceTracking;
     this.mBipSound;
     this.mTanSound;
     this.mCalmSound;

     this.mGames = [
         {id: 3, name: 'platformer', url: '../platformer/', width: 1024, height: 768},
         {id: 2, name: 'tetris', url: '../tetris/', width: 1024, height: 800},
         {id: 1, name: 'card-flipper', url: '../card-flipper/', width: 1524, height: 768}
     ];

    // Initialize the whole thing up
    this.init();
 };

// Singleton that will be used by all games
FTG.Experiment.instance = null;

// Methods

FTG.Experiment.prototype.init = function() {
    this.mUid = FTG.Utils.getURLParamByName('user');

    this.mCurrentGame = -1; // TODO: get from URL.
    this.mRestTime = FTG.Utils.getURLParamByName('rest') || 3;
    this.mEnableFaceTracking = FTG.Utils.getURLParamByName('face') || false;
    this.mBipSound = document.getElementById('bip');
    this.mTanSound = document.getElementById('tan');
    this.mCalmSound = document.getElementById('calm');

    this.mRestTime *= 60 * 1000;

    console.log('[Experiment] Init with user uid:' + this.mUid + ', rest: ' + this.mRestTime + ', facial tracking: ' + this.mEnableFaceTracking);

    if(this.mUid == null) {
        alert('User id not informed! Append ?user=DDD to the URL.');
    } else {
        // Reverse the order of the games for a subset of users.
        if(this.mUid % 2 == 0) {
            this.mGames.reverse();
        }
        this.greetings();
    }
};

FTG.Experiment.prototype.enableCalmMusic = function(theStatus) {
    if(theStatus) {
        this.mCalmSound.loop = true;
        this.mCalmSound.play();
    } else {
        this.mCalmSound.pause();
    }
};

FTG.Experiment.prototype.playBipSound = function() {
    this.mBipSound.currentTime = 0;
    this.mBipSound.play();
};

FTG.Experiment.prototype.playTanSound = function() {
    this.mTanSound.currentTime = 0;
    this.mTanSound.play();
};

FTG.Experiment.prototype.greetings = function() {
    var aSelf = this;

    $('#info').html(
        '
' +
            '
Instructions
' +
            '
User: ' + this.mUid + '
' +
            '
Welcome! Please wait the researcher let you know when to start.
When you are told to start, click the "Start" button below.

Thank you for being part of this research!
' +
            '<button>Start</button>' +
        '
'
    );

    $('#info button').click(function() {
        aSelf.startNewGame();
    });

    // Play the bip sound to indicate everything is set.
    this.playBipSound();
};

FTG.Experiment.prototype.generateGameURL = function(theGameInfo) {
    return theGameInfo.url + '?user=' + this.mUid + '&game=' + theGameInfo.id + '&rand=' + Math.random() + '&face=' + this.mEnableFaceTracking;
};

FTG.Experiment.prototype.startNewGame = function() {
    var aGame;

    this.mCurrentGame++;

    if(this.anyMoreGamesToPlay()) {
        aGame = this.getCurrentGame();

        console.log('[Experiment] New game about to start: ' + aGame.name + ' (id=' + aGame.id + ')');
        this.playBipSound();

        // Add the game iframe and ajust its src property (prevent chache issues)
        $('#info').html('');
        document.getElementById('game').src = this.generateGameURL(aGame);

        // TODO: remove this block
        $('#info').append('<button>Conclude</button>');
        var aSelf = this;
        $('#info button').click(function() {
            aSelf.concludeCurrentGame();
        });

    } else {
        console.log('[Experiment] No more games to play, finishing now');
        this.finish();
    }
};

FTG.Experiment.prototype.concludeCurrentQuestionnaire = function(theData) {
    var aSelf = this;

    console.log('[Experiment] Sending questionnaire data.', theData);

    $.ajax({
        url: '../backend/',
        method: 'POST',
        data: {
            method: 'answer',
            user: this.mUid,
            game: this.getCurrentGame().id,
            data: JSON.stringify({t: Date.now(), d: theData})
        },
        dataType: 'json'

    }).done(function(theData) {
        if(theData.success) {
            console.log('[Experiment] Questionnaire data has been saved!');
            aSelf.rest();
        } else {
            console.error('[Experiment] Backend didn\'t like the answers: ' + theData.message);
        }
    }).fail(function(theXHR, theText) {
        // TODO: show some user friendly messages?
        console.error('Something wrong: ' + theXHR.responseText, theXHR, theText);
    });
};

FTG.Experiment.prototype.concludeCurrentGame = function() {
    var aGame,
        aQuestions;

    aGame = this.getCurrentGame();

    console.log('[Experiment] Current game (' + aGame.name + ', id=' + aGame.id + ') was concluded.');
    this.playTanSound();

    $('#info').html(
        '
' +
            '
Questions
' +
            '
Regarding the game you just played, please answer the questions below.
' +
            '

' +
        '
'
    );

    aQuestions = new FTG.Questionnaire(
        'questions',
        this.mUid,
        aGame.id,
        FTG.Questions.Game,
        this.concludeCurrentQuestionnaire,
        this
    );
};

FTG.Experiment.prototype.rest = function() {
    var aFuture = Date.now() + this.mRestTime,
        aSelf = this,
        aId;

    console.log('[Experiment] Resting for ' + (this.mRestTime/1000) + ' seconds...');

    this.enableCalmMusic(true);
    $('#info').html('

Please, relax.

Next game will start in a moment...

');

    aId = setInterval(function() {
        var aRemaining = aFuture - Date.now();

        if(aRemaining <= 0) {
            clearInterval(aId);
            aSelf.enableCalmMusic(false);
            aSelf.startNewGame();
        }
    }, 200);
};

FTG.Experiment.prototype.finish = function() {
    console.log('[Experiment] The party is over! Last one to leave turns off the lights.');
    $('#info').html('Finish');
};

FTG.Experiment.prototype.getCurrentGame = function() {
    // TODO: return game according to user id
    return this.mGames[this.mCurrentGame];
};

FTG.Experiment.prototype.anyMoreGamesToPlay = function() {
    return this.mCurrentGame < this.mGames.length;
};

// Start the party!
$(function() {
    FTG.Experiment.instance = new FTG.Experiment();
});
<commit_msg>Complete flow for the experiment.<commit_after>/**
 * This class controls a gameplay experiment where the player is
 * invited to play all the games, one after another, while
 * some data are collected (facial expressions, etc).
 */

 var FTG = FTG || {};

 FTG.Experiment = function() {
     this.mUid;
     this.mCurrentGame;
     this.mRestTime;
     this.mEnableFaceTracking;
     this.mFinished;
     this.mBipSound;
     this.mTanSound;
     this.mCalmSound;

     this.mGames = [
         {id: 1, name: 'card-flipper', url: '../card-flipper/', width: 1524, height: 768},
         {id: 2, name: 'tetris', url: '../tetris/', width: 1024, height: 800},
         {id: 3, name: 'platformer', url: '../platformer/', width: 1024, height: 768}
     ];

     this.mGamesSorting = [
         [0, 1, 2],
         [0, 2, 1],
         [1, 0, 2],
         [1, 2, 0],
         [2, 1, 0],
         [2, 0, 1],
     ];
     this.mSorting;

    // Initialize the whole thing up
    this.init();
 };

// Singleton that will be used by all games
FTG.Experiment.instance = null;

// Methods

FTG.Experiment.prototype.init = function() {
    this.mUid = FTG.Utils.getURLParamByName('user');

    this.mCurrentGame = -1; // TODO: get from URL.
    this.mRestTime = FTG.Utils.getURLParamByName('rest') || 3;
    this.mEnableFaceTracking = FTG.Utils.getURLParamByName('face') || false;
    this.mBipSound = document.getElementById('bip');
    this.mTanSound = document.getElementById('tan');
    this.mCalmSound = document.getElementById('calm');
    this.mSorting = this.mUid ? this.mUid % this.mGamesSorting.length : 0;
    this.mFinished = false;

    this.mRestTime *= 60 * 1000;

    console.log('[Experiment] Init with user uid:' + this.mUid + ', rest: ' + this.mRestTime + ', facial tracking: ' + this.mEnableFaceTracking + ', sorting: ' + this.mSorting + ' [' + this.mGamesSorting[this.mSorting].join(',') + ']');

    if(this.mUid == null) {
        alert('User id not informed! Append ?user=DDD to the URL.');
    } else {
        // Reverse the order of the games for a subset of users.
        if(this.mUid % 2 == 0) {
            this.mGames.reverse();
        }
        this.greetings();
    }
};

FTG.Experiment.prototype.enableCalmMusic = function(theStatus) {
    if(theStatus) {
        this.mCalmSound.loop = true;
        this.mCalmSound.play();
    } else {
        this.mCalmSound.pause();
    }
};

FTG.Experiment.prototype.playBipSound = function() {
    this.mBipSound.currentTime = 0;
    this.mBipSound.play();
};

FTG.Experiment.prototype.playTanSound = function() {
    this.mTanSound.currentTime = 0;
    this.mTanSound.play();
};

FTG.Experiment.prototype.greetings = function() {
    var aSelf = this;

    $('#info').html(
        '
' +
            '
Instructions
' +
            '
User: ' + this.mUid + '
' +
            '
Welcome! Please wait the researcher let you know when to start.
When you are told to start, click the "Start" button below.

Thank you for being part of this research!
' +
            '<button>Start</button>' +
        '
'
    );

    $('#info button').click(function() {
        aSelf.startNewGame();
    });

    // Play the bip sound to indicate everything is set.
    this.playBipSound();
};

FTG.Experiment.prototype.generateGameURL = function(theGameInfo) {
    return theGameInfo.url + '?user=' + this.mUid + '&game=' + theGameInfo.id + '&rand=' + Math.random() + '&face=' + this.mEnableFaceTracking;
};

FTG.Experiment.prototype.startNewGame = function() {
    var aGame;

    if(this.anyMoreGamesToPlay()) {
        this.mCurrentGame++;
        aGame = this.getCurrentGame();

        console.log('[Experiment] New game about to start: ' + aGame.name + ' (id=' + aGame.id + ')');
        this.playBipSound();

        // Add the game iframe and ajust its src property (prevent chache issues)
        $('#info').html('');
        document.getElementById('game').src = this.generateGameURL(aGame);

        // TODO: remove this block
        $('#info').append('<button>Conclude</button>');
        var aSelf = this;
        $('#info button').click(function() {
            aSelf.concludeCurrentGame();
        });

    } else {
        console.log('[Experiment] No more games to play, finishing now');
        this.finish();
    }
};

FTG.Experiment.prototype.concludeCurrentQuestionnaire = function(theData) {
    var aSelf = this;

    console.log('[Experiment] Sending questionnaire data.', theData);

    $.ajax({
        url: '../backend/',
        method: 'POST',
        data: {
            method: 'answer',
            user: this.mUid,
            game: this.getCurrentGame().id,
            data: JSON.stringify({t: Date.now(), d: theData})
        },
        dataType: 'json'

    }).done(function(theData) {
        if(theData.success) {
            console.log('[Experiment] Questionnaire data has been saved!');

            if(aSelf.anyMoreGamesToPlay()) {
                aSelf.rest();
            } else {
                aSelf.finish();
            }

        } else {
            console.error('[Experiment] Backend didn\'t like the answers: ' + theData.message);
        }
    }).fail(function(theXHR, theText) {
        // TODO: show some user friendly messages?
        console.error('Something wrong: ' + theXHR.responseText, theXHR, theText);
    });
};

FTG.Experiment.prototype.concludeCurrentGame = function() {
    var aGame,
        aQuestions;

    aGame = this.getCurrentGame();

    console.log('[Experiment] Current game (' + aGame.name + ', id=' + aGame.id + ') was concluded.');
    this.playTanSound();

    $('#info').html(
        '
' +
            '
Questions
' +
            '
Regarding the game you just played, please answer the questions below.
' +
            '

' +
        '
'
    );

    aQuestions = new FTG.Questionnaire(
        'questions',
        this.mUid,
        aGame.id,
        FTG.Questions.Game,
        this.concludeCurrentQuestionnaire,
        this
    );
};

FTG.Experiment.prototype.rest = function() {
    var aFuture = Date.now() + this.mRestTime,
        aSelf = this,
        aId;

    console.log('[Experiment] Resting for ' + (this.mRestTime/1000) + ' seconds...');

    this.enableCalmMusic(true);
    $('#info').html('

Please, relax.

Next game will start in a moment...

');

    aId = setInterval(function() {
        var aRemaining = aFuture - Date.now();

        if(aRemaining <= 0) {
            clearInterval(aId);
            aSelf.enableCalmMusic(false);
            aSelf.startNewGame();
        }
    }, 200);
};

FTG.Experiment.prototype.finish = function() {
    if(this.mFinished) {
        this.sendSubjectHome();
        return;
    }

    console.log('[Experiment] Finishing up. Last chance to ask anything.');
    this.playTanSound();

    $('#info').html(
        '
' +
            '
Questions
' +
            '
Please tell us a bit about you.
' +
            '

' +
        '
'
    );

    aQuestions = new FTG.Questionnaire(
        'questions',
        this.mUid,
        -1, // no game
        FTG.Questions.User,
        this.concludeCurrentQuestionnaire,
        this
    );

    this.mFinished = true;
};

FTG.Experiment.prototype.sendSubjectHome = function() {
    console.log('[Experiment] The party is over! Last one to leave turn off the lights.');
    $('#info').html('

The end!

You are good to go. Thank you for helping us help us all! :)

');
};

FTG.Experiment.prototype.getCurrentGame = function() {
    return this.mGames[this.mGamesSorting[this.mSorting][this.mCurrentGame]];
};

FTG.Experiment.prototype.anyMoreGamesToPlay = function() {
    return (this.mCurrentGame + 1) < this.mGamesSorting[this.mSorting].length;
};

// Start the party!
$(function() {
    FTG.Experiment.instance = new FTG.Experiment();
});
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Broad Institute
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

// Simple variant track for mpg prototype

var igv = (function (igv) {

    const DEFAULT_POPOVER_WINDOW = 100000000;

    igv.GWASTrack = function (config) {
        this.config = config;
        this.url = config.url;
        this.name = config.name;
        this.trait = config.trait;
        this.height = config.height || 100;   // The preferred height
        this.minLogP = config.minLogP || 0;
        this.maxLogP = config.maxLogP || 15;
        this.background = config.background;    // No default
        this.divider = config.divider || "rgb(225,225,225)";
        this.dotSize = config.dotSize || 4;
        this.popoverWindow = (config.popoverWindow === undefined ? DEFAULT_POPOVER_WINDOW : config.popoverWindow);

        this.description = config.description;  // might be null
        this.proxy = config.proxy;   // might be null

        this.portalURL = config.portalURL ? config.portalURL : window.location.origin;
        this.variantURL = config.variantURL || "http://www.type2diabetesgenetics.org/variant/variantInfo/";
        this.traitURL = config.traitURL || "http://www.type2diabetesgenetics.org/trait/traitInfo/";

        var cs = config.colorScale || {
            thresholds: [5e-8, 5e-4, 0.5],
            colors: ["rgb(255,50,50)", "rgb(251,100,100)", "rgb(251,170,170)", "rgb(227,238,249)"]
        };

        this.pvalue = config.pvalue ? config.pvalue : "PVALUE";

        this.colorScale = new igv.BinnedColorScale(cs);

        // An obvious hack -- the source should be passed in as an arbument
        if(config.format && ("gtexGWAS" === config.format)) {
            this.featureSource = new igv.FeatureSource(config);
        } else {
            this.featureSource = new igv.T2DVariantSource(config);
        }

    }

    igv.GWASTrack.prototype.getFeatures = function (chr, bpStart, bpEnd, continuation, task) {

        this.featureSource.getFeatures(chr, bpStart, bpEnd, continuation, task)
    }

    igv.GWASTrack.prototype.draw = function (options) {

        var track = this,
            featureList = options.features,
            ctx = options.context,
            bpPerPixel = options.bpPerPixel,
            bpStart = options.bpStart,
            pixelWidth = options.pixelWidth,
            pixelHeight = options.pixelHeight,
            bpEnd = bpStart + pixelWidth * bpPerPixel + 1,
            yScale = (track.maxLogP - track.minLogP) / pixelHeight,
            enablePopover = (bpEnd - bpStart) < DEFAULT_POPOVER_WINDOW;

        if (enablePopover) {
            this.po = [];
        }
        else {
            this.po = undefined;
        }

        if (this.background) igv.graphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': this.background});
        igv.graphics.strokeLine(ctx, 0, pixelHeight - 1, pixelWidth, pixelHeight - 1, {'strokeStyle': this.divider});

        var variant, pos, len, xScale, px, px1, pw, py, color, pvalue, val;

        if (featureList) {
            len = featureList.length;

            for (var i = 0; i < len; i++) {

                variant = featureList[i];

                pos = variant.start;     // TODO fixme

                if (pos < bpStart) continue;
                if (pos > bpEnd) break;

                pvalue = variant.pvalue || variant[track.pvalue];
                if (!pvalue) continue;

                color = track.colorScale.getColor(pvalue);
                val = -Math.log(pvalue) / 2.302585092994046;

                xScale = bpPerPixel;

                px = Math.round((pos - bpStart) / xScale);

                py = Math.max(track.dotSize, pixelHeight - Math.round((val - track.minLogP) / yScale));

                if (color) igv.graphics.setProperties(ctx, {fillStyle: color, strokeStyle: "black"});

                igv.graphics.fillCircle(ctx, px, py, track.dotSize);
                //canvas.strokeCircle(px, py, radius);

                if (enablePopover) track.po.push({x: px, y: py, feature: variant});

            }
        }

    };

    igv.GWASTrack.prototype.paintAxis = function (ctx, pixelWidth, pixelHeight) {

        var track = this,
            yScale = (track.maxLogP - track.minLogP) / pixelHeight;

        var font = {'font': 'normal 10px Arial',
            'textAlign': 'right',
            'strokeStyle': "black"};

        igv.graphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});

        for (var p = 2; p < track.maxLogP; p += 2) {
            var yp = pixelHeight - Math.round((p - track.minLogP) / yScale);
            // TODO: Dashes may not actually line up with correct scale. Ask Jim about this
            igv.graphics.strokeLine(ctx, 45, yp - 2, 50, yp - 2, font); // Offset dashes up by 2 pixel
            igv.graphics.fillText(ctx, p, 44, yp + 2, font); // Offset numbers down by 2 pixels;
        }

        font['textAlign'] = 'center';

        igv.graphics.fillText(ctx, "-log10(pvalue)", pixelWidth / 2, pixelHeight / 2, font, {rotate: {angle: -90}});

    };

    igv.GWASTrack.prototype.popupData = function (genomicLocation, xOffset, yOffset) {

        var i,
            len,
            p,
            dbSnp,
            url,
            data = [],
            chr,
            pos,
            pvalue;

        if (this.po) {
            for (i = 0, len = this.po.length; i < len; i++) {
                p = this.po[i];

                if (Math.abs(xOffset - p.x) < this.dotSize && Math.abs(yOffset - p.y) <= this.dotSize) {

                    chr = p.feature.CHROM || p.feature.chr;   // TODO fixme
                    pos = p.feature.POS || p.feature.start;   // TODO fixme
                    pvalue = p.feature[this.pvalue] || p.feature.pvalue;
                    dbSnp = p.feature.DBSNP_ID;

                    if (dbSnp) {
                        url = this.variantURL.startsWith("http") ? this.variantURL : this.portalURL + "/" + this.variantURL + "/" + dbSnp;
                        data.push("" + dbSnp + "");
                    }
                    data.push(chr + ":" + pos.toString());
                    data.push({name: 'p-value', value: pvalue});

                    if (p.feature.ZSCORE) {
                        data.push({name: 'z-score', value: p.feature.ZSCORE});
                    }

                    if (dbSnp) {
                        url = this.traitURL.startsWith("http") ? this.traitURL : this.portalURL + "/" + this.traitURL + "/" + dbSnp;
                        data.push("" + "see all available statistics for this variant");
                    }

                    if (i < len - 1) {
                        data.push("
");
                    }
                }
            }
        } else {
            data.push("Popover not available at this resolution.")

        }
        return data;
    };

    return igv;

})(igv || {});<commit_msg>dittor<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Broad Institute
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

// Simple variant track for mpg prototype

var igv = (function (igv) {

    const DEFAULT_POPOVER_WINDOW = 100000000;

    igv.GWASTrack = function (config) {
        this.config = config;
        this.url = config.url;
        this.name = config.name;
        this.trait = config.trait;
        this.height = config.height || 100;   // The preferred height
        this.minLogP = config.minLogP || 0;
        this.maxLogP = config.maxLogP || 15;
        this.background = config.background;    // No default
        this.divider = config.divider || "rgb(225,225,225)";
        this.dotSize = config.dotSize || 4;
        this.popoverWindow = (config.popoverWindow === undefined ? DEFAULT_POPOVER_WINDOW : config.popoverWindow);

        this.description = config.description;  // might be null
        this.proxy = config.proxy;   // might be null

        this.portalURL = config.portalURL ? config.portalURL : window.location.origin;
        this.variantURL = config.variantURL || "http://www.type2diabetesgenetics.org/variant/variantInfo/";
        this.traitURL = config.traitURL || "http://www.type2diabetesgenetics.org/trait/traitInfo/";

        var cs = config.colorScale || {
            thresholds: [5e-8, 5e-4, 0.5],
            colors: ["rgb(255,50,50)", "rgb(251,100,100)", "rgb(251,170,170)", "rgb(227,238,249)"]
        };

        this.pvalue = config.pvalue ? config.pvalue : "PVALUE";

        this.colorScale = new igv.BinnedColorScale(cs);

        // An obvious hack -- the source should be passed in as an arbument
        if(config.format && ("gtexGWAS" === config.format)) {
            this.featureSource = new igv.FeatureSource(config);
        } else {
            this.featureSource = new igv.T2DVariantSource(config);
        }

    }

    igv.GWASTrack.prototype.getFeatures = function (chr, bpStart, bpEnd, continuation, task) {

        this.featureSource.getFeatures(chr, bpStart, bpEnd, continuation, task)
    }

    igv.GWASTrack.prototype.draw = function (options) {

        var track = this,
            featureList = options.features,
            ctx = options.context,
            bpPerPixel = options.bpPerPixel,
            bpStart = options.bpStart,
            pixelWidth = options.pixelWidth,
            pixelHeight = options.pixelHeight,
            bpEnd = bpStart + pixelWidth * bpPerPixel + 1,
            yScale = (track.maxLogP - track.minLogP) / pixelHeight,
            enablePopover = (bpEnd - bpStart) < DEFAULT_POPOVER_WINDOW;

        if (enablePopover) {
            this.po = [];
        }
        else {
            this.po = undefined;
        }

        if (this.background) igv.graphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': this.background});
        igv.graphics.strokeLine(ctx, 0, pixelHeight - 1, pixelWidth, pixelHeight - 1, {'strokeStyle': this.divider});

        var variant, pos, len, xScale, px, px1, pw, py, color, pvalue, val;

        if (featureList) {
            len = featureList.length;

            for (var i = 0; i < len; i++) {

                variant = featureList[i];

                pos = variant.start;     // TODO fixme

                if (pos < bpStart) continue;
                if (pos > bpEnd) break;

                pvalue = variant.pvalue || variant[track.pvalue];
                if (!pvalue) continue;

                color = track.colorScale.getColor(pvalue);
                val = -Math.log(pvalue) / 2.302585092994046;

                xScale = bpPerPixel;

                px = Math.round((pos - bpStart) / xScale);

                py = Math.max(track.dotSize, pixelHeight - Math.round((val - track.minLogP) / yScale));

                if (color) igv.graphics.setProperties(ctx, {fillStyle: color, strokeStyle: "black"});

                igv.graphics.fillCircle(ctx, px, py, track.dotSize);
                //canvas.strokeCircle(px, py, radius);

                if (enablePopover) track.po.push({x: px, y: py, feature: variant});

            }
        }

    };

    igv.GWASTrack.prototype.paintAxis = function (ctx, pixelWidth, pixelHeight) {

        var track = this,
            yScale = (track.maxLogP - track.minLogP) / pixelHeight;

        var font = {'font': 'normal 10px Arial',
            'textAlign': 'right',
            'strokeStyle': "black"};

        igv.graphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});

        for (var p = 2; p < track.maxLogP; p += 2) {
            var yp = pixelHeight - Math.round((p - track.minLogP) / yScale);
            // TODO: Dashes may not actually line up with correct scale. Ask Jim about this
            igv.graphics.strokeLine(ctx, 45, yp - 2, 50, yp - 2, font); // Offset dashes up by 2 pixel
            igv.graphics.fillText(ctx, p, 44, yp + 2, font); // Offset numbers down by 2 pixels;
        }

        font['textAlign'] = 'center';

        igv.graphics.fillText(ctx, "-log10(pvalue)", pixelWidth / 2, pixelHeight / 2, font, {rotate: {angle: -90}});

    };

    igv.GWASTrack.prototype.popupData = function (genomicLocation, xOffset, yOffset) {

        var i,
            len,
            p,
            dbSnp,
            url,
            data = [],
            chr,
            pos,
            pvalue;

        if (this.po) {
            for (i = 0, len = this.po.length; i < len; i++) {
                p = this.po[i];

                if (Math.abs(xOffset - p.x) < this.dotSize && Math.abs(yOffset - p.y) <= this.dotSize) {

                    chr = p.feature.CHROM || p.feature.chr;   // TODO fixme
                    pos = p.feature.POS || p.feature.start;   // TODO fixme
                    pvalue = p.feature[this.pvalue] || p.feature.pvalue;
                    dbSnp = p.feature.DBSNP_ID;

                    if (dbSnp) {
                        url = this.variantURL.startsWith("http") ? this.variantURL : this.portalURL + "/" + this.variantURL;
                        data.push("" + dbSnp + "");
                    }
                    data.push(chr + ":" + pos.toString());
                    data.push({name: 'p-value', value: pvalue});

                    if (p.feature.ZSCORE) {
                        data.push({name: 'z-score', value: p.feature.ZSCORE});
                    }

                    if (dbSnp) {
                        url = this.traitURL.startsWith("http") ? this.traitURL : this.portalURL + "/" + this.traitURL ;
                        data.push("" + "see all available statistics for this variant");
                    }

                    if (i < len - 1) {
                        data.push("
");
                    }
                }
            }
        } else {
            data.push("Popover not available at this resolution.")

        }
        return data;
    };

    return igv;

})(igv || {});<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * @author mig <michel.gutierrez@gmail.com>
 * @version 0.1
 * @module jaingee
 * @overview Javascript UI/Layout application framework.
 */

(function($) {

	'use strict';

	angular.module('com.jocly.jaingee.adjust', ['com.jocly.jaingee.layout', 'com.jocly.jaingee.unit'])

	/**
	 * jngUnit service: facilities on button/toolbar sizing
	 */
	.service('jngAdjust', [ '$rootScope', '$window', '$document', 'jngLayout', 'jngUnit', function($rootScope, $window, $document, jngLayout, jngUnit) {

		//console.log("installed jngAdjust")

		var pixelRatio=1;
		if($window.devicePixelRatio)
			pixelRatio=$window.devicePixelRatio;

		$rootScope.jngAdjust={
			specs: [{
				title: "Huge",
				min: 1280,
				bodyClass: "jng-adjust-huge",
				unit: 80,
			},{
				title: "Big",
				min: 768,
				bodyClass: "jng-adjust-big",
				unit: 60,
			},{
				title: "Medium",
				min: 360,
				bodyClass: "jng-adjust-medium",
				unit: 40,
			},{
				title: "Small",
				bodyClass: "jng-adjust-small",
				unit: 30,
			}],
			currentClass: "jng-adjust-medium",
			pixelRatio: pixelRatio,
			screenWidth: 0,
			screenHeight: 0,
			autoAdjust: true,
		};

		var body=angular.element($document[0].body);
		body.addClass($rootScope.jngAdjust.currentClass);

		function UpdateClass(spec) {
			body.addClass(spec.bodyClass);
			$rootScope.jngUnit.unit.pixels=spec.unit;
		}

		jngLayout.watchWindowDimensions(function (winSize) {
			$rootScope.jngAdjust.screenWidth=winSize.w;
			$rootScope.jngAdjust.screenHeight=winSize.h;
			var newSpec=null;
			var size=Math.min(winSize.w,winSize.h)*pixelRatio;
			for(var i=0;i<$rootScope.jngAdjust.specs.length;i++) {
				var spec=$rootScope.jngAdjust.specs[i];
				if((spec.min===undefined || size>=spec.min) &&
					(spec.max===undefined || size<=spec.max)) {
					newSpec=spec;
					break;
				}
			}
			if($rootScope.jngAdjust.autoAdjust && newSpec && newSpec.bodyClass!=$rootScope.jngAdjust.currentClass) {
				$rootScope.jngAdjust.currentClass=spec.bodyClass;
			}
        });

		$rootScope.$watch('jngAdjust.currentClass',function(newValue,oldValue) {
			console.log("modified current class")
			var newSpec=null;
			for(var i=0;i<$rootScope.jngAdjust.specs.length;i++) {
				var spec=$rootScope.jngAdjust.specs[i];
				if(spec.bodyClass==newValue) {
					newSpec=spec;
					break;
				}
			}
			if(newSpec) {
				body.removeClass(oldValue);
				UpdateClass(newSpec);
			}
		});

	}]);

})(jQuery);
<commit_msg>Removed debug trace<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * @author mig <michel.gutierrez@gmail.com>
 * @version 0.1
 * @module jaingee
 * @overview Javascript UI/Layout application framework.
 */

(function($) {

	'use strict';

	angular.module('com.jocly.jaingee.adjust', ['com.jocly.jaingee.layout', 'com.jocly.jaingee.unit'])

	/**
	 * jngUnit service: facilities on button/toolbar sizing
	 */
	.service('jngAdjust', [ '$rootScope', '$window', '$document', 'jngLayout', 'jngUnit', function($rootScope, $window, $document, jngLayout, jngUnit) {

		//console.log("installed jngAdjust")

		var pixelRatio=1;
		if($window.devicePixelRatio)
			pixelRatio=$window.devicePixelRatio;

		$rootScope.jngAdjust={
			specs: [{
				title: "Huge",
				min: 1280,
				bodyClass: "jng-adjust-huge",
				unit: 80,
			},{
				title: "Big",
				min: 768,
				bodyClass: "jng-adjust-big",
				unit: 60,
			},{
				title: "Medium",
				min: 360,
				bodyClass: "jng-adjust-medium",
				unit: 40,
			},{
				title: "Small",
				bodyClass: "jng-adjust-small",
				unit: 30,
			}],
			currentClass: "jng-adjust-medium",
			pixelRatio: pixelRatio,
			screenWidth: 0,
			screenHeight: 0,
			autoAdjust: true,
		};

		var body=angular.element($document[0].body);
		body.addClass($rootScope.jngAdjust.currentClass);

		function UpdateClass(spec) {
			body.addClass(spec.bodyClass);
			$rootScope.jngUnit.unit.pixels=spec.unit;
		}

		jngLayout.watchWindowDimensions(function (winSize) {
			$rootScope.jngAdjust.screenWidth=winSize.w;
			$rootScope.jngAdjust.screenHeight=winSize.h;
			var newSpec=null;
			var size=Math.min(winSize.w,winSize.h)*pixelRatio;
			for(var i=0;i<$rootScope.jngAdjust.specs.length;i++) {
				var spec=$rootScope.jngAdjust.specs[i];
				if((spec.min===undefined || size>=spec.min) &&
					(spec.max===undefined || size<=spec.max)) {
					newSpec=spec;
					break;
				}
			}
			if($rootScope.jngAdjust.autoAdjust && newSpec && newSpec.bodyClass!=$rootScope.jngAdjust.currentClass) {
				$rootScope.jngAdjust.currentClass=spec.bodyClass;
			}
        });

		$rootScope.$watch('jngAdjust.currentClass',function(newValue,oldValue) {
			var newSpec=null;
			for(var i=0;i<$rootScope.jngAdjust.specs.length;i++) {
				var spec=$rootScope.jngAdjust.specs[i];
				if(spec.bodyClass==newValue) {
					newSpec=spec;
					break;
				}
			}
			if(newSpec) {
				body.removeClass(oldValue);
				UpdateClass(newSpec);
			}
		});

	}]);

})(jQuery);
<|endoftext|>


<commit_before>(function($){
    "use strict";
    function createLink(idSuffix,text)
    {
        var link= document.createElement('a');
        link.href='#outline_'+idSuffix;
        link.innerHTML=text;
        return link;
    }

    function createHeader(wrapDiv,element)
    {
        var header = document.createElement("h3");
        header.innerHTML=element.innerHTML;
        wrapDiv.appendChild(header);
    }

    function createOutline(id,elements,hasTitle)
    {
        var i=0;//index of elements
        var content=$(id);
        var wrapDiv = content[0]||content;
        hasTitle&&createHeader(wrapDiv,elements[i++]);

        var ul = document.createElement("ul");
        var len=elements.length;

        var li=document.createElement('li');
        var link= createLink(i,elements[i++].innerHTML);
        li.appendChild(link);
        ul.appendChild(li); //create first li element to compare

        for (; i < len; i++){

            li= createElement(li,elements[i],elements[i-1].nodeName,i)
        }

        wrapDiv.appendChild(ul);
        return wrapDiv;
    }

    function createElement(current,element,lastNodeName,index)
    {
        var link= createLink(index,element.innerHTML);
        var ul,
            li=document.createElement('li');
        li.appendChild(link);
        if(element.nodeName>lastNodeName)//eg. H3>H2
        {
            ul = document.createElement("ul");
            ul.appendChild(li);
            current.appendChild(ul);
        }
        else if(element.nodeName===lastNodeName)
        {
            current.parentNode.appendChild(li);
        }
        else
        {
            //当为ul时继续查找
            while(current.nodeName.toUpperCase()==='UL'||(document.getElementById(current.firstChild.getAttribute('href').substring(1)).nodeName!==element.nodeName))
            {
                if(current.parentNode)
                {
                    current=current.parentNode;
                }
                else
                {
                    //如果没有父节点，说明是顶层的ul，把当前元素置为顶层ul第一个子元素,方便插入
                    current=current.firstChild;
                    break;
                }

            }

            current.parentNode.appendChild(li);

        }
        return li;

    }

    function validate(option)
    {
        if(!option.contentSelector)
        {
             throw new TypeError("contentSelector is Required attribute");
        }
    }

    var ol={
        outline:function(option)
        {

            validate(option);

            var option= $.extend({
                selector:'body',  //css选择器，选择的范围
                hArray:['h1','h2','h3','h4','h5','h6'], //要识别的header
                addSpy:true,
                hasTitle:false, //范围内是否第一个是标题
                offset:20
            },option);

            var hSelector=option.hArray.join(',');
            var index=0;
            $(option.selector).find(hSelector).each(function()
            {
                var id='outline_'+index++;
                this.setAttribute('id',id);

                if(option.addSpy){
                    //scrollspy
                    var $that=$(this);
                    var position = $that.position();
                    console.log(this);
                    $that.scrollspy({

                        min:  $that.offset().top-option.offset,
                        max: (function () {
                            var next= $that.nextAll(hSelector)[0];//下一个标题

                            return next?$(next).offset().top:$that.offset().top;
                        })(),
                        onEnter: function(element, position) {

                            $('[href="#'+element.id+'"]').addClass("active-header");
                        },
                        onLeave: function(element, position) {
                            $('[href="#'+element.id+'"]').removeClass("active-header");
                        }
                    });
                }
            });
            createOutline(option.contentSelector,$(option.selector).find(hSelector),option.hasTitle)

        }

    };

    $.extend(ol);

    /*data API*/

    if($('[data-outline]'))
    {

        $.outline({contentSelector:'[data-outline]',selector:$('[data-outline]').data('outline')});

    }

})(jQuery);/**
 * Created by Lucien on 7/14/2015.
 */

//$.outline({contentSelector:'#sub-outline',selector:'article',hasTitle:true});
<commit_msg>实现全部功能<commit_after>/*!
 * jQuery Scrollspy Plugin
 * Author: @sxalexander，Lucien
 * Licensed under the MIT license
 */
;
(function ($, window, document, undefined) {

    $.fn.extend({
        scrollspy: function (options) {

            var defaults = {
                min: 0,
                max: 0,
                mode: 'vertical',
                namespace: 'scrollspy',
                buffer: 0,
                container: window,
                onEnter: [],
                onLeave: [],
                onTick: []
            }

            var options = $.extend({}, defaults, options);

            return this.each(function (i) {

                var element = this;
                var o = options;
                var $container = $(o.container);
                var mode = o.mode;
                var buffer = o.buffer;
                var enters = leaves = 0;
                var inside = false;

                /* add listener to container */
                $container.bind('scroll.' + o.namespace, function (e) {
                    var position = {top: $(this).scrollTop(), left: $(this).scrollLeft()};
                    var xy = (mode == 'vertical') ? position.top + buffer : position.left + buffer;
                    var max = o.max;
                    var min = o.min;

                    /* fix max */
                    if ($.isFunction(o.max)) {
                        max = o.max();
                    }

                    /* fix max */
                    if ($.isFunction(o.min)) {
                        min = o.min();
                    }

                    if (max == 0) {
                        max = (mode == 'vertical') ? $container.height() : $container.outerWidth() + $(element).outerWidth();
                    }

                    /* if we have reached the minimum bound but are below the max ... */
                    if (xy >= min && xy <= max) {
                        /* trigger enter event */
                        if (!inside) {
                            inside = true;
                            enters++;

                            /* fire enter event */
                            $(element).trigger('scrollEnter', {position: position})
                            if ($.isFunction(o.onEnter)) {
                                o.onEnter(element, position);
                            }

                        }

                        /* trigger tick event */
                        $(element).trigger('scrollTick', {
                            position: position,
                            inside: inside,
                            enters: enters,
                            leaves: leaves
                        })
                        if ($.isFunction(o.onTick)) {
                            o.onTick(element, position, inside, enters, leaves);
                        }
                    } else {

                        if (inside) {
                            inside = false;
                            leaves++;
                            /* trigger leave event */
                            $(element).trigger('scrollLeave', {position: position, leaves: leaves})

                            if ($.isFunction(o.onLeave)) {
                                o.onLeave(element, position);
                            }
                        }
                    }
                });

            });
        }

    })
})(jQuery, window, document, undefined);

/*!
 * jQuery outline Plugin
 * Author: @Lucien  etoahn@163.com
 */

;
(function ($) {
    "use strict";
    function createLink(idSuffix, text) {
        var link = document.createElement('a');
        link.href = '#outline_' + idSuffix;
        link.innerHTML = text;
        return link;
    }

    function createHeader(wrapDiv, element) {
        var header = document.createElement("h3");
        header.innerHTML = element.innerHTML;
        wrapDiv.appendChild(header);
    }

    function createOutline(id, elements, hasTitle) {
        var i = 0;//index of elements
        var content = $(id);
        var wrapDiv = content[0] || content;
        hasTitle && createHeader(wrapDiv, elements[i++]);

        var ul = document.createElement("ul");
        var len = elements.length;

        var li = document.createElement('li');
        var link = createLink(i, elements[i++].innerHTML);
        li.appendChild(link);
        ul.appendChild(li); //create first li element to compare

        for (; i < len; i++) {

            li = createElement(li, elements[i], elements[i - 1].nodeName, i)
        }

        wrapDiv.appendChild(ul);
        return wrapDiv;
    }

    function createElement(current, element, lastNodeName, index) {
        var link = createLink(index, element.innerHTML);
        var ul,
            li = document.createElement('li');
        li.appendChild(link);
        if (element.nodeName > lastNodeName)//eg. H3>H2
        {
            ul = document.createElement("ul");
            ul.appendChild(li);
            current.appendChild(ul);
        }
        else if (element.nodeName === lastNodeName) {
            current.parentNode.appendChild(li);
        }
        else {
            //当为ul时继续查找
            while (current.nodeName.toUpperCase() === 'UL' || (document.getElementById(current.firstChild.getAttribute('href').substring(1)).nodeName !== element.nodeName)) {
                if (current.parentNode) {
                    current = current.parentNode;
                }
                else {
                    //如果没有父节点，说明是顶层的ul，把当前元素置为顶层ul第一个子元素,方便插入
                    current = current.firstChild;
                    break;
                }

            }

            current.parentNode.appendChild(li);

        }
        return li;

    }

    function validate(option) {
        if (!option.contentSelector) {
            throw new TypeError("contentSelector is Required attribute");
        }
    }

    var ol = {
        outline: function (option) {

            validate(option);

            var option = $.extend({
                selector: 'body',  //css选择器，选择的范围
                hArray: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], //要识别的header
                addSpy: true,//是否添加滚动事件监听
                hasTitle: false, //范围内是否第一个是标题
                offset: 20 //偏离的位置
            }, option);

            var hSelector = option.hArray.join(',');
            var index = 0;

            //先生成outline,再在下一步添加监听
            $(option.selector).find(hSelector).each(function () {
                var id = 'outline_' + index++;
                this.setAttribute('id', id);
            });

            createOutline(option.contentSelector, $(option.selector).find(hSelector), option.hasTitle);
            if (option.addSpy) {
                $(option.selector).find(hSelector).each(function () {

                    //scrollspy
                    var $that = $(this);
                    var position = $that.position();
                    $that.scrollspy({

                        min: $that.offset().top - option.offset,
                        max: (function () {
                            var next = $that.nextAll(hSelector)[0];//下一个标题

                            return next ? $(next).offset().top : $that.offset().top;
                        })(),
                        onEnter: function (element, position) {
                            $('[href="#' + element.id + '"]').addClass("active-header");
                        },
                        onLeave: function (element, position) {
                            $('[href="#' + element.id + '"]').removeClass("active-header");
                        }
                    });
                });
            }

        }

    };

    $.extend(ol);

    /*data API*/

    if ($('[data-outline]')) {

        $.outline({contentSelector: '[data-outline]', selector: $('[data-outline]').data('outline')});

    }

})(jQuery);
/**
 * Created by Lucien on 7/14/2015.
 */

//$.outline({contentSelector:'#sub-outline',selector:'article',hasTitle:true});
<|endoftext|>


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

/**
 * Data structure for a fraction (possibly improper).
 *
 * NOTE: The common version of this class in the PhET Java code base has a number of additional methods.  These methods
 * should be ported into this file as needed.  Please see edu.colorado.phet.fractions.common.math.Fractions.java in the
 * PhET Java code base.
 *
 * @author John Blanco
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {number} numerator must be an integer
   * @param {number} denominator must be an integer
   * @constructor
   */
  function Fraction( numerator, denominator ) {
    assert && assert( Util.isInteger( numerator ) ) && assert( Util.isInteger( denominator ) );
    this.numerator = numerator;
    this.denominator = denominator;
  }

  return inherit( Object, Fraction, {

    // Floating-point error is not an issue as long as numerator and denominator are integers < 2^53
    getValue: function() {
      return this.numerator / this.denominator;
    },

    isInteger: function() {
      return Util.isInteger( this.getValue() );
    },

    toString: function() {
      return this.numerator + '/' + this.denominator;
    },

    reduce: function() {
      var gcd = Util.gcd( this.numerator, this.denominator );
      this.numerator = gcd === 0 ? 0 : Math.round( this.numerator / gcd );
      this.denominator = gcd === 0 ? 0 : Math.round( this.denominator / gcd );
    },

    equals: function( that ) {
      return this.numerator === that.numerator && this.denominator === that.denominator;
    }
  } );
} );<commit_msg>phetsims/tasks#275 replace Math.round with dot.Util.roundSymmetric<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Data structure for a fraction (possibly improper).
 *
 * NOTE: The common version of this class in the PhET Java code base has a number of additional methods.  These methods
 * should be ported into this file as needed.  Please see edu.colorado.phet.fractions.common.math.Fractions.java in the
 * PhET Java code base.
 *
 * @author John Blanco
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {number} numerator must be an integer
   * @param {number} denominator must be an integer
   * @constructor
   */
  function Fraction( numerator, denominator ) {
    assert && assert( Util.isInteger( numerator ) ) && assert( Util.isInteger( denominator ) );
    this.numerator = numerator;
    this.denominator = denominator;
  }

  return inherit( Object, Fraction, {

    // Floating-point error is not an issue as long as numerator and denominator are integers < 2^53
    getValue: function() {
      return this.numerator / this.denominator;
    },

    isInteger: function() {
      return Util.isInteger( this.getValue() );
    },

    toString: function() {
      return this.numerator + '/' + this.denominator;
    },

    reduce: function() {
      var gcd = Util.gcd( this.numerator, this.denominator );
      this.numerator = gcd === 0 ? 0 : Util.roundSymmetric( this.numerator / gcd );
      this.denominator = gcd === 0 ? 0 : Util.roundSymmetric( this.denominator / gcd );
    },

    equals: function( that ) {
      return this.numerator === that.numerator && this.denominator === that.denominator;
    }
  } );
} );<|endoftext|>


<commit_before>/*There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:
nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5*/

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    var target = nums1.length > nums2.length ? nums1 : nums2;
    var donator= nums1.length > nums2.length ? nums2 : nums1;

    var tstart = 0, tend = target.length;
    var dstart = 0, dend = donator.length;

    while(dend - dstart > 2){
    	if((dend - dstart) % 2 == 1){ //if donator is oddnumber
    		var dmiddle = parseInt((dend - dstart) / 2) + 1;

    		if((tend - tstart) % 2 == 1){
    			var tmiddle = parseInt((tend - tstart) / 2) + 1;

    			if(target[tmiddle] > dmiddle[dmiddle]){ // 1/3/*5*/7/9 & 2/*4*/6
    				tstart -= (dmiddle - dstart);
    				dstart = dmiddle;
    			}
    			else{									// 1/3/*5*/7/9 & 4/*6*/8
    				tend += (dend - dmiddle + 1);
    				dend = dmiddle + 1;
    			}
    		}
    		else{
    			var tmiddle = [parseInt((tend - tstart) / 2) - 1, parseInt((tend - tstart) / 2)];

    			// 1/3/*5/7*/9/11 & 4/*6*/8 => 6
    			if(target[tmiddle[0]] <= donator[dmiddle] && donator[dmiddle] <= target[tmiddle[1]] )
    				return donator[dmiddle];
    			// 1/3/*5/7*/9/11 & 2/*4*/6
    			else if(target[tmiddle[0]] > donator[dmiddle]){
    				tstart -= (dmiddle - dstart);
    				dstart = dmiddle;
    			}
    			// 1/3/*5/7*/9/11 & 6/*8*/10
    			else{
    				tend += (dend - dmiddle + 1);
    				dend = dmiddle + 1;
    			}
    		}
    	}
    	else{ //if dnoator is even number
            var dmiddle = [parseInt((dend - dstart) / 2) - 1, parseInt((dend - dstart) / 2)];
            if((tend - tstart) % 2 == 1){
                var tmiddle = parseInt((tend - tstart) / 2) + 1;

                // 1/3/*5*/7/9 2/*4/6*/8
                if(donator[dmiddle[0]] <= target[tmiddle] && target[tmiddle] <= donator[dmiddle[1]] )
                    return target[tmiddle];
                // 1/3/*5*/7/9 4/*6/8*/10
                else if(tmiddle < donator[dmiddle[0]]){
                    tend += (dend - dmiddle[1] + 1);
                    dend = dmiddle[1] + 1;
                }
            }
    	}
    }
    if(dend - dstart == 2){

    }
    else if(dend - dstart == 1){

    }
    else{	//dend - dstart === 0

    }
};

var calc = function(num1, num2){
	var sortby = function(l, r){return l - r;}
	var sum = num1.concat(num2).sort(sortby);
	console.log(sum);
	if(sum.length % 2 == 1)
		return sum[parseInt(sum.length/2)];
	else
		return (sum[parseInt(sum.length/2) - 1] + sum[parseInt(sum.length/2)])/2;
};

QUnit.test( "Example", function( assert ) {
	var num1   = [1, 3];
	var num2   = [2];
	var expect = calc(num1, num2);
	var result = findMedianSortedArrays(num1, num2);

	assert.ok(( expect == result ),	"Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
	var num1   = [1, 3, 5, 7];
	var num2   = [2, 4, 6, 8];
	var expect = calc(num1, num2);
	var result = findMedianSortedArrays(num1, num2);

	assert.ok(( expect == result ),	"Expect:" + expect + ", Result:" + result);
});<commit_msg>leetcode add No.4<commit_after>/*There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:
nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5*/

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {
    var target = nums1.length > nums2.length ? nums1 : nums2;
    var donator= nums1.length > nums2.length ? nums2 : nums1;
    debugger;

    var tstart = 0, tend = target.length;
    var dstart = 0, dend = donator.length;

    while(dend - dstart > 2){
    	if((dend - dstart) % 2 == 1){ //if donator is oddnumber
    		var dmiddle = parseInt((dend + dstart) / 2);

    		if((tend - tstart) % 2 == 1){
    			var tmiddle = parseInt((tend + tstart) / 2);

    			if(target[tmiddle] > donator[dmiddle]){ // 1/3/*5*/7/9 & 2/*4*/6
    				tstart -= (dmiddle - dstart);
    				dstart = dmiddle;
    			}
    			else{									// 1/3/*5*/7/9 & 4/*6*/8
    				tend += (dend - dmiddle - 1);
    				dend = dmiddle + 1;
    			}
    		}
    		else{
    			var tmiddle = [parseInt((tend + tstart) / 2) - 1, parseInt((tend + tstart) / 2)];

    			// 1/3/*5/7*/9/11 & 4/*6*/8 => 6
    			if(target[tmiddle[0]] <= donator[dmiddle] && donator[dmiddle] <= target[tmiddle[1]] )
    				return donator[dmiddle];
    			// 1/3/*5/7*/9/11 & 2/*4*/6
    			else if(target[tmiddle[0]] > donator[dmiddle]){
    				tstart -= (dmiddle - dstart);
    				dstart = dmiddle;
    			}
    			// 1/3/*5/7*/9/11 & 6/*8*/10
    			else{
    				tend += (dend - dmiddle - 1);
    				dend = dmiddle + 1;
    			}
    		}
    	}
    	else{ //if donator is even number
            var dmiddle = [parseInt((dend + dstart) / 2) - 1, parseInt((dend + dstart) / 2)];
            if((tend - tstart) % 2 == 1){
                var tmiddle = parseInt((tend + tstart) / 2);

                // d t d
                if(donator[dmiddle[0]] <= target[tmiddle] && target[tmiddle] <= donator[dmiddle[1]] )
                    return target[tmiddle];
                // t d d -> remove d's tail
                else if(target[tmiddle] <= donator[dmiddle[0]]){
                    tend += (dend - dmiddle[1] - 1);
                    dend = dmiddle[1] + 1;
                }
                // d d t -> remove d's head
                else {
                    tstart -= (dmiddle[0] - dstart);
                    dstart = dmiddle[0];
                }
            }
            else {
                var tmiddle = [parseInt((tend + tstart) / 2) - 1, parseInt((tend + tstart) / 2)];

                //t d d t
                if(target[tmiddle[0]] <= donator[dmiddle[0]] && donator[dmiddle[1]] <= target[tmiddle[1]])
                    return (donator[dmiddle[0]] + donator[dmiddle[1]]) / 2;
                //d t t d
                else if (donator[dmiddle[0]] <= target[tmiddle[0]] && target[tmiddle[1]] <= donator[dmiddle[1]])
                    return (target[tmiddle[0]] + target[tmiddle[1]]) / 2;
                // t d t d || t t d d
                // 1 *3* *5* 7 & 2 *4* *6* 8
                // everynumber > donator[dmiddle[1]] is useless
                else if (target[tmiddle[1]] <= donator[dmiddle[1]]) {
                    tend += (dend - dmiddle[1] - 1);
                    dend = dmiddle[1] + 1;
                }
                // d t d t || d d t t
                else{
                    tstart -= (dmiddle[0] - dstart);
                    dstart = dmiddle[0];
                }
            }
    	}
    }
    if(dend - dstart == 2){
        if((tend - tstart) % 2 == 1){ //2 odds
            var dmiddle = [dstart, dstart + 1];
            var tmiddle = parseInt((tend + tstart) / 2);
            // d t d
            if(donator[dmiddle[0]] <= target[tmiddle] &&
                target[tmiddle] <= donator[dmiddle[1]])
                return target[tmiddle];
            else if(donator[dmiddle[1]] <= target[tmiddle]){
                // d d t || d tx d t
                if(tmiddle == 0 || target[tmiddle - 1] <= donator[dmiddle[1]])
                    return donator[dmiddle[1]];
                // d d tx t
                else
                    return target[tmiddle - 1];
            }
            else{
                // t d d || t d tx d
                if(tmiddle == target.length - 1 || donator[dmiddle[0]] <= target[tmiddle + 1])
                    return donator[dmiddle[0]];
                else
                    return target[tmiddle + 1];
            }

        }
        else {
            var dmiddle = [dstart, dstart + 1];
            var tmiddle = [parseInt((tend + tstart) / 2) - 1, parseInt((tend + tstart) / 2)];

            // d t d t
            if(donator[dmiddle[0]] <= target[tmiddle[0]]
                && target[tmiddle[0]] <= donator[dmiddle[1]]
                && donator[dmiddle[1]] <= target[tmiddle[1]]){
                return (target[tmiddle[0]] + donator[dmiddle[1]])/2;
            }
            // t d t d
            else if(target[tmiddle[0]] <= donator[dmiddle[0]]
                && donator[dmiddle[0]] <= target[tmiddle[1]]
                && target[tmiddle[1]] <= donator[dmiddle[1]] ){
                return (donator[dmiddle[0]] + target[tmiddle[1]])/2;
            }
            // t d d t
            else if(target[tmiddle[0]] <= donator[dmiddle[0]]
                && donator[dmiddle[1]] <= target[tmiddle[1]]){
                return (donator[dmiddle[0]] + donator[dmiddle[1]]) / 2;
            }
            // d t t d
            else if(donator[dmiddle[0]] <= target[tmiddle[0]]
                && target[tmiddle[1]] <= donator[dmiddle[1]]){
                return (target[tmiddle[0]] + target[tmiddle[1]]) / 2;
            }
            else if(target[tmiddle[1]] <= donator[dmiddle[0]]){
                // t t tX d d
                if(tmiddle[1] < target.length - 1 && target[tmiddle[1] + 1] <= donator[0])
                    return (target[tmiddle[1]] + target[tmiddle[1] + 1]) / 2;
                // t t d d
                else
                    return (target[tmiddle[1]] + donator[dmiddle[0]]) / 2;
            }
            else if(donator[dmiddle[1]] < target[tmiddle[0]]){
                // d d tX t t
                if(tmiddle[0] > 0 && donator[dmiddle[1]] <= target[tmiddle[0] - 1])
                    return (target[tmiddle[0] - 1] + target[tmiddle[0]]) / 2;
                // d d t t
                else
                    return (donator[dmiddle[1]] + target[tmiddle[0]]) / 2;
            }

        }
    }
    else if(dend - dstart == 1){
        var dmiddle = dstart;

        if((tend - tstart) % 2 == 1){ //2 odds
            var tmiddle = parseInt((tend + tstart) / 2);

            // d tx t
            if(tmiddle > 0 && donator[dmiddle] <= target[tmiddle - 1])
                return (target[tmiddle - 1] + target[tmiddle]) / 2;
            // t tx d
            else if(tmiddle < target.length - 1 && target[tmiddle + 1] <= donator[dmiddle])
                return (target[tmiddle] + target[tmiddle + 1]) / 2;
            // t d
            else
                return (target[tmiddle] + donator[dmiddle]) / 2;
        }
        else{
            var tmiddle = [parseInt((tend + tstart) / 2) - 1, parseInt((tend + tstart) / 2)];

            if(donator[dmiddle] < target[tmiddle[0]]) // d t t
                return target[tmiddle[0]];
            else if(target[tmiddle[1]] < donator[dmiddle]) // t t d
                return target[tmiddle[1]];
            else
                return donator[dmiddle];     //t d t
        }
    }
    else{	//dend - dstart === 0
        if((tend - tstart) % 2 == 1){ //odd
            var tmiddle = parseInt((tend + tstart) / 2);
            return target[tmiddle];
        }
        else{
            var tmiddle = [parseInt((tend + tstart) / 2) - 1, parseInt((tend + tstart) / 2)];
            return (target[tmiddle[0]] + target[tmiddle[1]]) / 2;
        }
    }
};
/*--------------------------------------------------------------------------------------*/
var calc = function(num1, num2){
	var sortby = function(l, r){return l - r;}
	var sum = num1.concat(num2).sort(sortby);
	//console.log(sum);
	if(sum.length % 2 == 1)
		return sum[parseInt(sum.length/2)];
	else
		return (sum[parseInt(sum.length/2) - 1] + sum[parseInt(sum.length/2)])/2;
};
/*--------------------------------------------------------------------------------------*/
QUnit.test( "Example", function( assert ) {
    var num1   = [4,38,50];
    var num2   = [1,66,95];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result + "[" + num1.toString() +"] [" + num2.toString() + "]");
});

var sortby = function(l, r){return l - r;}
for(let i = 1; i < 10; i++){
    for(let j = 1; j < 10; j++){
        for(let k = 0; k < 5; k ++){
            let r = [];
            let l = [];
            for(let di = 0; di < i; di++)
                r.push(parseInt(Math.random() * 100));
            for(let dj = 0; dj < j; dj++)
                l.push(parseInt(Math.random() * 100));

            r.sort(sortby);
            l.sort(sortby);

            //debugger;
            QUnit.test( "" + i + "." + j + "." + k , function( assert ) {
                var num1   = r;
                var num2   = l;
                console.log("" + i + "." + j + "." + k + ":[" + r.toString() + "] [" + l.toString() + "]")
                var expect = calc(num1, num2);
                var result = findMedianSortedArrays(num1, num2);

                assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result + "[" + r.toString() +"][" + l.toString() + "]");
            });
        }
    }
}

QUnit.test( "Example", function( assert ) {
    var num1   = [45,76];
    var num2   = [5,13,17,37,74];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result + "[" + num1.toString() +"] [" + num2.toString() + "]");
});

QUnit.test( "Example", function( assert ) {
    var num1   = [6,25,32,37,49,74,76,95];
    var num2   = [3,3,68,71,72,88,99];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example", function( assert ) {
    var num1   = [6,25,32,37,49,74,76,95];
    var num2   = [3,3,68,71,72,88,99];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example", function( assert ) {
    var num1   = [27, 29];
    var num2   = [20, 42, 64, 68, 93];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var r   = [2, 4];
    var l   = [1, 3];
    var expect = calc(r, l);
    var result = findMedianSortedArrays(r, l);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result + "[" + r.toString() +  +"][" + l.toString() + "]");
});

QUnit.test( "Example", function( assert ) {
    var num1   = [1, 3];
    var num2   = [2];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1, 3, 5, 7];
    var num2   = [2, 4, 6, 8];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1, 3, 5, 7, 9];
    var num2   = [2, 4, 6, 8];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1, 3, 5, 7, 9, 11];
    var num2   = [2, 4, 6, 8];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1];
    var num2   = [2];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1];
    var num2   = [2, 3, 4, 5, 6];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1, 2];
    var num2   = [2, 3];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});

QUnit.test( "Example2", function( assert ) {
    var num1   = [1, 2];
    var num2   = [1, 2, 3];
    var expect = calc(num1, num2);
    var result = findMedianSortedArrays(num1, num2);

    assert.ok(( expect == result ), "Expect:" + expect + ", Result:" + result);
});<|endoftext|>


<commit_before>'use strict';

var _              = require('mano').i18n.bind('User')
  , loginDialog    = require('./_user-login-dialog')
  , registerDialog = require('./_user-register-dialog')
  , modalContainer = require('./_modal-container');

exports._parent = require('./base');

exports.menu = function () {
	modalContainer.append(loginDialog);
	modalContainer.append(registerDialog(this));

	insert(_if(this.user._isDemo,
		div(
			{ class: 'submitted-menu-demo-info-wrapper' },
			ul({ class: 'header-top-menu-demo' },
				li(a({ class: 'demo-public-out', href: '/logout/', rel: 'server' }, _("Out of demo mode"))),
				li(a({ class: 'demo-public-login', href: '#login' }, _("Log in")))),
			div({ class: 'submitted-menu-demo-info' },
				p(_("Did this demo convinced you?")),
				a({ href: '#register' }, _("Create account")))
		),
		ul(
			{ class: 'header-top-menu' },
			li(
				a(
					{ href: '/profile/' },
					span({ class: 'header-top-user-name' }, this.user._fullName)
				)
			),
			li(
				a(
					{ href: '/profile/' },
					span({ class: 'fa fa-cog' }, "Preferences")
				)
			),
			li(
				a(
					{ href: '/logout/', rel: 'server' },
					span({ class: 'fa fa-power-off' }, "Log out")
				)
			)
		)));
};

exports.main = function () {

	div({ class: 'submitted-menu' },
		div({ class: 'submitted-menu-bar content' },
			nav(ul({ class: 'submitted-menu-items', id: 'submitted-menu' },
				exports._submittedMenu(this))),
			_if(this.user._isDemo, div({ class: 'submitted-menu-demo' },
				a({ class: 'submitted-menu-demo-ribon' }, _("Demo"))))));

	insert(_if(this.user._isDemo,
		div({ class: 'submitted-menu-demo-msg' },
			div({ class: 'content' },
				h3(_("Demo version")),
				p(_("Introduction to demo version"))))));

	insert(_if(this.managedUser, function () {
		return div({ class: 'manager-bar' },
			div({ class: 'content' },
				div(
					span(_('Client:')),
					span(this.managedUser._fullName)
				),
				div(_if(not(this.managedUser.roles._has('user')),
						postButton({ buttonClass: 'actions-create',
							action: url('clients', this.managedUser.__id__, 'create'),
							value: span(_('Create account for this client')) })))
				));
	}.bind(this)));

	div({ class: 'user-forms', id: 'sub-main' });
};

exports._submittedMenu = Function.prototype;
<commit_msg>Add class to div<commit_after>'use strict';

var _              = require('mano').i18n.bind('User')
  , loginDialog    = require('./_user-login-dialog')
  , registerDialog = require('./_user-register-dialog')
  , modalContainer = require('./_modal-container');

exports._parent = require('./base');

exports.menu = function () {
	modalContainer.append(loginDialog);
	modalContainer.append(registerDialog(this));

	insert(_if(this.user._isDemo,
		div(
			{ class: 'submitted-menu-demo-info-wrapper' },
			ul({ class: 'header-top-menu-demo' },
				li(a({ class: 'demo-public-out', href: '/logout/', rel: 'server' }, _("Out of demo mode"))),
				li(a({ class: 'demo-public-login', href: '#login' }, _("Log in")))),
			div({ class: 'submitted-menu-demo-info' },
				p(_("Did this demo convinced you?")),
				a({ href: '#register' }, _("Create account")))
		),
		ul(
			{ class: 'header-top-menu' },
			li(
				a(
					{ href: '/profile/' },
					span({ class: 'header-top-user-name' }, this.user._fullName)
				)
			),
			li(
				a(
					{ href: '/profile/' },
					span({ class: 'fa fa-cog' }, "Preferences")
				)
			),
			li(
				a(
					{ href: '/logout/', rel: 'server' },
					span({ class: 'fa fa-power-off' }, "Log out")
				)
			)
		)));
};

exports.main = function () {

	div({ class: 'submitted-menu' },
		div({ class: 'submitted-menu-bar content' },
			nav(ul({ class: 'submitted-menu-items', id: 'submitted-menu' },
				exports._submittedMenu(this))),
			_if(this.user._isDemo, div({ class: 'submitted-menu-demo' },
				a({ class: 'submitted-menu-demo-ribon' }, _("Demo"))))));

	insert(_if(this.user._isDemo,
		div({ class: 'submitted-menu-demo-msg' },
			div({ class: 'content' },
				h3(_("Demo version")),
				p(_("Introduction to demo version"))))));

	insert(_if(this.managedUser, function () {
		return div({ class: 'manager-bar' },
			div({ class: 'content' },
				div(
					span(_('Client:')),
					span(this.managedUser._fullName)
				),
				div({ class: 'manager-bar-actions' },
					_if(not(this.managedUser.roles._has('user')),
						postButton({ buttonClass: 'actions-create',
							action: url('clients', this.managedUser.__id__, 'create'),
							value: span(_('Create account for this client')) })))
				));
	}.bind(this)));

	div({ class: 'user-forms', id: 'sub-main' });
};

exports._submittedMenu = Function.prototype;
<|endoftext|>


<commit_before>// ========================================================================
// SproutCore
// copyright 2006-2008 Sprout Systems, Inc.
// ========================================================================

require('views/view') ;

/**
  @class

  ProgressView displays a progress bar.  It does this mostly through CSS
  classes so that you can style them however you want.  A progress bar must
  have the following structure:

  The outer can form the boundary of the bar while the inner will be adjusted
  to fit the percentage of the progress.

  Style the progress bar with the following CSS classes:

  .progress.indeterminate = to show an indeterminate progress. inner will
      be set to fill 100%
  .progress.disabled = show as disabled.

  @extends SC.View
*/
SC.ProgressView = SC.View.extend({

  // ........................................
  // PROPERTIES
  //

  /**
    The minimum value of the progress.
  */
  minimum: 0,

  /**
    The maximum value of the progress bar.
  */
  maximum: 1.0,

  /**
    Bind this to the current value of the progress bar.  Note that by default an
    empty value will disable the progress bar and a multiple value too make it
    indeterminate.
  */
  value: 0.50,
  valueBindingDefault: SC.Binding.SingleNotEmpty,

  /**
    Set to true if the item in progress is indeterminate.  This may be overridden
    by the actual value.
    @returns {Boolean}
  */
  isIndeterminate: function(key,value) {
    if (value !== undefined) {
      this._isIndeterminate = value ;
    }
    return this._isIndeterminate && (this.value != SC.Binding.EMPTY_PLACEHOLDER) ;
  }.property(),

  /**
   Set to false to disable the progress bar.
   @returns {Boolean}
  */
  isEnabled: function(key, value) {
    if (value !== undefined) {
      this._isEnabled = value ;
    }
    return this._isEnabled && (this.value != SC.Binding.MULTIPLE_PLACEHOLDER) ;
  }.property(),

  _isIndeterminate: false, _isEnabled: true,

  // ........................................
  // STRUCTURE
  //

  emptyElement: '

',

  outlets: ['innerView'],
  innerView: SC.View.outletFor('.inner?'),

  // ........................................
  // INTERNAL SUPPORT
  //

  propertyObserver: function(observing,target,key,value) {
    // collect new settings.
    if (['value','minimum','maximum','isIndeterminate','isEnabled'].include(key)) {
      var isIndeterminate = this.get('isIndeterminate') ;
      var isEnabled = this.get('isEnabled') ;

      Element.setClassName(this,'indeterminate',isIndeterminate) ;
      Element.setClassName(this,'disabled',!isEnabled) ;

      // compute value for setting the width of the inner progress
      var value ;
      if (!isEnabled) {
        value = 0.0 ;
      } else if (isIndeterminate) {
        value = 1.0;
      }else {
        var minimum = this.get('minimum') || 0.0 ;
        var maximum = this.get('maximum') || 1.0 ;
        value = this.get('value') || 0.0 ;
        value = (value - minimum) / (maximum - minimum) ;
        if (value > 1.0) value = 1.0 ;
      }
      value = value * 100 ;
      if (this.innerView) this.innerView.setStyle({ width: (value + '%') }) ;
    }
  }
}) ;

<commit_msg><rdar://problem/6054767> IE7: Unable to upload a file<commit_after>// ========================================================================
// SproutCore
// copyright 2006-2008 Sprout Systems, Inc.
// ========================================================================

require('views/view') ;

/**
  @class

  ProgressView displays a progress bar.  It does this mostly through CSS
  classes so that you can style them however you want.  A progress bar must
  have the following structure:

  The outer can form the boundary of the bar while the inner will be adjusted
  to fit the percentage of the progress.

  Style the progress bar with the following CSS classes:

  .progress.indeterminate = to show an indeterminate progress. inner will
      be set to fill 100%
  .progress.disabled = show as disabled.

  @extends SC.View
*/
SC.ProgressView = SC.View.extend({

  // ........................................
  // PROPERTIES
  //

  /**
    The minimum value of the progress.
  */
  minimum: 0,

  /**
    The maximum value of the progress bar.
  */
  maximum: 1.0,

  /**
    Bind this to the current value of the progress bar.  Note that by default an
    empty value will disable the progress bar and a multiple value too make it
    indeterminate.
  */
  value: 0.50,
  valueBindingDefault: SC.Binding.SingleNotEmpty,

  /**
    Set to true if the item in progress is indeterminate.  This may be overridden
    by the actual value.
    @returns {Boolean}
  */
  isIndeterminate: function(key,value) {
    if (value !== undefined) {
      this._isIndeterminate = value ;
    }
    return this._isIndeterminate && (this.value != SC.Binding.EMPTY_PLACEHOLDER) ;
  }.property(),

  /**
   Set to false to disable the progress bar.
   @returns {Boolean}
  */
  isEnabled: function(key, value) {
    if (value !== undefined) {
      this._isEnabled = value ;
    }
    return this._isEnabled && (this.value != SC.Binding.MULTIPLE_PLACEHOLDER) ;
  }.property(),

  _isIndeterminate: false, _isEnabled: true,

  // ........................................
  // STRUCTURE
  //

  emptyElement: '

',

  outlets: ['innerView'],
  innerView: SC.View.outletFor('.inner?'),

  // ........................................
  // INTERNAL SUPPORT
  //

  propertyObserver: function(observing,target,key,value) {
    // collect new settings.
    if (['value','minimum','maximum','isIndeterminate','isEnabled'].include(key)) {
      var isIndeterminate = this.get('isIndeterminate') ;
      var isEnabled = this.get('isEnabled') ;

      this.setClassName('indeterminate',isIndeterminate);
      this.setClassName('disabled',!isEnabled);

      // compute value for setting the width of the inner progress
      var value ;
      if (!isEnabled) {
        value = 0.0 ;
      } else if (isIndeterminate) {
        value = 1.0;
      }else {
        var minimum = this.get('minimum') || 0.0 ;
        var maximum = this.get('maximum') || 1.0 ;
        value = this.get('value') || 0.0 ;
        value = (value - minimum) / (maximum - minimum) ;
        if (value > 1.0) value = 1.0 ;
      }
      if(isNaN(value))
        value = 0.0;
      value = value * 100 ;
      if (this.innerView) this.innerView.setStyle({ width: (value + '%') }) ;
    }
  }
}) ;

<|endoftext|>


<commit_before>/*Installed by the InputFieldPrompt plugin. Check the readme for more details.

	Author: Forrest Zeisler
	February 27, 2009
*/

var PROMPT_CLASS = "prompt"

function add_prompt(input,value)
{
  input_item = Element.extend(input);
  input_item.writeAttribute("prompt",value);
  input.observe('focus',prompt_onfocus);
  input.observe('blur',prompt_onblur);
  prompt_onblur(input);
}

function prompt_onblur(event_or_input)
{
  if(Object.isElement(event_or_input))
    input = event_or_input;
  else
    input = event_or_input.element();
  value = input.readAttribute("prompt").strip();
  current = $F(input).strip();

  //if it is the default value set to grey
  if(current==value || current.length==0)
      input.addClassName(PROMPT_CLASS);

  //if it is not a select field set the value to the default
  if(input.tagName!="SELECT" && current.length==0)
      input.value = value;
}

function prompt_onfocus(event)
{
  input = event.element();
  value = input.readAttribute("prompt").strip();
  current = $F(input).strip();
  if(current==value)
      input.value = "";
  input.removeClassName(PROMPT_CLASS);
}

function add_tab_label(input)
{
  input_item = Element.extend(input);
  input_item.writeAttribute("prompt",value);
  input.observe('focus',tab_label_onfocus);
  input.observe('blur',tab_label_onblur);
}

function tab_label_onfocus(event)
{
  input = event.element();
  label_div = input.previous("div");
  if(!label_div.hasClassName("tab_label"))
    return;
  label_div.clonePosition(input,{setLeft:true, setTop:true, setWidth:true, setHeight:true});
  label_div.show();
}

function tab_label_onblur(event)
{
  input = event.element();
  label_div = input.previous("div");
  if(!label_div.hasClassName("tab_label"))
    return;
  label_div.hide();
}

function enforce_textarea_maxlength(textarea,count)
{
    textarea = Element.extend(textarea);
    ml = $(textarea).getAttribute('maxlength');
    if(!ml)
        return;
    v = $F($(textarea));

    if(v.gsub(/\n/,"
").length>ml)
    {
      st = $(textarea).scrollTop;
      $(textarea).value = (v.truncate(ml,""));
      $(textarea).scrollTop = st;
    }

    new_v = $F($(textarea));
	if(textarea.readAttribute("prompt") && new_v==textarea.readAttribute("prompt").strip())
		new_v = "";
    if(count)
	{
		left = ml-new_v.length;
		count.update(left);
		if(left==0)
			count.addClassName("full_counter");
		else if(left<=10)
		{
			count.removeClassName("full_counter");
			count.addClassName("last_ten");
		}
		else
		{
			count.removeClassName("full_counter");
			count.removeClassName("last_ten");
		}
	}

    return;
}
<commit_msg>prompt fields now add an attribute when prompt is added. Also the value field is set if the field is empty. This lets the field keep it's default value when the form is reset<commit_after>/*Installed by the InputFieldPrompt plugin. Check the readme for more details.

	Author: Forrest Zeisler
	February 27, 2009
*/

var PROMPT_CLASS = "prompt"

function add_prompt(input,value)
{
  input_item = Element.extend(input);
  input_item.writeAttribute("prompt",value);
  input.observe('focus',prompt_onfocus);
  input.observe('blur',prompt_onblur);
  input_item.writeAttribute("promptAdded",true);
  if(input_item.readAttribute("value")==null || input_item.readAttribute("value")=="")
     input_item.writeAttribute("value",value);
  prompt_onblur(input);
}

function prompt_onblur(event_or_input)
{
  if(Object.isElement(event_or_input))
    input = event_or_input;
  else
    input = event_or_input.element();
  value = input.readAttribute("prompt").strip();
  current = $F(input).strip();

  //if it is the default value set to grey
  if(current==value || current.length==0)
      input.addClassName(PROMPT_CLASS);

  //if it is not a select field set the value to the default
  if(input.tagName!="SELECT" && current.length==0)
      input.value = value;
}

function prompt_onfocus(event)
{
  input = event.element();
  value = input.readAttribute("prompt").strip();
  current = $F(input).strip();
  if(current==value)
      input.value = "";
  input.removeClassName(PROMPT_CLASS);
}

function add_tab_label(input)
{
  input_item = Element.extend(input);
  input_item.writeAttribute("prompt",value);
  input.observe('focus',tab_label_onfocus);
  input.observe('blur',tab_label_onblur);
}

function tab_label_onfocus(event)
{
  input = event.element();
  label_div = input.previous("div");
  if(!label_div.hasClassName("tab_label"))
    return;
  label_div.clonePosition(input,{setLeft:true, setTop:true, setWidth:true, setHeight:true});
  label_div.show();
}

function tab_label_onblur(event)
{
  input = event.element();
  label_div = input.previous("div");
  if(!label_div.hasClassName("tab_label"))
    return;
  label_div.hide();
}

function enforce_textarea_maxlength(textarea,count)
{
    textarea = Element.extend(textarea);
    ml = $(textarea).getAttribute('maxlength');
    if(!ml)
        return;
    v = $F($(textarea));

    if(v.gsub(/\n/,"
").length>ml)
    {
      st = $(textarea).scrollTop;
      $(textarea).value = (v.truncate(ml,""));
      $(textarea).scrollTop = st;
    }

    new_v = $F($(textarea));
	if(textarea.readAttribute("prompt") && new_v==textarea.readAttribute("prompt").strip())
		new_v = "";
    if(count)
	{
		left = ml-new_v.length;
		count.update(left);
		if(left==0)
			count.addClassName("full_counter");
		else if(left<=10)
		{
			count.removeClassName("full_counter");
			count.addClassName("last_ten");
		}
		else
		{
			count.removeClassName("full_counter");
			count.removeClassName("last_ten");
		}
	}

    return;
}
<|endoftext|>