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

/**
 * Model container for the level screen.
 *
 * @author Anton Ulyanov, Andrey Zelenkov (Mlearner)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );
  var SingleShapeModel = require( 'FRACTION_MATCHER/model/SingleShapeModel' );

  function LevelModel( gameModel, levelDescription, levelNumber ) {
    this.gameModel = gameModel;
    this.levelNumber = levelNumber;
    this.levelDescription = levelDescription;

    PropertySet.call( this, {
      score: 0,
      time: 0,
      stepScore: 2,
      answers: [], //shapes, which moved to answer zone
      lastPair: [-1, -1], //pair of shapes on scales, user can't compare the same pair two times
      lastChangedZone: -1, //when showing correct answer, change only last dragged shape position
      shapes: [], //array of SingleShapeModels
      canDrag: true,
      buttonStatus: "none" // ['none','ok','check','tryAgain','showAnswer']
    } );

    this.dropZone = []; //contains indexes of shapes, which are placed in current zone, -1 if empty

    for ( var i = 0; i < 2 * this.gameModel.MAXIMUM_PAIRS; i++ ) {
      this.dropZone[i] = -1;
    }

    //two more dropZones 12 and 13 - scales
    this.dropZone.push( -1 );
    this.dropZone.push( -1 );

    this.generateLevel();
  }

  inherit( PropertySet, LevelModel, {
    reset: function() {
      PropertySet.prototype.reset.call( this );
      this.generateLevel();
      for ( var i = 0; i < this.dropZone.length; i++ ) {
        this.dropZone[i] = -1;
      }
      this.answers = [];
      this.lastPair = [-1, -1];
    },
    step: function( dt ) {
      if ( this.gameModel.isTimer ) {
        this.time += dt;
      }
    },
    // return filtered shapes set for the selected denominator, from java model
    filterShapes: function( shapes, d ) {
      var arr = shapes.slice( 0 ),
        map = [
          true, // PIES
            d < 9, // HORIZONTAL_BARS
            d < 9, // VERTICAL_BARS
            d === 6, // PLUSES
            d === 4 || d === 9, // GRID
            d === 1 || d === 4 || d === 9, // PYRAMID
            d >= 3, // POLYGON
            d === 4, // TETRIS
            d === 6, // FLOWER
            d % 2 === 0, // LETTER_L_SHAPES
            d === 2 || d === 4, // INTERLEAVED_L_SHAPES
            d === 7, // RING_OF_HEXAGONS
            d === 8  // NINJA_STAR
        ],
        index;

      // move through all shapes and check it
      this.gameModel.CONSTANTS.SHAPES.forEach( function( shape, i ) {
        index = arr.indexOf( shape );
        if ( !map[i] && index !== -1 ) {
          arr.splice( index, 1 );
        }
      } );

      return arr;
    },
    // generate new level
    generateLevel: function() {
      var fractions = _.shuffle( this.levelDescription.fractions.slice( 0 ) ).splice( 0, this.gameModel.MAXIMUM_PAIRS ), //get random MAXIMUM_PAIRS fractions
        numericScaleFactors = this.levelDescription.numericScaleFactors.slice( 0 ), //scaleFactors to multiply fractions
        numberType = 'NUMBER',
        newShapes = [];

      var shapesAll = this.levelDescription.shapes.slice( 0 ); // get possible shapes for selected level
      shapesAll.push( numberType ); // add fractions to possible shapes

      // add shapes
      for ( var i = 0; i < this.gameModel.MAXIMUM_PAIRS; i++ ) {
        var fraction = fractions[i]; // [numerator, denominator] pair
        var shapes = this.filterShapes( shapesAll, fraction[1] ); //filter only shapes for current denominator
        var scaleFactor = numericScaleFactors[_.random( numericScaleFactors.length - 1 )]; //random scaleFactor
        var fillType = this.levelDescription.fillType[_.random( this.levelDescription.fillType.length - 1 )];

        // first 3 fractions - number, last 3 fractions - shapes with different colors (3 numbers and 3 shapes at least)
        var type = (i < this.gameModel.MAXIMUM_PAIRS / 2) ? numberType : shapes[ i % (shapes.length - 1) ];
        var color = (type === numberType) ? 'rgb(0,0,0)' : this.gameModel.colorScheme[i % 3];
        newShapes.push( new SingleShapeModel( type, fraction, scaleFactor, color, fillType, this.gameModel.toSimplify ) );

        // add partner: if was number - add shape, if was shape - add number or shape with another color
        type = shapes[_.random( shapes.length - (type === numberType ? 2 : 1) )];
        color = (type === numberType) ? 'rgb(0,0,0)' : this.gameModel.colorScheme[(i + 1) % 3];
        newShapes.push( new SingleShapeModel( type, fraction, scaleFactor, color, fillType, this.gameModel.toSimplify ) );
      }

      newShapes = _.shuffle( newShapes );
      for ( i = 0; i < newShapes.length; i++ ) {
        newShapes[i].dropZone = i;
      }

      this.shapes = newShapes;
    },
    answerButton: function( buttonName ) {
      var self = this;
      switch( buttonName ) { //['none','ok','check','tryAgain','showAnswer']
        case "ok":
          this.lastChangedZone = -1;
          self.stepScore = 2;
          this.canDrag = true;
          this.buttonStatus = "none";
          if ( self.answers.length === self.gameModel.MAXIMUM_PAIRS ) {
            self.hiScore = Math.max( self.hiScore, self.score );
          }
          break;
        case "check":
          if ( self.isShapesEqual( self.shapes[this.dropZone[12]], self.shapes[this.dropZone[13]] ) ) {
            //answer correct
            this.buttonStatus = "ok";
            self.score += self.stepScore;
            if ( self.gameModel.isSound ) {
              self.gameModel.sounds.correct.play();
            }
          }
          else {
            //answer incorrect
            if ( self.gameModel.isSound ) {
              self.gameModel.sounds.incorrect.play();
            }
            self.stepScore--;
            this.buttonStatus = (self.stepScore) ? "tryAgain" : "showAnswer";
          }
          this.canDrag = false;
          break;
        case "tryAgain" :
          this.canDrag = true;
          this.buttonStatus = "none";
          break;
        case "showAnswer" :
          this.buttonStatus = "ok";
          break;
      }
    },
    isShapesEqual: function( shape1, shape2 ) {
      return Math.abs( shape1.getAnswer() - shape2.getAnswer() ) < 0.001;
    }
  } );

  return LevelModel;
} );
<commit_msg>fixed #13<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Model container for the level screen.
 *
 * @author Anton Ulyanov, Andrey Zelenkov (Mlearner)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );
  var SingleShapeModel = require( 'FRACTION_MATCHER/model/SingleShapeModel' );

  function LevelModel( gameModel, levelDescription, levelNumber ) {
    this.gameModel = gameModel;
    this.levelNumber = levelNumber;
    this.levelDescription = levelDescription;

    PropertySet.call( this, {
      score: 0,
      time: 0,
      stepScore: 2,
      answers: [], //shapes, which moved to answer zone
      lastPair: [-1, -1], //pair of shapes on scales, user can't compare the same pair two times
      lastChangedZone: -1, //when showing correct answer, change only last dragged shape position
      shapes: [], //array of SingleShapeModels
      canDrag: true,
      buttonStatus: "none" // ['none','ok','check','tryAgain','showAnswer']
    } );

    this.dropZone = []; //contains indexes of shapes, which are placed in current zone, -1 if empty

    for ( var i = 0; i < 2 * this.gameModel.MAXIMUM_PAIRS; i++ ) {
      this.dropZone[i] = -1;
    }

    //two more dropZones 12 and 13 - scales
    this.dropZone.push( -1 );
    this.dropZone.push( -1 );

    this.generateLevel();
  }

  inherit( PropertySet, LevelModel, {
    reset: function() {
      PropertySet.prototype.reset.call( this );
      this.generateLevel();
      for ( var i = 0; i < this.dropZone.length; i++ ) {
        this.dropZone[i] = -1;
      }
      this.answers = [];
      this.lastPair = [-1, -1];
    },
    step: function( dt ) {
      if ( this.gameModel.isTimer ) {
        this.time += dt;
      }
    },
    // return filtered shapes set for the selected denominator, from java model
    filterShapes: function( shapes, d ) {
      var arr = [],
        //rules if shape_type can be used for denominator d
        map = {
          PIES: true,
          HORIZONTAL_BARS: d < 9,
          VERTICAL_BARS: d < 9,
          PLUSES: d === 6,
          GRID: d === 4 || d === 9,
          PYRAMID: d === 1 || d === 4 || d === 9,
          TETRIS: d === 4,
          FLOWER: d === 6,
          LETTER_L_SHAPES: d % 2 === 0,
          INTERLEAVED_L_SHAPES: d === 2 || d === 4,
          RING_OF_HEXAGONS: d === 7,
          NINJA_STAR: d === 8
        };

      // move through all possible shapes and add it if filter through map
      shapes.forEach( function( shape) {
        if ( map[shape]) {
          arr.push(shape);
        }
      } );

      return arr;
    },
    // generate new level
    generateLevel: function() {
      var fractions = _.shuffle( this.levelDescription.fractions.slice( 0 ) ).splice( 0, this.gameModel.MAXIMUM_PAIRS ), //get random MAXIMUM_PAIRS fractions
        numericScaleFactors = this.levelDescription.numericScaleFactors.slice( 0 ), //scaleFactors to multiply fractions
        numberType = 'NUMBER',
        newShapes = [];

      var shapesAll = this.levelDescription.shapes.slice( 0 ); // get possible shapes for selected level
      shapesAll.push( numberType ); // add fractions to possible shapes

      // add shapes
      for ( var i = 0; i < this.gameModel.MAXIMUM_PAIRS; i++ ) {
        var fraction = fractions[i]; // [numerator, denominator] pair
        var shapes = this.filterShapes( shapesAll, fraction[1] ); //filter only shapes for current denominator
        var scaleFactor = numericScaleFactors[_.random( numericScaleFactors.length - 1 )]; //random scaleFactor
        var fillType = this.levelDescription.fillType[_.random( this.levelDescription.fillType.length - 1 )];

        // first 3 fractions - number, last 3 fractions - shapes with different colors (3 numbers and 3 shapes at least)
        var type = (i < this.gameModel.MAXIMUM_PAIRS / 2) ? numberType : shapes[ i % (shapes.length - 1) ];
        var color = (type === numberType) ? 'rgb(0,0,0)' : this.gameModel.colorScheme[i % 3];
        newShapes.push( new SingleShapeModel( type, fraction, scaleFactor, color, fillType, this.gameModel.toSimplify ) );

        // add partner: if was number - add shape, if was shape - add number or shape with another color
        type = shapes[_.random( shapes.length - (type === numberType ? 2 : 1) )];
        color = (type === numberType) ? 'rgb(0,0,0)' : this.gameModel.colorScheme[(i + 1) % 3];
        newShapes.push( new SingleShapeModel( type, fraction, scaleFactor, color, fillType, this.gameModel.toSimplify ) );
      }

      newShapes = _.shuffle( newShapes );
      for ( i = 0; i < newShapes.length; i++ ) {
        newShapes[i].dropZone = i;
      }

      this.shapes = newShapes;
    },
    answerButton: function( buttonName ) {
      var self = this;
      switch( buttonName ) { //['none','ok','check','tryAgain','showAnswer']
        case "ok":
          this.lastChangedZone = -1;
          self.stepScore = 2;
          this.canDrag = true;
          this.buttonStatus = "none";
          if ( self.answers.length === self.gameModel.MAXIMUM_PAIRS ) {
            self.hiScore = Math.max( self.hiScore, self.score );
          }
          break;
        case "check":
          if ( self.isShapesEqual( self.shapes[this.dropZone[12]], self.shapes[this.dropZone[13]] ) ) {
            //answer correct
            this.buttonStatus = "ok";
            self.score += self.stepScore;
            if ( self.gameModel.isSound ) {
              self.gameModel.sounds.correct.play();
            }
          }
          else {
            //answer incorrect
            if ( self.gameModel.isSound ) {
              self.gameModel.sounds.incorrect.play();
            }
            self.stepScore--;
            this.buttonStatus = (self.stepScore) ? "tryAgain" : "showAnswer";
          }
          this.canDrag = false;
          break;
        case "tryAgain" :
          this.canDrag = true;
          this.buttonStatus = "none";
          break;
        case "showAnswer" :
          this.buttonStatus = "ok";
          break;
      }
    },
    isShapesEqual: function( shape1, shape2 ) {
      return Math.abs( shape1.getAnswer() - shape2.getAnswer() ) < 0.001;
    }
  } );

  return LevelModel;
} );
<|endoftext|>


<commit_before>/**
 * This file is part of the Nextras community extensions of Nette Framework
 *
 * Copyright (c) 2012 Jan Skrasek (http://jan.skrasek.com)
 *
 * @license    MIT
 * @link       https://github.com/nextras
 */

$.nette.ext('datagrid', {
	init: function() {
		var datagrid = this;
		this.grids = $('.datagrid').each(function() {
			datagrid.load($(this));
		});
	},
	load: function() {
		$('.datagrid input').off('keypress.datagrid').on('keypress.datagrid', function(e) {
			if (e.which == 13) {
				$(this).parents('tr').find('input[name=filter\\[filter\\]]').click();
				e.preventDefault();
			}
		});
		$('.datagrid thead select').off('change.datagrid').on('change.datagrid', function(e) {
			$(this).parents('tr').find('input[name=filter\\[filter\\]]').click();
		});
	},
	before: function(settings) {
		this.grid = settings.nette.el.parents('.datagrid');
	},
	success: function() {
		this.load(this.grid);
	}
}, {
	activeGrid: null,
	load: function(grid) {
		var idToClose = [];
		var paramName = grid.attr('data-grid-name');
		grid.find('tr:has(input[name=edit\\[cancel\\]])').each(function() {
			idToClose.push($(this).attr('data-grid-primary'));
		});

		if (idToClose.length == 0) {
			return;
		}

		grid.find('.editLink').each(function() {
			var href = $(this).data('grid-href');
			if (!href) {
				$(this).data('grid-href', href = $(this).attr('href'));
			}

			$(this).attr('href', href + '&' + paramName + '-cancelEditPrimaryValue=' + idToClose.join(','));
		});
	}
});
<commit_msg>Fixed for current nette.ajax.js<commit_after>/**
 * This file is part of the Nextras community extensions of Nette Framework
 *
 * Copyright (c) 2012 Jan Skrasek (http://jan.skrasek.com)
 *
 * @license    MIT
 * @link       https://github.com/nextras
 */

$.nette.ext('datagrid', {
	init: function() {
		var datagrid = this;
		this.grids = $('.datagrid').each(function() {
			datagrid.load($(this));
		});
	},
	load: function() {
		$('.datagrid input').off('keypress.datagrid').on('keypress.datagrid', function(e) {
			if (e.which == 13) {
				$(this).parents('tr').find('input[name=filter\\[filter\\]]').click();
				e.preventDefault();
			}
		});
		$('.datagrid thead select').off('change.datagrid').on('change.datagrid', function(e) {
			$(this).parents('tr').find('input[name=filter\\[filter\\]]').click();
		});
	},
	before: function(xhr, settings) {
		this.grid = settings.nette.el.parents('.datagrid');
	},
	success: function() {
		this.load(this.grid);
	}
}, {
	activeGrid: null,
	load: function(grid) {
		var idToClose = [];
		var paramName = grid.attr('data-grid-name');
		grid.find('tr:has(input[name=edit\\[cancel\\]])').each(function() {
			idToClose.push($(this).attr('data-grid-primary'));
		});

		if (idToClose.length == 0) {
			return;
		}

		grid.find('.editLink').each(function() {
			var href = $(this).data('grid-href');
			if (!href) {
				$(this).data('grid-href', href = $(this).attr('href'));
			}

			$(this).attr('href', href + '&' + paramName + '-cancelEditPrimaryValue=' + idToClose.join(','));
		});
	}
});
<|endoftext|>


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

/**
 * A node that can be custom-drawn with Canvas calls. Manual handling of dirty region repainting.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

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

  var inherit = require( 'PHET_CORE/inherit' );
  var scenery = require( 'SCENERY/scenery' );

  var Node = require( 'SCENERY/nodes/Node' );
  require( 'SCENERY/display/Renderer' );
  var CanvasSelfDrawable = require( 'SCENERY/display/CanvasSelfDrawable' );

  // pass a canvasBounds option if you want to specify the self bounds
  scenery.CanvasNode = function CanvasNode( options ) {
    Node.call( this, options );
    this.setRendererBitmask( scenery.bitmaskBoundsValid | scenery.bitmaskSupportsCanvas );

    if ( options && options.canvasBounds ) {
      this.setCanvasBounds( options.canvasBounds );
    }
  };
  var CanvasNode = scenery.CanvasNode;

  inherit( Node, CanvasNode, {

    // how to set the bounds of the CanvasNode
    setCanvasBounds: function( selfBounds ) {
      this.invalidateSelf( selfBounds );
    },

    isPainted: function() {
      return true;
    },

    // override paintCanvas with a faster version, since fillRect and drawRect don't affect the current default path
    paintCanvas: function( wrapper ) {
      throw new Error( 'CanvasNode needs paintCanvas implemented' );
    },

    invalidatePaint: function() {
      var stateLen = this._drawables.length;
      for ( var i = 0; i < stateLen; i++ ) {
        this._drawables[i].markDirty();
      }
    },

    canvasPaintSelf: function( wrapper ) {
      this.paintCanvas( wrapper );
    },

    // override for computation of whether a point is inside the self content
    // point is considered to be in the local coordinate frame
    containsPointSelf: function( point ) {
      return false;
      // throw new Error( 'CanvasNode needs containsPointSelf implemented' );
    },

    createCanvasDrawable: function( renderer, instance ) {
      return CanvasNode.CanvasNodeDrawable.createFromPool( renderer, instance );
    },

    // whether this node's self intersects the specified bounds, in the local coordinate frame
    // intersectsBoundsSelf: function( bounds ) {
    //   // TODO: implement?
    // },

    getBasicConstructor: function( propLines ) {
      return 'new scenery.CanvasNode( {' + propLines + '} )'; // TODO: no real way to do this nicely?
    }

  } );

  /*---------------------------------------------------------------------------*
  * Canvas rendering
  *----------------------------------------------------------------------------*/

  CanvasNode.CanvasNodeDrawable = CanvasSelfDrawable.createDrawable( {
    type: function CanvasNodeDrawable( renderer, instance ) { this.initialize( renderer, instance ); },
    paintCanvas: function paintCanvasNode( wrapper, node ) {
      node.paintCanvas( wrapper );
    },
    usesFill: false,
    usesStroke: false
  } );

  return CanvasNode;
} );

<commit_msg>Adding support for canvasBounds mutator on CanvasNode. fixes #227<commit_after>// Copyright 2002-2014, University of Colorado

/**
 * A node that can be custom-drawn with Canvas calls. Manual handling of dirty region repainting.
 *
 * setCanvasBounds (or the mutator canvasBounds) should be used to set the area that is drawn to (otherwise nothing
 * will show up)
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

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

  var inherit = require( 'PHET_CORE/inherit' );
  var scenery = require( 'SCENERY/scenery' );

  var Node = require( 'SCENERY/nodes/Node' );
  require( 'SCENERY/display/Renderer' );
  var CanvasSelfDrawable = require( 'SCENERY/display/CanvasSelfDrawable' );

  // pass a canvasBounds option if you want to specify the self bounds
  scenery.CanvasNode = function CanvasNode( options ) {
    Node.call( this, options );
    this.setRendererBitmask( scenery.bitmaskBoundsValid | scenery.bitmaskSupportsCanvas );

    if ( options && options.canvasBounds ) {
      this.setCanvasBounds( options.canvasBounds );
    }
  };
  var CanvasNode = scenery.CanvasNode;

  inherit( Node, CanvasNode, {

    // how to set the bounds of the CanvasNode
    setCanvasBounds: function( selfBounds ) {
      this.invalidateSelf( selfBounds );
    },
    set canvasBounds( value ) { this.setCanvasBounds( value ); },
    get canvasBounds() { return this.getSelfBounds(); },

    isPainted: function() {
      return true;
    },

    // override paintCanvas with a faster version, since fillRect and drawRect don't affect the current default path
    paintCanvas: function( wrapper ) {
      throw new Error( 'CanvasNode needs paintCanvas implemented' );
    },

    invalidatePaint: function() {
      var stateLen = this._drawables.length;
      for ( var i = 0; i < stateLen; i++ ) {
        this._drawables[i].markDirty();
      }
    },

    canvasPaintSelf: function( wrapper ) {
      this.paintCanvas( wrapper );
    },

    // override for computation of whether a point is inside the self content
    // point is considered to be in the local coordinate frame
    containsPointSelf: function( point ) {
      return false;
      // throw new Error( 'CanvasNode needs containsPointSelf implemented' );
    },

    createCanvasDrawable: function( renderer, instance ) {
      return CanvasNode.CanvasNodeDrawable.createFromPool( renderer, instance );
    },

    // whether this node's self intersects the specified bounds, in the local coordinate frame
    // intersectsBoundsSelf: function( bounds ) {
    //   // TODO: implement?
    // },

    getBasicConstructor: function( propLines ) {
      return 'new scenery.CanvasNode( {' + propLines + '} )'; // TODO: no real way to do this nicely?
    }

  } );

  CanvasNode.prototype._mutatorKeys = [ 'canvasBounds' ].concat( Node.prototype._mutatorKeys );

  /*---------------------------------------------------------------------------*
  * Canvas rendering
  *----------------------------------------------------------------------------*/

  CanvasNode.CanvasNodeDrawable = CanvasSelfDrawable.createDrawable( {
    type: function CanvasNodeDrawable( renderer, instance ) { this.initialize( renderer, instance ); },
    paintCanvas: function paintCanvasNode( wrapper, node ) {
      if ( !node._selfBounds.isEmpty() ) {
        node.paintCanvas( wrapper );
      }
    },
    usesFill: false,
    usesStroke: false
  } );

  return CanvasNode;
} );

<|endoftext|>


<commit_before>/*global $, Whisper, Backbone, textsecure, extension*/
/*
 * vim: ts=4:sw=4:expandtab
 */

// This script should only be included in background.html
(function () {
    'use strict';

    window.Whisper = window.Whisper || {};

    window.setUnreadCount = function(count) {
        if (count > 0) {
            extension.navigator.setBadgeText(count);
        } else {
            extension.navigator.setBadgeText("");
        }
    };

    window.isFocused = function() {
        return inboxFocused;
    };
    window.isOpen = function() {
        return inboxOpened;
    };

    window.drawAttention = function() {
        if (inboxOpened && !inboxFocused) {
            extension.windows.drawAttention(inboxWindowId);
        }
    };

    /* Inbox window controller */
    var inboxFocused = false;
    var inboxOpened = false;
    var inboxWindowId = 'inbox';
    var appWindow = null;
    window.openInbox = function() {
        if (inboxOpened === false) {
            inboxOpened = true;
            extension.windows.open({
                id: 'inbox',
                url: 'index.html',
                focused: true,
                width: 580,
                height: 440,
                minWidth: 600,
                minHeight: 360
            }, function (windowInfo) {
                inboxWindowId = windowInfo.id;
                appWindow = windowInfo;

                windowInfo.onClosed.addListener(function () {
                    inboxOpened = false;
                    appWindow = null;
                });

                appWindow.contentWindow.addEventListener('blur', function() {
                    inboxFocused = false;
                });
                appWindow.contentWindow.addEventListener('focus', function() {
                    inboxFocused = true;
                });

                // close the panel if background.html is refreshed
                extension.windows.beforeUnload(function() {
                    // TODO: reattach after reload instead of closing.
                    extension.windows.remove(inboxWindowId);
                });
            });
        } else if (inboxOpened === true) {
            extension.windows.focus(inboxWindowId, function (error) {
                if (error) {
                    inboxOpened = false;
                    openInbox();
                }
            });
        }
    };

    var open;
    window.openConversation = function(conversation) {
        if (inboxOpened === true) {
            var appWindow = chrome.app.window.get(inboxWindowId);
            appWindow.contentWindow.openConversation(conversation);
        } else {
            open = conversation;
        }
        openInbox();
    };
    window.getOpenConversation = function() {
        var o = open;
        open = null;
        return o;
    };
})();
<commit_msg>Clean up references to appWindow<commit_after>/*global $, Whisper, Backbone, textsecure, extension*/
/*
 * vim: ts=4:sw=4:expandtab
 */

// This script should only be included in background.html
(function () {
    'use strict';

    window.Whisper = window.Whisper || {};

    window.setUnreadCount = function(count) {
        if (count > 0) {
            extension.navigator.setBadgeText(count);
        } else {
            extension.navigator.setBadgeText("");
        }
    };

    window.isFocused = function() {
        return inboxFocused;
    };
    window.isOpen = function() {
        return inboxOpened;
    };

    window.drawAttention = function() {
        if (inboxOpened && !inboxFocused) {
            extension.windows.drawAttention(inboxWindowId);
        }
    };

    /* Inbox window controller */
    var inboxFocused = false;
    var inboxOpened = false;
    var inboxWindowId = 'inbox';
    var appWindow = null;
    window.openInbox = function() {
        if (inboxOpened === false) {
            inboxOpened = true;
            extension.windows.open({
                id: 'inbox',
                url: 'index.html',
                focused: true,
                width: 580,
                height: 440,
                minWidth: 600,
                minHeight: 360
            }, function (windowInfo) {
                appWindow = windowInfo;
                inboxWindowId = appWindow.id;

                appWindow.onClosed.addListener(function () {
                    inboxOpened = false;
                    appWindow = null;
                });

                appWindow.contentWindow.addEventListener('blur', function() {
                    inboxFocused = false;
                });
                appWindow.contentWindow.addEventListener('focus', function() {
                    inboxFocused = true;
                });

                // close the panel if background.html is refreshed
                extension.windows.beforeUnload(function() {
                    // TODO: reattach after reload instead of closing.
                    extension.windows.remove(inboxWindowId);
                });
            });
        } else if (inboxOpened === true) {
            extension.windows.focus(inboxWindowId, function (error) {
                if (error) {
                    inboxOpened = false;
                    openInbox();
                }
            });
        }
    };

    var open;
    window.openConversation = function(conversation) {
        if (inboxOpened === true) {
            appWindow.contentWindow.openConversation(conversation);
        } else {
            open = conversation;
        }
        openInbox();
    };
    window.getOpenConversation = function() {
        var o = open;
        open = null;
        return o;
    };
})();
<|endoftext|>


<commit_before>/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
            /*var total = 100;
            alert(total);
            console.log(this.subcompetences);
            for(var sub in this.subcompetences){
                alert(sub);
                sub.calculateWeight(100);
                total -= sub.weight;
                alert(total);
            }*/
        },

        removeThis: function() {
            viewmodel.removeCompetence(this);
            automatedWeightCalculation(this.subcompetences());
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            this.subcompetences.remove(subCompetence);
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);
            automatedWeightCalculation(this.indicators());
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            this.indicators.remove(indicator);
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, locked, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        description : ko.observable(description),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    }
}

/**
 * Push the current project state to the database
 * @returns {undefined}
 */
function saveProjectStructure() {
    $.ajax({
       type: "POST",
       url: "/api/projectstructure/" + projectid,
       data: ko.toJSON(viewModel.competences),
       success: function(){
           // TODO make multilangual and with modals
           alert("Saved projectstructure to server");

           fetchProjectStructure();
       }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);

            $.each(item.subcompetences, function(i, subcomp){
               var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
               competence.subcompetences.push(subcompetence);

               $.each(subcomp.indicators, function(i, indic){
                  subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description));
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        saveProjectStructure();
    });
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = percentPerCompetence.toFixed(2);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<commit_msg>weight check<commit_after>/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
            /*var total = 100;
            alert(total);
            console.log(this.subcompetences);
            for(var sub in this.subcompetences){
                alert(sub);
                sub.calculateWeight(100);
                total -= sub.weight;
                alert(total);
            }*/
        },

        removeThis: function() {
            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            this.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, locked, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        description : ko.observable(description),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    }
}

/**
 * Push the current project state to the database
 * @returns {undefined}
 */
function saveProjectStructure() {
    $.ajax({
       type: "POST",
       url: "/api/projectstructure/" + projectid,
       data: ko.toJSON(viewModel.competences),
       success: function(){
           // TODO make multilangual and with modals
           alert("Saved projectstructure to server");

           fetchProjectStructure();
       }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);

            $.each(item.subcompetences, function(i, subcomp){
               var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
               competence.subcompetences.push(subcompetence);

               $.each(subcomp.indicators, function(i, indic){
                  subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description));
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        saveProjectStructure();
    });
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = percentPerCompetence.toFixed(2);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<|endoftext|>


<commit_before>/**
 * @class OO.ui
 */

/**
 * Lazy-initialize and return a global OO.ui.WindowManager instance, used by OO.ui.alert and
 * OO.ui.confirm.
 *
 * @private
 * @return {OO.ui.WindowManager}
 */
OO.ui.getWindowManager = function () {
	if ( !OO.ui.windowManager ) {
		OO.ui.windowManager = new OO.ui.WindowManager();
		$( 'body' ).append( OO.ui.windowManager.$element );
		OO.ui.windowManager.addWindows( {
			messageDialog: new OO.ui.MessageDialog()
		} );
	}
	return OO.ui.windowManager;
};

/**
 * Display a quick modal alert dialog, using a OO.ui.MessageDialog. While the dialog is open, the
 * rest of the page will be dimmed out and the user won't be able to interact with it. The dialog
 * has only one action button, labelled "OK", clicking it will simply close the dialog.
 *
 * A window manager is created automatically when this function is called for the first time.
 *
 *     @example
 *     OO.ui.alert( 'Something happened!' ).done( function () {
 *         console.log( 'User closed the dialog.' );
 *     } );
 *
 * @param {jQuery|string} text Message text to display
 * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
 * @return {jQuery.Promise} Promise resolved when the user closes the dialog
 */
OO.ui.alert = function ( text, options ) {
	return OO.ui.getWindowManager().openWindow( 'messageDialog', $.extend( {
		message: text,
		actions: [ OO.ui.MessageDialog.static.actions[ 0 ] ]
	}, options ) ).then( function ( opened ) {
		return opened.then( function ( closing ) {
			return closing.then( function () {
				return $.Deferred().resolve();
			} );
		} );
	} );
};

/**
 * Display a quick modal confirmation dialog, using a OO.ui.MessageDialog. While the dialog is open,
 * the rest of the page will be dimmed out and the user won't be able to interact with it. The
 * dialog has two action buttons, one to confirm an operation (labelled "OK") and one to cancel it
 * (labelled "Cancel").
 *
 * A window manager is created automatically when this function is called for the first time.
 *
 *     @example
 *     OO.ui.confirm( 'Are you sure?' ).done( function ( confirmed ) {
 *         if ( confirmed ) {
 *             console.log( 'User clicked "OK"!' );
 *         } else {
 *             console.log( 'User clicked "Cancel" or closed the dialog.' );
 *         }
 *     } );
 *
 * @param {jQuery|string} text Message text to display
 * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
 * @return {jQuery.Promise} Promise resolved when the user closes the dialog. If the user chose to
 *  confirm, the promise will resolve to boolean `true`; otherwise, it will resolve to boolean
 *  `false`.
 */
OO.ui.confirm = function ( text, options ) {
	return OO.ui.getWindowManager().openWindow( 'messageDialog', $.extend( {
		message: text
	}, options ) ).then( function ( opened ) {
		return opened.then( function ( closing ) {
			return closing.then( function ( data ) {
				return $.Deferred().resolve( !!( data && data.action === 'accept' ) );
			} );
		} );
	} );
};

/**
 * Display a quick modal prompt dialog, using a OO.ui.MessageDialog. While the dialog is open,
 * the rest of the page will be dimmed out and the user won't be able to interact with it. The
 * dialog has a text input widget and two action buttons, one to confirm an operation (labelled "OK")
 * and one to cancel it (labelled "Cancel").
 *
 * A window manager is created automatically when this function is called for the first time.
 *
 *     @example
 *     OO.ui.prompt( 'Choose a line to go to', { textInput: { placeholder: 'Line number' } } ).done( function ( result ) {
 *         if ( result !== null ) {
 *             console.log( 'User typed "' + result + '" then clicked "OK".' );
 *         } else {
 *             console.log( 'User clicked "Cancel" or closed the dialog.' );
 *         }
 *     } );
 *
 * @param {jQuery|string} text Message text to display
 * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
 * @cfg {Object} [textInput] Additional options for text input widget, see OO.ui.TextInputWidget
 * @return {jQuery.Promise} Promise resolved when the user closes the dialog. If the user chose to
 *  confirm, the promise will resolve with the value of the text input widget; otherwise, it will
 *  resolve to `null`.
 */
OO.ui.prompt = function ( text, options ) {
	var manager = OO.ui.getWindowManager(),
		textInput = new OO.ui.TextInputWidget( ( options && options.textInput ) || {} ),
		textField = new OO.ui.FieldLayout( textInput, {
			align: 'top',
			label: text
		} );

	// TODO: This is a little hacky, and could be done by extending MessageDialog instead.

	return manager.openWindow( 'messageDialog', $.extend( {
		message: textField.$element
	}, options ) ).then( function ( opened ) {
		// After ready
		textInput.on( 'enter', function () {
			manager.getCurrentWindow().close( { action: 'accept' } );
		} );
		textInput.focus();
		return opened.then( function ( closing ) {
			return closing.then( function ( data ) {
				return $.Deferred().resolve( data && data.action === 'accept' ? textInput.getValue() : null );
			} );
		} );
	} );
};
<commit_msg>windows: Use the "recommended" WindowManager#addWindows usage<commit_after>/**
 * @class OO.ui
 */

/**
 * Lazy-initialize and return a global OO.ui.WindowManager instance, used by OO.ui.alert and
 * OO.ui.confirm.
 *
 * @private
 * @return {OO.ui.WindowManager}
 */
OO.ui.getWindowManager = function () {
	if ( !OO.ui.windowManager ) {
		OO.ui.windowManager = new OO.ui.WindowManager();
		$( 'body' ).append( OO.ui.windowManager.$element );
		OO.ui.windowManager.addWindows( [ new OO.ui.MessageDialog() ] );
	}
	return OO.ui.windowManager;
};

/**
 * Display a quick modal alert dialog, using a OO.ui.MessageDialog. While the dialog is open, the
 * rest of the page will be dimmed out and the user won't be able to interact with it. The dialog
 * has only one action button, labelled "OK", clicking it will simply close the dialog.
 *
 * A window manager is created automatically when this function is called for the first time.
 *
 *     @example
 *     OO.ui.alert( 'Something happened!' ).done( function () {
 *         console.log( 'User closed the dialog.' );
 *     } );
 *
 * @param {jQuery|string} text Message text to display
 * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
 * @return {jQuery.Promise} Promise resolved when the user closes the dialog
 */
OO.ui.alert = function ( text, options ) {
	return OO.ui.getWindowManager().openWindow( 'message', $.extend( {
		message: text,
		actions: [ OO.ui.MessageDialog.static.actions[ 0 ] ]
	}, options ) ).then( function ( opened ) {
		return opened.then( function ( closing ) {
			return closing.then( function () {
				return $.Deferred().resolve();
			} );
		} );
	} );
};

/**
 * Display a quick modal confirmation dialog, using a OO.ui.MessageDialog. While the dialog is open,
 * the rest of the page will be dimmed out and the user won't be able to interact with it. The
 * dialog has two action buttons, one to confirm an operation (labelled "OK") and one to cancel it
 * (labelled "Cancel").
 *
 * A window manager is created automatically when this function is called for the first time.
 *
 *     @example
 *     OO.ui.confirm( 'Are you sure?' ).done( function ( confirmed ) {
 *         if ( confirmed ) {
 *             console.log( 'User clicked "OK"!' );
 *         } else {
 *             console.log( 'User clicked "Cancel" or closed the dialog.' );
 *         }
 *     } );
 *
 * @param {jQuery|string} text Message text to display
 * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
 * @return {jQuery.Promise} Promise resolved when the user closes the dialog. If the user chose to
 *  confirm, the promise will resolve to boolean `true`; otherwise, it will resolve to boolean
 *  `false`.
 */
OO.ui.confirm = function ( text, options ) {
	return OO.ui.getWindowManager().openWindow( 'message', $.extend( {
		message: text
	}, options ) ).then( function ( opened ) {
		return opened.then( function ( closing ) {
			return closing.then( function ( data ) {
				return $.Deferred().resolve( !!( data && data.action === 'accept' ) );
			} );
		} );
	} );
};

/**
 * Display a quick modal prompt dialog, using a OO.ui.MessageDialog. While the dialog is open,
 * the rest of the page will be dimmed out and the user won't be able to interact with it. The
 * dialog has a text input widget and two action buttons, one to confirm an operation (labelled "OK")
 * and one to cancel it (labelled "Cancel").
 *
 * A window manager is created automatically when this function is called for the first time.
 *
 *     @example
 *     OO.ui.prompt( 'Choose a line to go to', { textInput: { placeholder: 'Line number' } } ).done( function ( result ) {
 *         if ( result !== null ) {
 *             console.log( 'User typed "' + result + '" then clicked "OK".' );
 *         } else {
 *             console.log( 'User clicked "Cancel" or closed the dialog.' );
 *         }
 *     } );
 *
 * @param {jQuery|string} text Message text to display
 * @param {Object} [options] Additional options, see OO.ui.MessageDialog#getSetupProcess
 * @cfg {Object} [textInput] Additional options for text input widget, see OO.ui.TextInputWidget
 * @return {jQuery.Promise} Promise resolved when the user closes the dialog. If the user chose to
 *  confirm, the promise will resolve with the value of the text input widget; otherwise, it will
 *  resolve to `null`.
 */
OO.ui.prompt = function ( text, options ) {
	var manager = OO.ui.getWindowManager(),
		textInput = new OO.ui.TextInputWidget( ( options && options.textInput ) || {} ),
		textField = new OO.ui.FieldLayout( textInput, {
			align: 'top',
			label: text
		} );

	// TODO: This is a little hacky, and could be done by extending MessageDialog instead.

	return manager.openWindow( 'message', $.extend( {
		message: textField.$element
	}, options ) ).then( function ( opened ) {
		// After ready
		textInput.on( 'enter', function () {
			manager.getCurrentWindow().close( { action: 'accept' } );
		} );
		textInput.focus();
		return opened.then( function ( closing ) {
			return closing.then( function ( data ) {
				return $.Deferred().resolve( data && data.action === 'accept' ? textInput.getValue() : null );
			} );
		} );
	} );
};
<|endoftext|>


<commit_before>var workQueue = [];
/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
        },

        removeThis: function() {
            if(this.id() !== undefined) // User deletes a competence that's been saved to the database
            {
                workQueue.push("/api/project/competence/delete/" + this.id())
            }

            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            if(subCompetence.id() !== undefined) // User deletes a subcompetence that's been saved to the database
            {
                workQueue.push("/api/project/subcompetence/delete/" + subCompetence.id())
            }

            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {

        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            var self = this;

            if(indicator.id() != undefined) // User deletes an indicator that hasn't been saved to the database yet
            {
                workQueue.push("/api/project/indicator/delete/" + indicator.id())
            }

            self.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, description, locked,pointType) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        description : ko.observable(description),
        locked: false,
        pointType: pointType,

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.nextPage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NextPage");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.availableTypes = ko.observableArray(['Slider','Punten','Ja/Nee']);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.removeAll();
    }
}

function fetchProjectStructure() {
    viewModel.clearStructure();
    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            if(item.id > 0) {
                var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);
            }
            $.each(item.subcompetences, function(i, subcomp){
                if(subcomp.id > 0) {
                    var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
                    competence.subcompetences.push(subcompetence);
                }

               $.each(subcomp.indicators, function(i, indic){
                   if(indic.id > 0) {
                       var test = 'Punten';
                       subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.weight, indic.description,false,test));
                       console.log(test);
                   }
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        if(allValidationChecks()) {
            saveProjectStructure();
            var url = document.URL;
            var string = url.split("/");
            window.location.href = "http://" + string[2] + "/" + string[3] + "/students/" + string[4];
            console.log("Saved");
        }
        else
        {
            window.scrollTo(0,0);
            console.log("Not saved");
        }
    });
}

function saveProjectStructure() {
    var self = this;

    this.doTheRest = function()
    {
        $.ajax({
            type: "POST",
            url: "/api/projectstructure/" + projectid,
            data: ko.toJSON(viewModel.competences),
            success: function(){
                // TODO make multilangual and with modals
                alert("Saved projectstructure to server");

                fetchProjectStructure();
            }
        });
    }

    if(workQueue.length === 0)
    {
        this.doTheRest();
    }

    var processedIndex = 0;
    for(i = 0; i < workQueue.length; i++)
    {
        $.getJSON(
            workQueue[i],
            function(result)
            {
                if(!result.success)
                {
                    alert("Failed processing your request: " + result.error);
                }

                if(processedIndex === workQueue.length - 1)
                {
                    self.doTheRest();
                    workQueue = [];
                }
                processedIndex++;
            }
        );
    }

}

function allValidationChecks()
{
    $(".validationSummary").addClass('hide');
    $(".validationSummary ul").empty();
    result = validationCheck() && totalPercentCheck()
    if(!result)
    {
        $(".validationSummary").removeClass('hide');
    }

    return result;
}

function validationCheck()
{
    var allCompetencesValid = true;
    var allSubcompetencesValid = true;
    var allIndicatorsValid = true;

    for(var indexCompetences =0; indexCompetences < viewModel.competences().length; indexCompetences++)
    {
        if(!viewModel.competences()[indexCompetences].code() && !viewModel.competences()[indexCompetences].name())
        {
            if(allCompetencesValid)
            {
                $(".validationSummary ul").append("
Code or name in competences is empty
");
                $(".validationSummary").removeClass("hide");
            }
            allCompetencesValid = false;
        }
        for(var indexSubcompetence = 0; indexSubcompetence < viewModel.competences()[indexCompetences].subcompetences().length; indexSubcompetence++)
        {
            if(!viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].name() && !viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].code())
            {
                if(allSubcompetencesValid)
                {
                    $(".validationSummary ul").append("
Code or name in subcompetences is empty
");
                    $(".validationSummary").removeClass("hide");
                }
                allSubcompetencesValid = false;
            }
            for(var indexIndicators = 0; indexIndicators < viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators().length; indexIndicators++)
            {
                if(!viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators()[indexIndicators].name() && !viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators()[indexIndicators].description())
                {
                    if(allIndicatorsValid)
                    {
                        $(".validationSummary ul").append("
Description or name in indicators is empty
");
                        $(".validationSummary").removeClass("hide");
                    }
                    allIndicatorsValid = false;
                }
            }
        }
    }
    return allCompetencesValid && allSubcompetencesValid && allIndicatorsValid;
}

function totalPercentCheck()
{
    var cTotal = 0;
    var success = true;

    $.each(viewModel.competences(),
        function(cI, cVal) {
            cTotal += parseInt(cVal.weight());

            scTotal = 0;
            $.each(cVal.subcompetences(),
                function(scI, scVal)
                {
                    scTotal += parseInt(scVal.weight());

                    iTotal = 0;
                    $.each(scVal.indicators(),
                        function(iI, iVal)
                        {
                            iTotal += parseInt(iVal.weight());
                        }
                    );

                    if(scVal.indicators().length > 0 && iTotal !== 100)
                    {
                        $(".validationSummary ul").append('
Indicator weights in the subcompetence ' + scVal.name() + ' are not adding up to 100%
');
                        success = false;
                    }
                }
            );

            if(cVal.subcompetences().length > 0 && scTotal !== 100)
            {
                $(".validationSummary ul").append('
Subcompentence weights in the competence ' + cVal.name() + ' are not adding up to 100%
');
                success = false;
            }
        }
    );

    if(viewModel.competences().length > 0 && cTotal !== 100)
    {
        $(".validationSummary ul").append('
Competence weights are not adding up to 100%
');
        success = false;
    }

    return success;
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = Math.floor(percentPerCompetence);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<commit_msg>min max<commit_after>var workQueue = [];
/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
        },

        removeThis: function() {
            if(this.id() !== undefined) // User deletes a competence that's been saved to the database
            {
                workQueue.push("/api/project/competence/delete/" + this.id())
            }

            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            if(subCompetence.id() !== undefined) // User deletes a subcompetence that's been saved to the database
            {
                workQueue.push("/api/project/subcompetence/delete/" + subCompetence.id())
            }

            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {

        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            var self = this;

            if(indicator.id() != undefined) // User deletes an indicator that hasn't been saved to the database yet
            {
                workQueue.push("/api/project/indicator/delete/" + indicator.id())
            }

            self.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, description, locked,pointType) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        description : ko.observable(description),
        locked: false,
        pointType: ko.observable(pointType),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);
    gvm.nextPage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NextPage");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.availableTypes = ko.observableArray(['Slider','Punten','Ja/Nee']);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.removeAll();
    }
}

function fetchProjectStructure() {
    viewModel.clearStructure();
    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            if(item.id > 0) {
                var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);
            }
            $.each(item.subcompetences, function(i, subcomp){
                if(subcomp.id > 0) {
                    var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
                    competence.subcompetences.push(subcompetence);
                }

               $.each(subcomp.indicators, function(i, indic){
                   if(indic.id > 0) {
                       var test = 'Punten';
                       subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.weight, indic.description,false,test));
                       console.log(test);
                   }
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        if(allValidationChecks()) {
            saveProjectStructure();
            var url = document.URL;
            var string = url.split("/");
            window.location.href = "http://" + string[2] + "/" + string[3] + "/students/" + string[4];
            console.log("Saved");
        }
        else
        {
            window.scrollTo(0,0);
            console.log("Not saved");
        }
    });
}

function saveProjectStructure() {
    var self = this;

    this.doTheRest = function()
    {
        $.ajax({
            type: "POST",
            url: "/api/projectstructure/" + projectid,
            data: ko.toJSON(viewModel.competences),
            success: function(){
                // TODO make multilangual and with modals
                alert("Saved projectstructure to server");

                fetchProjectStructure();
            }
        });
    }

    if(workQueue.length === 0)
    {
        this.doTheRest();
    }

    var processedIndex = 0;
    for(i = 0; i < workQueue.length; i++)
    {
        $.getJSON(
            workQueue[i],
            function(result)
            {
                if(!result.success)
                {
                    alert("Failed processing your request: " + result.error);
                }

                if(processedIndex === workQueue.length - 1)
                {
                    self.doTheRest();
                    workQueue = [];
                }
                processedIndex++;
            }
        );
    }

}

function allValidationChecks()
{
    $(".validationSummary").addClass('hide');
    $(".validationSummary ul").empty();
    result = validationCheck() && totalPercentCheck()
    if(!result)
    {
        $(".validationSummary").removeClass('hide');
    }

    return result;
}

function validationCheck()
{
    var allCompetencesValid = true;
    var allSubcompetencesValid = true;
    var allIndicatorsValid = true;

    for(var indexCompetences =0; indexCompetences < viewModel.competences().length; indexCompetences++)
    {
        if(!viewModel.competences()[indexCompetences].code() && !viewModel.competences()[indexCompetences].name())
        {
            if(allCompetencesValid)
            {
                $(".validationSummary ul").append("
Code or name in competences is empty
");
                $(".validationSummary").removeClass("hide");
            }
            allCompetencesValid = false;
        }
        for(var indexSubcompetence = 0; indexSubcompetence < viewModel.competences()[indexCompetences].subcompetences().length; indexSubcompetence++)
        {
            if(!viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].name() && !viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].code())
            {
                if(allSubcompetencesValid)
                {
                    $(".validationSummary ul").append("
Code or name in subcompetences is empty
");
                    $(".validationSummary").removeClass("hide");
                }
                allSubcompetencesValid = false;
            }
            for(var indexIndicators = 0; indexIndicators < viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators().length; indexIndicators++)
            {
                if(!viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators()[indexIndicators].name() && !viewModel.competences()[indexCompetences].subcompetences()[indexSubcompetence].indicators()[indexIndicators].description())
                {
                    if(allIndicatorsValid)
                    {
                        $(".validationSummary ul").append("
Description or name in indicators is empty
");
                        $(".validationSummary").removeClass("hide");
                    }
                    allIndicatorsValid = false;
                }
            }
        }
    }
    return allCompetencesValid && allSubcompetencesValid && allIndicatorsValid;
}

function totalPercentCheck()
{
    var cTotal = 0;
    var success = true;

    $.each(viewModel.competences(),
        function(cI, cVal) {
            cTotal += parseInt(cVal.weight());

            scTotal = 0;
            $.each(cVal.subcompetences(),
                function(scI, scVal)
                {
                    scTotal += parseInt(scVal.weight());

                    iTotal = 0;
                    $.each(scVal.indicators(),
                        function(iI, iVal)
                        {
                            iTotal += parseInt(iVal.weight());
                        }
                    );

                    if(scVal.indicators().length > 0 && iTotal !== 100)
                    {
                        $(".validationSummary ul").append('
Indicator weights in the subcompetence ' + scVal.name() + ' are not adding up to 100%
');
                        success = false;
                    }
                }
            );

            if(cVal.subcompetences().length > 0 && scTotal !== 100)
            {
                $(".validationSummary ul").append('
Subcompentence weights in the competence ' + cVal.name() + ' are not adding up to 100%
');
                success = false;
            }
        }
    );

    if(viewModel.competences().length > 0 && cTotal !== 100)
    {
        $(".validationSummary ul").append('
Competence weights are not adding up to 100%
');
        success = false;
    }

    return success;
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = Math.floor(percentPerCompetence);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<|endoftext|>


<commit_before>module.exports = function(mongo) {
	if(!mongo) {
		throw 'Missing mongo';
	}

	var url = 'http://' + (process.env.NODE_ENV === 'production' ? 'kpjs.azurewebsites.net' : 'localhost:1337');
	var passport = require('passport');
	var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
	var GithubStrategy = require('passport-github').Strategy;
	var TwitterStrategy = require('passport-twitter').Strategy;
	var FacebookStrategy = require('passport-facebook').Strategy;

	passport.use(new GoogleStrategy({
			clientID: process.env.GOOGLE_CLIENT_ID,
			clientSecret: process.env.GOOGLE_CLIENT_SECRET,
			callbackURL: url + '/login/google/callback',
			state: true
		},
		authCallback(function(p) {
			return p.photos[0].value;
		})
	));

	passport.use(new GithubStrategy({
			clientID: process.env.GITHUB_CLIENT_ID,
			clientSecret: process.env.GITHUB_CLIENT_SECRET,
			callbackURL: url + '/login/github/callback',
			state: true
		},
		authCallback(function(p) {
			return p._json.avatar_url;
		})
	));

	passport.use(new TwitterStrategy({
			consumerKey: process.env.TWITTER_CLIENT_ID,
			consumerSecret: process.env.TWITTER_CLIENT_SECRET,
			callbackURL: url + '/login/twitter/callback',
			state: true
		},
		authCallback(function(p) {
			return p.photos[0].value;
		})
	));

	passport.use(new FacebookStrategy({
			clientID: process.env.FACEBOOK_CLIENT_ID,
			clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
			callbackURL: url + '/login/facebook/callback',
			profileFields: [ 'displayName', 'photos' ],
			state: true
		},
		authCallback(function(p) {
			return p.photos[0].value;
		})
	));

	passport.serializeUser(function(user, done) {
		done(null, user);
	});

	passport.deserializeUser(function(obj, done) {
		done(null, obj);
	});

	return {
		setup: setup,
		ensureZombie: ensureRoleRequestHandlerWrapper(0),
		ensureCitizen: ensureRoleRequestHandlerWrapper(1),
		ensureRuler: ensureRoleRequestHandlerWrapper(2),
		ensureRulerOrOwner: ensureRulerOrOwner
	};

	function authCallback(avatarCallback) {
		return function(token, tokenSecret, profile, done) {
			mongo.collection('users').findOneAndUpdate({ provider: profile.provider, providerId: profile.id },
				{ $set: { name: profile.displayName }, $setOnInsert: { name: profile.displayName, role: 0 } },
				{ upsert: true, returnOriginal: false },
				function(err, item) {
					if(err) {
						return done(err);
					}
					var avatarUrl;
					try {
						avatarUrl = avatarCallback(profile);
					} catch(e) {}
					return done(null, { id: item.value._id, name: item.value.name, avatarUrl: avatarUrl });
				});
		};
	}

	function setup(expressApp) {
		if(!expressApp) {
			throw 'Missing express app';
		}
		expressApp.use(passport.initialize());
		expressApp.use(passport.session());
		expressApp.get('/login/google', passport.authenticate('google', { scope: 'profile' }));
		expressApp.get('/login/github', passport.authenticate('github'));
		expressApp.get('/login/twitter', passport.authenticate('twitter'));
		expressApp.get('/login/facebook', passport.authenticate('facebook'));
		expressApp.get('/login/google/callback',
			passport.authenticate('google', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/login/github/callback',
			passport.authenticate('github', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/login/twitter/callback',
			passport.authenticate('twitter', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/login/facebook/callback',
			passport.authenticate('facebook', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/logout', function(req, res) {
			req.logout();
			req.session.regenerate(function() {
				res.redirect('/');
			});
		});
		expressApp.get('/loginFail', function(req, res) {
			res.end('login failed');
		});
	}

	function verifyRole(userId, role, callback) {
		var ObjectID = require('mongodb').ObjectID;
		mongo.collection('users').findOne({ _id: new ObjectID(userId) }, { role: 1 }, function(err, item) {
			if(err) {
				return callback(err);
			}
			if(item && item.role >= role) {
				callback(null, true);
			}
			else {
				callback(null, false);
			}
		});
	}

	function ensureRoleRequestHandlerWrapper(role) {
		return function(req, res, next) {
			if(!req.isAuthenticated()) {
				var error = new Error('Not logged in');
				error.statusCode = 401;
				return next(error);
			}
			verifyRole(req.user.id, role, function(err, hasRole) {
				if(err) {
					return next(err);
				}
				if(hasRole) {
					next();
				}
				else {
					var error = new Error('Not authorized');
					error.statusCode = 403;
					next(error);
				}
			});
		};
	}

	function ensureRulerOrOwner(req, res, next) {
		if(!req.isAuthenticated()) {
			var error = new Error('Not logged in');
			error.statusCode = 401;
			return next(error);
		}
		verifyRole(req.user.id, 2, function(err, hasRole) {
			if(err) {
				return next(err);
			}
			if(hasRole) {
				next();
			}
			else {
				ensureOwner(req, res, next);
			}
		});
	}

	function ensureOwner(req, res, next) {
		if(!req.isAuthenticated()) {
			var error = new Error('Not logged in');
			error.statusCode = 401;
			return next(error);
		}
		var ObjectID = require('mongodb').ObjectID;
		mongo.collection('posts').count({ author_id: new ObjectID(req.user.id), uri: req.params.uri }, function(err, count) {
			if(count > 0) {
				return next();
			}
			var error = new Error('Not owner');
			error.statusCode = 403;
			return next(error);
		});
	}
};
<commit_msg>fixed user updates on login<commit_after>module.exports = function(mongo) {
	if(!mongo) {
		throw 'Missing mongo';
	}

	var url = 'http://' + (process.env.NODE_ENV === 'production' ? 'kpjs.azurewebsites.net' : 'localhost:1337');
	var passport = require('passport');
	var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
	var GithubStrategy = require('passport-github').Strategy;
	var TwitterStrategy = require('passport-twitter').Strategy;
	var FacebookStrategy = require('passport-facebook').Strategy;

	passport.use(new GoogleStrategy({
			clientID: process.env.GOOGLE_CLIENT_ID,
			clientSecret: process.env.GOOGLE_CLIENT_SECRET,
			callbackURL: url + '/login/google/callback',
			state: true
		},
		authCallback(function(p) {
			return p.photos[0].value;
		})
	));

	passport.use(new GithubStrategy({
			clientID: process.env.GITHUB_CLIENT_ID,
			clientSecret: process.env.GITHUB_CLIENT_SECRET,
			callbackURL: url + '/login/github/callback',
			state: true
		},
		authCallback(function(p) {
			return p._json.avatar_url;
		})
	));

	passport.use(new TwitterStrategy({
			consumerKey: process.env.TWITTER_CLIENT_ID,
			consumerSecret: process.env.TWITTER_CLIENT_SECRET,
			callbackURL: url + '/login/twitter/callback',
			state: true
		},
		authCallback(function(p) {
			return p.photos[0].value;
		})
	));

	passport.use(new FacebookStrategy({
			clientID: process.env.FACEBOOK_CLIENT_ID,
			clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
			callbackURL: url + '/login/facebook/callback',
			profileFields: [ 'displayName', 'photos' ],
			state: true
		},
		authCallback(function(p) {
			return p.photos[0].value;
		})
	));

	passport.serializeUser(function(user, done) {
		done(null, user);
	});

	passport.deserializeUser(function(obj, done) {
		done(null, obj);
	});

	return {
		setup: setup,
		ensureZombie: ensureRoleRequestHandlerWrapper(0),
		ensureCitizen: ensureRoleRequestHandlerWrapper(1),
		ensureRuler: ensureRoleRequestHandlerWrapper(2),
		ensureRulerOrOwner: ensureRulerOrOwner
	};

	function authCallback(avatarCallback) {
		return function(token, tokenSecret, profile, done) {
			mongo.collection('users').findOneAndUpdate({ provider: profile.provider, providerId: profile.id },
				{ $set: { name: profile.displayName }, $setOnInsert: { role: 0 } },
				{ upsert: true, returnOriginal: false },
				function(err, item) {
					if(err) {
						return done(err);
					}
					var avatarUrl;
					try {
						avatarUrl = avatarCallback(profile);
					} catch(e) {}
					return done(null, { id: item.value._id, name: item.value.name, avatarUrl: avatarUrl });
				});
		};
	}

	function setup(expressApp) {
		if(!expressApp) {
			throw 'Missing express app';
		}
		expressApp.use(passport.initialize());
		expressApp.use(passport.session());
		expressApp.get('/login/google', passport.authenticate('google', { scope: 'profile' }));
		expressApp.get('/login/github', passport.authenticate('github'));
		expressApp.get('/login/twitter', passport.authenticate('twitter'));
		expressApp.get('/login/facebook', passport.authenticate('facebook'));
		expressApp.get('/login/google/callback',
			passport.authenticate('google', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/login/github/callback',
			passport.authenticate('github', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/login/twitter/callback',
			passport.authenticate('twitter', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/login/facebook/callback',
			passport.authenticate('facebook', { failureRedirect: '/loginFail', successRedirect: '/' })
		);
		expressApp.get('/logout', function(req, res) {
			req.logout();
			req.session.regenerate(function() {
				res.redirect('/');
			});
		});
		expressApp.get('/loginFail', function(req, res) {
			res.end('login failed');
		});
	}

	function verifyRole(userId, role, callback) {
		var ObjectID = require('mongodb').ObjectID;
		mongo.collection('users').findOne({ _id: new ObjectID(userId) }, { role: 1 }, function(err, item) {
			if(err) {
				return callback(err);
			}
			if(item && item.role >= role) {
				callback(null, true);
			}
			else {
				callback(null, false);
			}
		});
	}

	function ensureRoleRequestHandlerWrapper(role) {
		return function(req, res, next) {
			if(!req.isAuthenticated()) {
				var error = new Error('Not logged in');
				error.statusCode = 401;
				return next(error);
			}
			verifyRole(req.user.id, role, function(err, hasRole) {
				if(err) {
					return next(err);
				}
				if(hasRole) {
					next();
				}
				else {
					var error = new Error('Not authorized');
					error.statusCode = 403;
					next(error);
				}
			});
		};
	}

	function ensureRulerOrOwner(req, res, next) {
		if(!req.isAuthenticated()) {
			var error = new Error('Not logged in');
			error.statusCode = 401;
			return next(error);
		}
		verifyRole(req.user.id, 2, function(err, hasRole) {
			if(err) {
				return next(err);
			}
			if(hasRole) {
				next();
			}
			else {
				ensureOwner(req, res, next);
			}
		});
	}

	function ensureOwner(req, res, next) {
		if(!req.isAuthenticated()) {
			var error = new Error('Not logged in');
			error.statusCode = 401;
			return next(error);
		}
		var ObjectID = require('mongodb').ObjectID;
		mongo.collection('posts').count({ author_id: new ObjectID(req.user.id), uri: req.params.uri }, function(err, count) {
			if(count > 0) {
				return next();
			}
			var error = new Error('Not owner');
			error.statusCode = 403;
			return next(error);
		});
	}
};
<|endoftext|>