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

/**
 * Abstract base class for model in Graphing Quadratics.
 *
 * @author Andrea Lin
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const Bounds2 = require( 'DOT/Bounds2' );
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const Graph = require( 'GRAPHING_LINES/common/model/Graph' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
  const PointTool = require( 'GRAPHING_QUADRATICS/common/model/PointTool' );
  const Property = require( 'AXON/Property' );
  const PropertyIO = require( 'AXON/PropertyIO' );
  const Quadratic = require( 'GRAPHING_QUADRATICS/common/model/Quadratic' );
  const QuadraticIO = require( 'GRAPHING_QUADRATICS/common/model/QuadraticIO' );
  const Vector2 = require( 'DOT/Vector2' );

  // ifphetio
  const NullableIO = require( 'ifphetio!PHET_IO/types/NullableIO' );

  // constants
  const GRAPH_VIEW_WIDTH = 530; // width of the graph, in view coordinates
  const GRAPH_ORIGIN_OFFSET = new Vector2( 315, 330 ); // offset of the graph's origin, in view coordinates

  class GQModel {

    /**
     * @param {Property.<Quadratic>} quadraticProperty - the interactive quadratic
     * @param {Tandem} tandem
     * @abstract
     */
    constructor( quadraticProperty, tandem ) {

      // @public {Property.<Quadratic>} the interactive quadratic
      this.quadraticProperty = quadraticProperty;

      // @public (read-only) graph
      this.graph = new Graph( GQConstants.X_AXIS_RANGE, GQConstants.Y_AXIS_RANGE );

      // @public {Property.<Quadratic|null>} the saved quadratic, null if nothing is saved
      this.savedQuadraticProperty = new Property( null, {
        isValidValue: value => ( value instanceof Quadratic || value === null ),
        tandem: tandem.createTandem( 'savedQuadraticProperty' ),
        phetioType: PropertyIO( NullableIO( QuadraticIO ) ),
        phetioDocumentation: 'the saved quadratic, null if there is no saved quadratic'
      } );

      // scale from model to view
      const modelViewTransformScale = GRAPH_VIEW_WIDTH / this.graph.xRange.getLength();

      // @public (read-only) model-view transform, created in the model because it's dependent on graph axes ranges.
      this.modelViewTransform = ModelViewTransform2.createOffsetXYScaleMapping(
        GRAPH_ORIGIN_OFFSET,
        modelViewTransformScale,
        -modelViewTransformScale // y is inverted (+y is up in the model, +y is down in the view)
      );

      // Options for {Property.<Quadratic[]>}
      const optionsPropertyQuadraticArray = {
        valueType: Array,
        isValidValue: array => _.every( array, function( value ) { return value instanceof Quadratic; } )
      };

      // {Property.<Quadratic[]>} Quadratics that are visible to the point tools.
      // Not using ObservableArray here because we need to change the entire array contents atomically.
      const pointToolQuadraticsProperty = new Property( [], optionsPropertyQuadraticArray );

      // @public {Property.<Quadratic[]>} optional quadratic terms to be displayed,
      // in the order that they will be considered by point tools.
      // Not using ObservableArray here because we need to change the entire array contents atomically.
      this.quadraticTermsProperty = new Property( [], optionsPropertyQuadraticArray );

      // @public (read-only)
      this.rightPointTool = new PointTool( pointToolQuadraticsProperty, {
        probeSide: 'right',
        location: new Vector2( -2, -12 ),
        dragBounds: new Bounds2(
          this.graph.xRange.min - 1, this.graph.yRange.min - 3,
          this.graph.xRange.max + 1, this.graph.yRange.max + 1 ),
        tandem: tandem.createTandem( 'rightPointTool' ),
        phetioDocumentation: 'the point tool whose probe is on the right side'
      } );

      // @public (read-only)
      this.leftPointTool = new PointTool( pointToolQuadraticsProperty, {
        probeSide: 'left',
        location: new Vector2( 2, -12 ),
        dragBounds: new Bounds2(
          this.graph.xRange.min - 1, this.graph.yRange.min - 3,
          this.graph.xRange.max + 1, this.graph.yRange.max + 1 ),
        tandem: tandem.createTandem( 'leftPointTool' ),
        phetioDocumentation: 'the point tool whose probe is on the left side'
      } );

      // @private Update the list of quadratics visible to the point tools,
      // in the order that they will be considered by the point tools.
      Property.multilink( [ this.quadraticProperty, this.quadraticTermsProperty, this.savedQuadraticProperty ],
        ( quadratic, quadraticTerms, savedQuadratic ) => {
          // order is important! compact to remove nulls
          pointToolQuadraticsProperty.value = _.compact( [ quadratic, ...quadraticTerms, savedQuadratic ] );
        } );
    }

    // @public
    reset() {
      this.savedQuadraticProperty.reset();
      this.rightPointTool.reset();
      this.leftPointTool.reset();
    }

    /**
     * Saves the current quadratic.
     * @public
     */
    saveQuadratic() {
      this.savedQuadraticProperty.value = this.quadraticProperty.value.withColor( GQColors.SAVED_CURVE );
    }

    /**
     * Erases the saved quadratic.
     * @public
     */
    eraseQuadratic() {
      this.savedQuadraticProperty.value = null;
    }
  }

  return graphingQuadratics.register( 'GQModel', GQModel );
} );
<commit_msg>doc<commit_after>// Copyright 2014-2018, University of Colorado Boulder

/**
 * Abstract base class for model in Graphing Quadratics.
 *
 * @author Andrea Lin
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const Bounds2 = require( 'DOT/Bounds2' );
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const Graph = require( 'GRAPHING_LINES/common/model/Graph' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
  const PointTool = require( 'GRAPHING_QUADRATICS/common/model/PointTool' );
  const Property = require( 'AXON/Property' );
  const PropertyIO = require( 'AXON/PropertyIO' );
  const Quadratic = require( 'GRAPHING_QUADRATICS/common/model/Quadratic' );
  const QuadraticIO = require( 'GRAPHING_QUADRATICS/common/model/QuadraticIO' );
  const Vector2 = require( 'DOT/Vector2' );

  // ifphetio
  const NullableIO = require( 'ifphetio!PHET_IO/types/NullableIO' );

  // constants
  const GRAPH_VIEW_WIDTH = 530; // width of the graph, in view coordinates
  const GRAPH_ORIGIN_OFFSET = new Vector2( 315, 330 ); // offset of the graph's origin, in view coordinates

  class GQModel {

    /**
     * @param {Property.<Quadratic>} quadraticProperty - the interactive quadratic
     * @param {Tandem} tandem
     * @abstract
     */
    constructor( quadraticProperty, tandem ) {

      // @public {Property.<Quadratic>} the interactive quadratic
      this.quadraticProperty = quadraticProperty;

      // @public (read-only) graph
      this.graph = new Graph( GQConstants.X_AXIS_RANGE, GQConstants.Y_AXIS_RANGE );

      // @public {Property.<Quadratic|null>} the saved quadratic, null if nothing is saved
      this.savedQuadraticProperty = new Property( null, {
        isValidValue: value => ( value instanceof Quadratic || value === null ),
        tandem: tandem.createTandem( 'savedQuadraticProperty' ),
        phetioType: PropertyIO( NullableIO( QuadraticIO ) ),
        phetioDocumentation: 'the saved quadratic, null if there is no saved quadratic'
      } );

      // scale from model to view
      const modelViewTransformScale = GRAPH_VIEW_WIDTH / this.graph.xRange.getLength();

      // @public (read-only) model-view transform, created in the model because it's dependent on graph axes ranges.
      this.modelViewTransform = ModelViewTransform2.createOffsetXYScaleMapping(
        GRAPH_ORIGIN_OFFSET,
        modelViewTransformScale,
        -modelViewTransformScale // y is inverted (+y is up in the model, +y is down in the view)
      );

      // Options for {Property.<Quadratic[]>}
      const optionsPropertyQuadraticArray = {
        valueType: Array,
        isValidValue: array => _.every( array, function( value ) { return value instanceof Quadratic; } )
      };

      // {Property.<Quadratic[]>} Quadratics that are visible to the point tools.
      // ObservableArray is not used here because we need to change the entire array contents atomically.
      const pointToolQuadraticsProperty = new Property( [], optionsPropertyQuadraticArray );

      // @public {Property.<Quadratic[]>} optional quadratic terms to be displayed,
      // in the order that they will be considered by point tools.
      // ObservableArray is not used here because we need to change the entire array contents atomically.
      this.quadraticTermsProperty = new Property( [], optionsPropertyQuadraticArray );

      // @public (read-only)
      this.rightPointTool = new PointTool( pointToolQuadraticsProperty, {
        probeSide: 'right',
        location: new Vector2( -2, -12 ),
        dragBounds: new Bounds2(
          this.graph.xRange.min - 1, this.graph.yRange.min - 3,
          this.graph.xRange.max + 1, this.graph.yRange.max + 1 ),
        tandem: tandem.createTandem( 'rightPointTool' ),
        phetioDocumentation: 'the point tool whose probe is on the right side'
      } );

      // @public (read-only)
      this.leftPointTool = new PointTool( pointToolQuadraticsProperty, {
        probeSide: 'left',
        location: new Vector2( 2, -12 ),
        dragBounds: new Bounds2(
          this.graph.xRange.min - 1, this.graph.yRange.min - 3,
          this.graph.xRange.max + 1, this.graph.yRange.max + 1 ),
        tandem: tandem.createTandem( 'leftPointTool' ),
        phetioDocumentation: 'the point tool whose probe is on the left side'
      } );

      // @private Update the list of quadratics visible to the point tools,
      // in the order that they will be considered by the point tools.
      Property.multilink( [ this.quadraticProperty, this.quadraticTermsProperty, this.savedQuadraticProperty ],
        ( quadratic, quadraticTerms, savedQuadratic ) => {
          // order is important! compact to remove nulls
          pointToolQuadraticsProperty.value = _.compact( [ quadratic, ...quadraticTerms, savedQuadratic ] );
        } );
    }

    // @public
    reset() {
      this.savedQuadraticProperty.reset();
      this.rightPointTool.reset();
      this.leftPointTool.reset();
    }

    /**
     * Saves the current quadratic.
     * @public
     */
    saveQuadratic() {
      this.savedQuadraticProperty.value = this.quadraticProperty.value.withColor( GQColors.SAVED_CURVE );
    }

    /**
     * Erases the saved quadratic.
     * @public
     */
    eraseQuadratic() {
      this.savedQuadraticProperty.value = null;
    }
  }

  return graphingQuadratics.register( 'GQModel', GQModel );
} );
<|endoftext|>


<commit_before>var socket;
var room = null;
var roomHash = null;
var userData = null;
var userDataHash = null;
var username = "default";

function gotMessage(evt) {
  if (evt.origin === document.location.protocol + '//localhost:3000' || evt.origin === document.location.protocol + '//tjournal.ru') {
    var data = $.parseJSON(evt.data);

    userData = data.user;
    userDataHash = data.userHash;
    room = data.room;
    roomHash = data.roomHash;
    username = data.username;

    socket.open();
  }
}

$(function() {
  // Templates
  var template = $("#message-template").html();
  var messageTemplate = Handlebars.compile(template);

  var template = $("#online-user-template").html();
  var onlineUserTemplate = Handlebars.compile(template);

  var template = $("#message-typing-template").html();
  var messageTypingTemplate = Handlebars.compile(template);

  var autolinker = new Autolinker();

  var connected = false;
  var typing = false;
  var lastTypingTime;

  $(window).resize(function(){
    definePanelHeight();
  });
  definePanelHeight();

  // --------------------------------------------------------------

  function cleanInput(input) {
    return $('<div/>').text(input).text();
  }

  function changeStatus(status) {
    if (status === -1) {
      $('.lineIndicator').addClass('offline').removeClass('connecting');
    } else if (status === 0) {
      $('.lineIndicator').removeClass('offline').addClass('connecting');
    } else if (status === 1) {
      $('.lineIndicator').removeClass('offline').removeClass('connecting');
    }
  }

  function definePanelHeight() {
    var h = $('.baseHeight').height();
    var hh = $('.baseHeight .panel-heading').outerHeight();
    var fh = $('.baseHeight .panel-footer').outerHeight();

    $('#chatWindow').css('height', h - hh - fh);
    $('#onlineList').css('height', h - hh);
  }

  function updateOnlineList(data, action) {
    if (data.numUsers != undefined) {
      var dnum = parseInt(data.numUsers);

      var ch = ' человек';
      if (dnum < 5 || dnum > 1) {
        ch = ' человека';
      }

      $('.onlineCount').text(dnum + ch + ' онлайн');
    }

    if (data.user != undefined) {
      if (action === 'remove') {
        $('#onlineList .userOnline' + data.user.id + ' .media-object').animate({opacity: 0.1}, 500).animate({opacity: 1}, 500).animate({opacity: 0.1}, 500).animate({opacity: 1}, 500, 'swing', function(){
          $('.userOnline' + data.user.id).remove();
        });
      } else if ($('#onlineList .userOnline' + data.user.id).length === 0) {
        var userLi = onlineUserTemplate(data.user);
        $('#onlineList').append(userLi);

        $('#onlineList .userOnline' + data.user.id + ' .media-object').animate({opacity: 0.1}, 500).animate({opacity: 1}, 500).animate({opacity: 0.1}, 500).animate({opacity: 1}, 500);
      }
    }

    if (data.users != undefined) {
      var list = '';

      $.each(data.users, function(i, v) {
        list += onlineUserTemplate(v);
      });

      $('#onlineList').html(list);
    }

    $('#onlineList .userOnline' + userData.id).addClass('me');
  }

  function sendMessage() {
    var message = $('#messageInput').val();
    message = cleanInput(message);

    if (message && connected) {
      $('#messageInput').val('');

      socket.emit('new message', { text: message });
    }
  }

  function addChatMessage(data) {
    //removeChatTyping(data);
    data.message = autolinker.link(data.message);
    addMessageElement(messageTemplate(data));

    var messageDate = new Date(data.timestamp*1000);
    $(".message"+data.id+" .timestamp").text(messageDate.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1"));
  }

  function addCommandResponse(data) {
    var el = $('<li>').addClass('command-response');

    // /help doesn't contains unsec text
    if (data.command === 'help') {
      el = el.html(data.response);
    } else {
      el = el.text(data.response);
    }
    addMessageElement(el);
  }

  function log(message) {
    var el = $('<li>').addClass('log').text(message);
    addMessageElement(el);
  }

  function addMessageElement(el) {
    var scrolledToNewest = ($('#chatWindow').scrollTop() + $('#chatWindow').innerHeight() >= $('#chatWindow')[0].scrollHeight);

    $('#chatWindow').append(el);

    if (scrolledToNewest) {
      $('#chatWindow')[0].scrollTop = $('#chatWindow')[0].scrollHeight;
    }
  }

  function addChatTyping(data) {
    addMessageElement(messageTypingTemplate(data));
  }

  function removeChatTyping(data) {
    $('.typing'+data.user.id).remove();
  }

  function updateTyping() {
    return false;
    if (connected) {
      if (!typing) {
        typing = true;
        socket.emit('typing');
      }

      lastTypingTime = (new Date()).getTime();

      setTimeout(function() {
        var typingTimer = (new Date()).getTime();
        var timeDiff = typingTimer - lastTypingTime;
        if (timeDiff >= 500 && typing) {
          socket.emit('stop typing');
          typing = false;
        }
      }, 500);
    }
  }

  // --------------------------------------------------------------

  // Keyboard events
  $(window).keydown(function(event) {
    if (!(event.ctrlKey || event.metaKey || event.altKey)) {
      $('#messageInput').focus();
    }

    if (event.which === 13) {
      sendMessage();
      //socket.emit('stop typing');
      typing = false;
    }
  });

  $('#messageSubmitButton').click(function (event) {
    sendMessage();
    //socket.emit('stop typing');
    typing = false;
  });

  /*$('#messageInput').on('input', function() {
    updateTyping();
  });*/

  // --------------------------------------------------------------

  socket = io('//' + document.location.host, {
    reconnection: true,
    autoConnect: false
  });

  // Socket events
  socket.on('connect', function() {
    $('#chatWindow .waiting').remove();
    changeStatus(0);

    socket.emit('authentication', {
      user: userData,
      hash: userDataHash,
      username: username
    });
  });

  socket.on('reconnect', function() {
    socket.emit('add user', {
      room: room,
      roomHash: roomHash,
      socket: socket.io.engine.id
    });
  });

  socket.on('connect_error', function() {
    changeStatus(-1);
  });

  socket.on('disconnect', function() {
    connected = false;
    changeStatus(-1);

    socket.removeAllListeners('authenticated');
    socket.removeAllListeners('connect_error');

    log('Соединение с чатом прервано');
  });

  socket.on('authenticated', function() {
    socket.emit('add user', {
      room: room,
      roomHash: roomHash,
      socket: socket.io.engine.id
    });

    // login
    socket.on('login', function (data) {
      connected = true;
      changeStatus(1);

      log('Вы вошли в чат!');
      updateOnlineList(data);
    });

    // message
    socket.on('new message', function (data) {
      addChatMessage(data);
    });

    // user join & left
    socket.on('user joined', function (data) {
      updateOnlineList(data, 'add');
    });

    socket.on('user left', function (data) {
      updateOnlineList(data, 'remove');
      //removeChatTyping(data);
    });

    // typing
    /*socket.on('typing', function (data) {
      addChatTyping(data);
    });

    socket.on('stop typing', function (data) {
      removeChatTyping(data);
    });*/

    // ban
    socket.on('banned', function (data) {
      log(data.user + ' заблокирован на ' + data.period + ' минут');
    });

    socket.on('unbanned', function (data) {
      log(data.user + ' разблокирован');
    });

    // slash command response
    socket.on('command response', function (data) {
      addCommandResponse(data);
    });

    socket.on('reconnecting', function() {
      changeStatus(0);
    });

    socket.on('reconnect_failed', function() {
      changeStatus(-1);
    });

    socket.on('reconnect_error', function() {
      changeStatus(-1);
    });
  });

  socket.on('auth failed', function (data) {
    changeStatus(-1);
    alert('Access denied');
  });
});

if (window.addEventListener) {
  window.addEventListener("message", gotMessage, false);
}
else {
  window.attachEvent("onmessage", gotMessage);
}

// Scrolling on iOS
(function registerScrolling($) {
    var prevTouchPosition = {},
        scrollYClass = 'scroll-y',
        scrollXClass = 'scroll-x',
        searchTerms = '.' + scrollYClass + ', .' + scrollXClass;

    $('body').on('touchstart', function (e) {
        var $scroll = $(e.target).closest(searchTerms),
            targetTouch = e.originalEvent.targetTouches[0];

        // Store previous touch position if within a scroll element
        prevTouchPosition = $scroll.length ? { x: targetTouch.pageX, y: targetTouch.pageY } : {};
    });

$('body').on('touchmove', function (e) {
    var $scroll = $(e.target).closest(searchTerms),
        targetTouch = e.originalEvent.targetTouches[0];

    if (prevTouchPosition && $scroll.length) {
        // Set move helper and update previous touch position
        var move = {
            x: targetTouch.pageX - prevTouchPosition.x,
            y: targetTouch.pageY - prevTouchPosition.y
        };
        prevTouchPosition = { x: targetTouch.pageX, y: targetTouch.pageY };

        // Check for scroll-y or scroll-x classes
        if ($scroll.hasClass(scrollYClass)) {
            var scrollHeight = $scroll[0].scrollHeight,
                outerHeight = $scroll.outerHeight(),

                atUpperLimit = ($scroll.scrollTop() === 0),
                atLowerLimit = (scrollHeight - $scroll.scrollTop() === outerHeight);

            if (scrollHeight > outerHeight) {
                // If at either limit move 1px away to allow normal scroll behavior on future moves,
                // but stop propagation on this move to remove limit behavior bubbling up to body
                if (move.y > 0 && atUpperLimit) {
                    $scroll.scrollTop(1);
                    e.stopPropagation();
                } else if (move.y < 0 && atLowerLimit) {
                    $scroll.scrollTop($scroll.scrollTop() - 1);
                    e.stopPropagation();
                }

                // If only moving right or left, prevent bad scroll.
                if(Math.abs(move.x) > 0 && Math.abs(move.y) < 3){
                  e.preventDefault()
                }

                // Normal scrolling behavior passes through
            } else {
                // No scrolling / adjustment when there is nothing to scroll
                e.preventDefault();
            }
        } else if ($scroll.hasClass(scrollXClass)) {
            var scrollWidth = $scroll[0].scrollWidth,
                outerWidth = $scroll.outerWidth(),

                atLeftLimit = $scroll.scrollLeft() === 0,
                atRightLimit = scrollWidth - $scroll.scrollLeft() === outerWidth;

            if (scrollWidth > outerWidth) {
                if (move.x > 0 && atLeftLimit) {
                    $scroll.scrollLeft(1);
                    e.stopPropagation();
                } else if (move.x < 0 && atRightLimit) {
                    $scroll.scrollLeft($scroll.scrollLeft() - 1);
                    e.stopPropagation();
                }
                // If only moving up or down, prevent bad scroll.
                if(Math.abs(move.y) > 0 && Math.abs(move.x) < 3){
                  e.preventDefault();
                }

                // Normal scrolling behavior passes through
            } else {
                // No scrolling / adjustment when there is nothing to scroll
                e.preventDefault();
            }
        }
    } else {
        // Prevent scrolling on non-scrolling elements
        e.preventDefault();
    }
});
})(jQuery);
<commit_msg>fix a bug with reconnect<commit_after>var socket;
var room = null;
var roomHash = null;
var userData = null;
var userDataHash = null;
var username = "default";

function gotMessage(evt) {
  if (evt.origin === document.location.protocol + '//localhost:3000' || evt.origin === document.location.protocol + '//tjournal.ru') {
    var data = $.parseJSON(evt.data);

    userData = data.user;
    userDataHash = data.userHash;
    room = data.room;
    roomHash = data.roomHash;
    username = data.username;

    socket.open();
  }
}

$(function() {
  // Templates
  var template = $("#message-template").html();
  var messageTemplate = Handlebars.compile(template);

  var template = $("#online-user-template").html();
  var onlineUserTemplate = Handlebars.compile(template);

  var template = $("#message-typing-template").html();
  var messageTypingTemplate = Handlebars.compile(template);

  var autolinker = new Autolinker();

  var connected = false;
  var typing = false;
  var lastTypingTime;

  $(window).resize(function(){
    definePanelHeight();
  });
  definePanelHeight();

  // --------------------------------------------------------------

  function cleanInput(input) {
    return $('<div/>').text(input).text();
  }

  function changeStatus(status) {
    if (status === -1) {
      $('.lineIndicator').addClass('offline').removeClass('connecting');
    } else if (status === 0) {
      $('.lineIndicator').removeClass('offline').addClass('connecting');
    } else if (status === 1) {
      $('.lineIndicator').removeClass('offline').removeClass('connecting');
    }
  }

  function definePanelHeight() {
    var h = $('.baseHeight').height();
    var hh = $('.baseHeight .panel-heading').outerHeight();
    var fh = $('.baseHeight .panel-footer').outerHeight();

    $('#chatWindow').css('height', h - hh - fh);
    $('#onlineList').css('height', h - hh);
  }

  function updateOnlineList(data, action) {
    if (data.numUsers != undefined) {
      var dnum = parseInt(data.numUsers);

      var ch = ' человек';
      if (dnum < 5 || dnum > 1) {
        ch = ' человека';
      }

      $('.onlineCount').text(dnum + ch + ' онлайн');
    }

    if (data.user != undefined) {
      if (action === 'remove') {
        $('#onlineList .userOnline' + data.user.id + ' .media-object').animate({opacity: 0.1}, 500).animate({opacity: 1}, 500).animate({opacity: 0.1}, 500).animate({opacity: 1}, 500, 'swing', function(){
          $('.userOnline' + data.user.id).remove();
        });
      } else if ($('#onlineList .userOnline' + data.user.id).length === 0) {
        var userLi = onlineUserTemplate(data.user);
        $('#onlineList').append(userLi);

        $('#onlineList .userOnline' + data.user.id + ' .media-object').animate({opacity: 0.1}, 500).animate({opacity: 1}, 500).animate({opacity: 0.1}, 500).animate({opacity: 1}, 500);
      }
    }

    if (data.users != undefined) {
      var list = '';

      $.each(data.users, function(i, v) {
        list += onlineUserTemplate(v);
      });

      $('#onlineList').html(list);
    }

    $('#onlineList .userOnline' + userData.id).addClass('me');
  }

  function sendMessage() {
    var message = $('#messageInput').val();
    message = cleanInput(message);

    if (message && connected) {
      $('#messageInput').val('');

      socket.emit('new message', { text: message });
    }
  }

  function addChatMessage(data) {
    //removeChatTyping(data);
    if ($('.message' + data.id).length == 0) {
      data.message = autolinker.link(data.message);
      addMessageElement(messageTemplate(data));

      var messageDate = new Date(data.timestamp*1000);
      $(".message"+data.id+" .timestamp").text(messageDate.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1"));
    }
  }

  function addCommandResponse(data) {
    var el = $('<li>').addClass('command-response');

    // /help doesn't contains unsec text
    if (data.command === 'help') {
      el = el.html(data.response);
    } else {
      el = el.text(data.response);
    }
    addMessageElement(el);
  }

  function log(message) {
    var el = $('<li>').addClass('log').text(message);
    addMessageElement(el);
  }

  function addMessageElement(el) {
    var scrolledToNewest = ($('#chatWindow').scrollTop() + $('#chatWindow').innerHeight() >= $('#chatWindow')[0].scrollHeight);

    $('#chatWindow').append(el);

    if (scrolledToNewest) {
      $('#chatWindow')[0].scrollTop = $('#chatWindow')[0].scrollHeight;
    }
  }

  function addChatTyping(data) {
    addMessageElement(messageTypingTemplate(data));
  }

  function removeChatTyping(data) {
    $('.typing'+data.user.id).remove();
  }

  function updateTyping() {
    return false;
    if (connected) {
      if (!typing) {
        typing = true;
        socket.emit('typing');
      }

      lastTypingTime = (new Date()).getTime();

      setTimeout(function() {
        var typingTimer = (new Date()).getTime();
        var timeDiff = typingTimer - lastTypingTime;
        if (timeDiff >= 500 && typing) {
          socket.emit('stop typing');
          typing = false;
        }
      }, 500);
    }
  }

  // --------------------------------------------------------------

  // Keyboard events
  $(window).keydown(function(event) {
    if (!(event.ctrlKey || event.metaKey || event.altKey)) {
      $('#messageInput').focus();
    }

    if (event.which === 13) {
      sendMessage();
      //socket.emit('stop typing');
      typing = false;
    }
  });

  $('#messageSubmitButton').click(function (event) {
    sendMessage();
    //socket.emit('stop typing');
    typing = false;
  });

  /*$('#messageInput').on('input', function() {
    updateTyping();
  });*/

  // --------------------------------------------------------------

  socket = io('//' + document.location.host, {
    reconnection: true,
    autoConnect: false
  });

  // Socket events
  socket.on('connect', function() {
    $('#chatWindow .waiting').remove();
    changeStatus(0);

    socket.emit('authentication', {
      user: userData,
      hash: userDataHash,
      username: username
    });
  });

  socket.on('reconnect', function() {
    socket.emit('add user', {
      room: room,
      roomHash: roomHash,
      socket: socket.io.engine.id
    });
  });

  socket.on('connect_error', function() {
    changeStatus(-1);
  });

  socket.on('disconnect', function() {
    connected = false;
    changeStatus(-1);

    socket.removeAllListeners('authenticated');
    socket.removeAllListeners('connect_error');

    log('Соединение с чатом прервано');
  });

  socket.on('authenticated', function() {
    socket.emit('add user', {
      room: room,
      roomHash: roomHash,
      socket: socket.io.engine.id
    });

    // login
    socket.on('login', function (data) {
      connected = true;
      changeStatus(1);

      log('Вы вошли в чат!');
      updateOnlineList(data);
    });

    // message
    socket.on('new message', function (data) {
      addChatMessage(data);
    });

    // user join & left
    socket.on('user joined', function (data) {
      updateOnlineList(data, 'add');
    });

    socket.on('user left', function (data) {
      updateOnlineList(data, 'remove');
      //removeChatTyping(data);
    });

    // typing
    /*socket.on('typing', function (data) {
      addChatTyping(data);
    });

    socket.on('stop typing', function (data) {
      removeChatTyping(data);
    });*/

    // ban
    socket.on('banned', function (data) {
      log(data.user + ' заблокирован на ' + data.period + ' минут');
    });

    socket.on('unbanned', function (data) {
      log(data.user + ' разблокирован');
    });

    // slash command response
    socket.on('command response', function (data) {
      addCommandResponse(data);
    });

    socket.on('reconnecting', function() {
      changeStatus(0);
    });

    socket.on('reconnect_failed', function() {
      changeStatus(-1);
    });

    socket.on('reconnect_error', function() {
      changeStatus(-1);
    });
  });

  socket.on('auth failed', function (data) {
    changeStatus(-1);
    alert('Access denied');
  });
});

if (window.addEventListener) {
  window.addEventListener("message", gotMessage, false);
}
else {
  window.attachEvent("onmessage", gotMessage);
}

// Scrolling on iOS
(function registerScrolling($) {
    var prevTouchPosition = {},
        scrollYClass = 'scroll-y',
        scrollXClass = 'scroll-x',
        searchTerms = '.' + scrollYClass + ', .' + scrollXClass;

    $('body').on('touchstart', function (e) {
        var $scroll = $(e.target).closest(searchTerms),
            targetTouch = e.originalEvent.targetTouches[0];

        // Store previous touch position if within a scroll element
        prevTouchPosition = $scroll.length ? { x: targetTouch.pageX, y: targetTouch.pageY } : {};
    });

$('body').on('touchmove', function (e) {
    var $scroll = $(e.target).closest(searchTerms),
        targetTouch = e.originalEvent.targetTouches[0];

    if (prevTouchPosition && $scroll.length) {
        // Set move helper and update previous touch position
        var move = {
            x: targetTouch.pageX - prevTouchPosition.x,
            y: targetTouch.pageY - prevTouchPosition.y
        };
        prevTouchPosition = { x: targetTouch.pageX, y: targetTouch.pageY };

        // Check for scroll-y or scroll-x classes
        if ($scroll.hasClass(scrollYClass)) {
            var scrollHeight = $scroll[0].scrollHeight,
                outerHeight = $scroll.outerHeight(),

                atUpperLimit = ($scroll.scrollTop() === 0),
                atLowerLimit = (scrollHeight - $scroll.scrollTop() === outerHeight);

            if (scrollHeight > outerHeight) {
                // If at either limit move 1px away to allow normal scroll behavior on future moves,
                // but stop propagation on this move to remove limit behavior bubbling up to body
                if (move.y > 0 && atUpperLimit) {
                    $scroll.scrollTop(1);
                    e.stopPropagation();
                } else if (move.y < 0 && atLowerLimit) {
                    $scroll.scrollTop($scroll.scrollTop() - 1);
                    e.stopPropagation();
                }

                // If only moving right or left, prevent bad scroll.
                if(Math.abs(move.x) > 0 && Math.abs(move.y) < 3){
                  e.preventDefault()
                }

                // Normal scrolling behavior passes through
            } else {
                // No scrolling / adjustment when there is nothing to scroll
                e.preventDefault();
            }
        } else if ($scroll.hasClass(scrollXClass)) {
            var scrollWidth = $scroll[0].scrollWidth,
                outerWidth = $scroll.outerWidth(),

                atLeftLimit = $scroll.scrollLeft() === 0,
                atRightLimit = scrollWidth - $scroll.scrollLeft() === outerWidth;

            if (scrollWidth > outerWidth) {
                if (move.x > 0 && atLeftLimit) {
                    $scroll.scrollLeft(1);
                    e.stopPropagation();
                } else if (move.x < 0 && atRightLimit) {
                    $scroll.scrollLeft($scroll.scrollLeft() - 1);
                    e.stopPropagation();
                }
                // If only moving up or down, prevent bad scroll.
                if(Math.abs(move.y) > 0 && Math.abs(move.x) < 3){
                  e.preventDefault();
                }

                // Normal scrolling behavior passes through
            } else {
                // No scrolling / adjustment when there is nothing to scroll
                e.preventDefault();
            }
        }
    } else {
        // Prevent scrolling on non-scrolling elements
        e.preventDefault();
    }
});
})(jQuery);
<|endoftext|>


<commit_before>/* openslides-site.js */

angular.module('openslides-website', [
    'duScroll',
    'gettext',
    'ngAnimate',
    'ui.bootstrap',
    'ui.router'
])

.config([
    '$urlRouterProvider',
    '$locationProvider',
    function($urlRouterProvider, $locationProvider) {
        // define fallback url and html5Mode
        $urlRouterProvider.otherwise('/');
        $locationProvider.html5Mode(true);
    }
])

.config([
    '$stateProvider',
    '$locationProvider',
    '$urlRouterProvider',
    function ($stateProvider, $locationProvider, $urlRouterProvider) {
        $stateProvider
            .state('home', {
                url: '/',
                templateUrl: 'static/views/home.html'
            })
            .state('press', {
                url: '/press',
                templateUrl: 'static/views/press.html'
            })
            .state('references', {
                url: '/references',
                templateUrl: 'static/views/references.html'
            })
            .state('legalnotice', {
                url: '/legalnotice',
                templateUrl: 'static/views/legalnotice.html'
            })
            // press news
            .state('20141125', {
                url: '/20141125',
                templateUrl: 'static/views/news-20141125.html'
            })
            .state('20121119', {
                url: '/20121119',
                templateUrl: 'static/views/news-20121119.html'
            });

        // redirect to 'home' for error states
        $urlRouterProvider.otherwise(function ($injector, $location) {
            $injector.invoke(['$state', function ($state) { $state.go('home'); }]);
            return true;
        });
    }
])

// gets all available languages
.factory('Languages', [
    'gettext',
    'gettextCatalog',
    function (gettext, gettextCatalog) {
        return {
            // get all available languages
            getLanguages: function () {
                var current = gettextCatalog.getCurrentLanguage();
                // Define here new languages...
                var languages = [
                    { code: 'en', name: 'English' },
                    { code: 'de', name: 'Deutsch' },
                    { code: 'es', name: 'Español' },
                    { code: 'pt', name: 'Português' },
                    { code: 'cs', name: 'Český' },
                ];
                angular.forEach(languages, function (language) {
                    if (language.code == current)
                        language.selected = true;
                });
                return languages;
            },
            // get detected browser language code
            getBrowserLanguage: function () {
                var lang = navigator.language || navigator.userLanguage;
                if (lang.indexOf('-') !== -1)
                    lang = lang.split('-')[0];
                if (lang.indexOf('_') !== -1)
                    lang = lang.split('_')[0];
                return lang;
            },
            // set current language and return updated languages object array
            setCurrentLanguage: function (lang) {
                var languages = this.getLanguages();
                angular.forEach(languages, function (language) {
                    language.selected = false;
                    if (language.code == lang) {
                        language.selected = true;
                        gettextCatalog.setCurrentLanguage(lang);
                        if (lang != 'en') {
                            gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
                        }
                    }
                });
                return languages;
            }
        };
    }
])

// set browser language as default language for OpenSlides
.run([
    '$rootScope',
    '$state',
    '$location',
    'gettextCatalog',
    'Languages',
    function($rootScope, $state, $location, gettextCatalog, Languages) {
        // set language spezified by query params (?lang=en) or browser language
        var urlQuery = $location.search(),
            langCodes = [],
            languages = Languages.getLanguages();
        for (var key in languages) { // I would prefer a quick _.map
            langCodes.push(languages[key].code);
        }

        if (urlQuery.lang && langCodes.indexOf(urlQuery.lang) > -1) {
            Languages.setCurrentLanguage(urlQuery.lang);
        } else {
            Languages.setCurrentLanguage(Languages.getBrowserLanguage());
        }

        // Set this to true for debug. Helps to find untranslated strings by
        // adding "[MISSING]:".
        gettextCatalog.debug = false;
    }
])
.controller('ScrollCtrl', [
    '$document',
    function ($document ) {
        $document.scrollTop(0);
    }
])

.controller('MenuCtrl', [
    '$scope',
    function ($scope) {
        $scope.isMenuOpen = false;
        $scope.closeMenu = function () {
            $scope.isMenuOpen = false;
        };
    }
])

.controller('LanguageCtrl', [
    '$scope',
    '$location',
    'Languages',
    'filterFilter',
    function ($scope, $location, Languages, filterFilter) {
        // get all available languages
        $scope.languages = Languages.getLanguages();
        // get detected browser language code
        $scope.selectedLangCode = filterFilter($scope.languages, {selected: true})[0].code;
        // controller to switch app language
        $scope.switchLanguage = function (lang) {
            $scope.languages = Languages.setCurrentLanguage(lang);
            $scope.selectedLangCode = filterFilter($scope.languages, {selected: true})[0].code;
        };
        $scope.getLanguageHref = function (lang) {
            return $location.$$absUrl.split('?')[0] + '?lang=' + lang;
        };
    }
])

.controller('ReferenceCtrl', [
    '$scope',
    function ($scope) {
        $scope.page = 0;
        $scope.numberPerPage = 5;
        $scope.logos = [
            { name: 'SPD',
              event: 'Landes-AK "Digitale Gesellschaft"',
              src:  'spd-logo.png' },
            { name: 'BÜNDNIS 90/DIE GRÜNEN',
              event: 'Landesparteitage Hamburg / Hessen / Schleswig-Holstein',
              src:  'gruene-logo.png' },
            { name: 'Grüne Jugend',
              event: 'Bundeskongress',
              src:  'gruene-jugend-logo.png' },
            { name: 'Sächsische Landesärztekammer',
              event: 'Kammerversammlung',
              src:  'slaek-logo.png' },
            { name: 'Landesärztekammer Hessen',
              event: 'Delegiertenversammlung',
              src:  'laekh-logo.png' },
            { name: 'Piratenpartei Deutschland / Schweiz',
              event: 'Bundes-, Landes- und Kreisparteitage',
              src:  'piraten-logo.png' },
            { name: 'Piraten ohne Grenzen',
              event: 'Piratenversammlung',
              src:  'pog-logo.png' },
            { name: 'Junge Generation in der SPÖ Wien',
              event: 'Landeskonferenz',
              src:  'jgspoe-logo.png' },
            { name: 'innovate!',
              event: 'innovate!Award-Preisverleihung (mit elektronischer Abstimmung) am 7.11.2013',
              src:  'innovate2013-logo.png' },
            { name: 'Evangelische StudentInnengemeinde in der Bundesrepublik Deutschland (ESG)',
              event: 'Bundesversammlung',
              src:  'esg-logo.png' },
            { name: 'Arbeitsgemeinschaft der Evangelischen Jugend in Deutschland e. V. (aej)',
              event: 'Mitgliederversammlung',
              src:  'aej-logo.png' },
            { name: 'Opennet Initiative e.V.',
              event: 'Jahresversammlung',
              src:  'opennet-logo.png' },
            { name: 'Studierende Cusanerinnen und Cusaner',
              event: 'Cusanerkonferenz, Vollversammlung',
              src:  'cusaner-logo.png' },
            { name: 'AStA der Universität des Saarlandes',
              event: 'Studierendenparlament',
              src:  'asta-uni-saarland-logo.png' },
            { name: 'Evangelischer Kirchenkreis Krefeld-Viersen',
              event: 'Kreissynode',
              src:  'ev-kirche-krefeld-viersen-logo.png' },
            { name: 'Mensa in Deutschland e.V.',
              event: 'Mitgliederversammlung',
              src:  'mensa-logo.png' },
            { name: 'Bund der Pfadfinderinnen und Pfadfinder e.V.',
              event: 'Bundesversammlung',
              src:  'bdp-logo.png' },
            { name: 'Berufsverband der Kinder- und Jugendärzte e.V.',
              event: 'Delegiertenversammlung',
              src:  'bvkj-logo.png' },
            { name: 'Deutscher Verband für Neuro-Linguistisches Programmieren e.V.',
              event: 'Mitgliederversammlung',
              src:  'dvnlp-logo.png' },
        ];
        $scope.maxpage = Math.ceil($scope.logos.length / $scope.numberPerPage) - 1;

        $scope.moveLeft = function () {
            if ($scope.page > 0) {
                $scope.page--;
            } else {
                $scope.page = $scope.maxpage;
            }
        };
        $scope.moveRight = function () {
            var nextLogoIndex = ($scope.page + 1) * $scope.numberPerPage + 1;
            if (nextLogoIndex <= $scope.logos.length) {
                $scope.page++;
            } else {
                $scope.page = 0;
            };
        };
    }
])

.controller('DownloadCtrl', [
    '$scope',
    function ($scope) {
        $scope.stableVersion = '2.0';
        $scope.stableDate = '2016-04-18';
        //$scope.betaVersion = '2.0b5';
        //$scope.betaDate = '2016-03-21';
    }
])

.controller('PluginCtrl', [
    '$scope',
    'gettext',
    function ($scope, gettext) {
        $scope.plugins = [
            { name: 'CSV Export Plugin',
              desc: gettext('Provides a CSV export of the lists of speakers. It is also useful as an example how to write plugins for OpenSlides.'),
              url:  'https://github.com/OpenSlides/openslides-csv-export',
              tags: ['2.0']
            },
            { name: 'VoteCollector Plugin',
              desc: gettext('Connects OpenSlides with the electronic voting system VoteCollector.'),
              url:  'https://github.com/OpenSlides/openslides-votecollector',
              tags: ['2.1']
            },
            { name: 'Export Plugin',
              desc: gettext('Exports OpenSlides data in several formats (e.g. ODT, HTML, CSV).'),
              url:  'https://github.com/OpenSlides/openslides-export',
              tags: ['1.7']
            },
            { name: 'Protocol Plugin (Beta)',
              desc: gettext('Provides protocolling of agenda items in OpenSlides.'),
              url:  'https://github.com/OpenSlides/openslides-protocol',
              tags: ['1.7']
            }
        ];
    }
])

<commit_msg>Publish 2.1b1 release.<commit_after>/* openslides-site.js */

angular.module('openslides-website', [
    'duScroll',
    'gettext',
    'ngAnimate',
    'ui.bootstrap',
    'ui.router'
])

.config([
    '$urlRouterProvider',
    '$locationProvider',
    function($urlRouterProvider, $locationProvider) {
        // define fallback url and html5Mode
        $urlRouterProvider.otherwise('/');
        $locationProvider.html5Mode(true);
    }
])

.config([
    '$stateProvider',
    '$locationProvider',
    '$urlRouterProvider',
    function ($stateProvider, $locationProvider, $urlRouterProvider) {
        $stateProvider
            .state('home', {
                url: '/',
                templateUrl: 'static/views/home.html'
            })
            .state('press', {
                url: '/press',
                templateUrl: 'static/views/press.html'
            })
            .state('references', {
                url: '/references',
                templateUrl: 'static/views/references.html'
            })
            .state('legalnotice', {
                url: '/legalnotice',
                templateUrl: 'static/views/legalnotice.html'
            })
            // press news
            .state('20141125', {
                url: '/20141125',
                templateUrl: 'static/views/news-20141125.html'
            })
            .state('20121119', {
                url: '/20121119',
                templateUrl: 'static/views/news-20121119.html'
            });

        // redirect to 'home' for error states
        $urlRouterProvider.otherwise(function ($injector, $location) {
            $injector.invoke(['$state', function ($state) { $state.go('home'); }]);
            return true;
        });
    }
])

// gets all available languages
.factory('Languages', [
    'gettext',
    'gettextCatalog',
    function (gettext, gettextCatalog) {
        return {
            // get all available languages
            getLanguages: function () {
                var current = gettextCatalog.getCurrentLanguage();
                // Define here new languages...
                var languages = [
                    { code: 'en', name: 'English' },
                    { code: 'de', name: 'Deutsch' },
                    { code: 'es', name: 'Español' },
                    { code: 'pt', name: 'Português' },
                    { code: 'cs', name: 'Český' },
                ];
                angular.forEach(languages, function (language) {
                    if (language.code == current)
                        language.selected = true;
                });
                return languages;
            },
            // get detected browser language code
            getBrowserLanguage: function () {
                var lang = navigator.language || navigator.userLanguage;
                if (lang.indexOf('-') !== -1)
                    lang = lang.split('-')[0];
                if (lang.indexOf('_') !== -1)
                    lang = lang.split('_')[0];
                return lang;
            },
            // set current language and return updated languages object array
            setCurrentLanguage: function (lang) {
                var languages = this.getLanguages();
                angular.forEach(languages, function (language) {
                    language.selected = false;
                    if (language.code == lang) {
                        language.selected = true;
                        gettextCatalog.setCurrentLanguage(lang);
                        if (lang != 'en') {
                            gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
                        }
                    }
                });
                return languages;
            }
        };
    }
])

// set browser language as default language for OpenSlides
.run([
    '$rootScope',
    '$state',
    '$location',
    'gettextCatalog',
    'Languages',
    function($rootScope, $state, $location, gettextCatalog, Languages) {
        // set language spezified by query params (?lang=en) or browser language
        var urlQuery = $location.search(),
            langCodes = [],
            languages = Languages.getLanguages();
        for (var key in languages) { // I would prefer a quick _.map
            langCodes.push(languages[key].code);
        }

        if (urlQuery.lang && langCodes.indexOf(urlQuery.lang) > -1) {
            Languages.setCurrentLanguage(urlQuery.lang);
        } else {
            Languages.setCurrentLanguage(Languages.getBrowserLanguage());
        }

        // Set this to true for debug. Helps to find untranslated strings by
        // adding "[MISSING]:".
        gettextCatalog.debug = false;
    }
])
.controller('ScrollCtrl', [
    '$document',
    function ($document ) {
        $document.scrollTop(0);
    }
])

.controller('MenuCtrl', [
    '$scope',
    function ($scope) {
        $scope.isMenuOpen = false;
        $scope.closeMenu = function () {
            $scope.isMenuOpen = false;
        };
    }
])

.controller('LanguageCtrl', [
    '$scope',
    '$location',
    'Languages',
    'filterFilter',
    function ($scope, $location, Languages, filterFilter) {
        // get all available languages
        $scope.languages = Languages.getLanguages();
        // get detected browser language code
        $scope.selectedLangCode = filterFilter($scope.languages, {selected: true})[0].code;
        // controller to switch app language
        $scope.switchLanguage = function (lang) {
            $scope.languages = Languages.setCurrentLanguage(lang);
            $scope.selectedLangCode = filterFilter($scope.languages, {selected: true})[0].code;
        };
        $scope.getLanguageHref = function (lang) {
            return $location.$$absUrl.split('?')[0] + '?lang=' + lang;
        };
    }
])

.controller('ReferenceCtrl', [
    '$scope',
    function ($scope) {
        $scope.page = 0;
        $scope.numberPerPage = 5;
        $scope.logos = [
            { name: 'SPD',
              event: 'Landes-AK "Digitale Gesellschaft"',
              src:  'spd-logo.png' },
            { name: 'BÜNDNIS 90/DIE GRÜNEN',
              event: 'Landesparteitage Hamburg / Hessen / Schleswig-Holstein',
              src:  'gruene-logo.png' },
            { name: 'Grüne Jugend',
              event: 'Bundeskongress',
              src:  'gruene-jugend-logo.png' },
            { name: 'Sächsische Landesärztekammer',
              event: 'Kammerversammlung',
              src:  'slaek-logo.png' },
            { name: 'Landesärztekammer Hessen',
              event: 'Delegiertenversammlung',
              src:  'laekh-logo.png' },
            { name: 'Piratenpartei Deutschland / Schweiz',
              event: 'Bundes-, Landes- und Kreisparteitage',
              src:  'piraten-logo.png' },
            { name: 'Piraten ohne Grenzen',
              event: 'Piratenversammlung',
              src:  'pog-logo.png' },
            { name: 'Junge Generation in der SPÖ Wien',
              event: 'Landeskonferenz',
              src:  'jgspoe-logo.png' },
            { name: 'innovate!',
              event: 'innovate!Award-Preisverleihung (mit elektronischer Abstimmung) am 7.11.2013',
              src:  'innovate2013-logo.png' },
            { name: 'Evangelische StudentInnengemeinde in der Bundesrepublik Deutschland (ESG)',
              event: 'Bundesversammlung',
              src:  'esg-logo.png' },
            { name: 'Arbeitsgemeinschaft der Evangelischen Jugend in Deutschland e. V. (aej)',
              event: 'Mitgliederversammlung',
              src:  'aej-logo.png' },
            { name: 'Opennet Initiative e.V.',
              event: 'Jahresversammlung',
              src:  'opennet-logo.png' },
            { name: 'Studierende Cusanerinnen und Cusaner',
              event: 'Cusanerkonferenz, Vollversammlung',
              src:  'cusaner-logo.png' },
            { name: 'AStA der Universität des Saarlandes',
              event: 'Studierendenparlament',
              src:  'asta-uni-saarland-logo.png' },
            { name: 'Evangelischer Kirchenkreis Krefeld-Viersen',
              event: 'Kreissynode',
              src:  'ev-kirche-krefeld-viersen-logo.png' },
            { name: 'Mensa in Deutschland e.V.',
              event: 'Mitgliederversammlung',
              src:  'mensa-logo.png' },
            { name: 'Bund der Pfadfinderinnen und Pfadfinder e.V.',
              event: 'Bundesversammlung',
              src:  'bdp-logo.png' },
            { name: 'Berufsverband der Kinder- und Jugendärzte e.V.',
              event: 'Delegiertenversammlung',
              src:  'bvkj-logo.png' },
            { name: 'Deutscher Verband für Neuro-Linguistisches Programmieren e.V.',
              event: 'Mitgliederversammlung',
              src:  'dvnlp-logo.png' },
        ];
        $scope.maxpage = Math.ceil($scope.logos.length / $scope.numberPerPage) - 1;

        $scope.moveLeft = function () {
            if ($scope.page > 0) {
                $scope.page--;
            } else {
                $scope.page = $scope.maxpage;
            }
        };
        $scope.moveRight = function () {
            var nextLogoIndex = ($scope.page + 1) * $scope.numberPerPage + 1;
            if (nextLogoIndex <= $scope.logos.length) {
                $scope.page++;
            } else {
                $scope.page = 0;
            };
        };
    }
])

.controller('DownloadCtrl', [
    '$scope',
    function ($scope) {
        $scope.stableVersion = '2.0';
        $scope.stableDate = '2016-04-18';
        $scope.betaVersion = '2.1b1';
        $scope.betaDate = '2016-12-17';
    }
])

.controller('PluginCtrl', [
    '$scope',
    'gettext',
    function ($scope, gettext) {
        $scope.plugins = [
            { name: 'CSV Export Plugin',
              desc: gettext('Provides a CSV export of the lists of speakers. It is also useful as an example how to write plugins for OpenSlides.'),
              url:  'https://github.com/OpenSlides/openslides-csv-export',
              tags: ['2.0']
            },
            { name: 'VoteCollector Plugin',
              desc: gettext('Connects OpenSlides with the electronic voting system VoteCollector.'),
              url:  'https://github.com/OpenSlides/openslides-votecollector',
              tags: ['2.1']
            },
            { name: 'Export Plugin',
              desc: gettext('Exports OpenSlides data in several formats (e.g. ODT, HTML, CSV).'),
              url:  'https://github.com/OpenSlides/openslides-export',
              tags: ['1.7']
            },
            { name: 'Protocol Plugin (Beta)',
              desc: gettext('Provides protocolling of agenda items in OpenSlides.'),
              url:  'https://github.com/OpenSlides/openslides-protocol',
              tags: ['1.7']
            }
        ];
    }
])

<|endoftext|>


<commit_before>(function(app) {
  'use strict';

  var jCore = require('jcore');
  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');

  var Component = helper.inherits(function(props) {
    Component.super_.call(this);

    this.element = this.prop(props.element);
    this.cache = this.prop({});
  }, jCore.Component);

  Component.prototype.needsUpdate = function(keys) {
    return keys.some(function(key) {
      var cache = this.cache();
      var value = this[key]();
      return (value !== cache[key]);
    }.bind(this));
  };

  Component.prototype.values = function(keys) {
    return keys.map(function(key) {
      return this[key]();
    }.bind(this))
  };

  Component.prototype.updateCache = function(keys) {
    keys.forEach(function(key) {
      var cache = this.cache();
      var value = this[key]();
      cache[key] = value;
    }.bind(this));
  };

  Component.prototype.redrawProp = function() {
    var args = Array.prototype.slice.call(arguments);
    var callback = args.pop();

    if (this.needsUpdate(args)) {
      callback.apply(null, this.values(args));
      this.updateCache(args);
    }
  };

  Component.prototype.redrawToggleClass = function(key, className) {
    this.redrawProp(key, function(value) {
      dom.toggleClass(this.element(), className, value);
    }.bind(this));
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = Component;
  } else {
    app.Component = Component;
  }
})(this.app || (this.app = {}));
<commit_msg>Bind a caller component to callback of 'redrawProp' method as the 'this' parameter<commit_after>(function(app) {
  'use strict';

  var jCore = require('jcore');
  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');

  var Component = helper.inherits(function(props) {
    Component.super_.call(this);

    this.element = this.prop(props.element);
    this.cache = this.prop({});
  }, jCore.Component);

  Component.prototype.needsUpdate = function(keys) {
    return keys.some(function(key) {
      var cache = this.cache();
      var value = this[key]();
      return (value !== cache[key]);
    }.bind(this));
  };

  Component.prototype.values = function(keys) {
    return keys.map(function(key) {
      return this[key]();
    }.bind(this))
  };

  Component.prototype.updateCache = function(keys) {
    keys.forEach(function(key) {
      var cache = this.cache();
      var value = this[key]();
      cache[key] = value;
    }.bind(this));
  };

  Component.prototype.redrawProp = function() {
    var args = Array.prototype.slice.call(arguments);
    var callback = args.pop();

    if (this.needsUpdate(args)) {
      callback.apply(this, this.values(args));
      this.updateCache(args);
    }
  };

  Component.prototype.redrawToggleClass = function(key, className) {
    this.redrawProp(key, function(value) {
      dom.toggleClass(this.element(), className, value);
    });
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = Component;
  } else {
    app.Component = Component;
  }
})(this.app || (this.app = {}));
<|endoftext|>


<commit_before>// Modified version of https://github.com/douglascrockford/JSON-js/blob/master/cycle.js
// Handle DOM elements
// Removed global reference
// Stop traversing beyond a max depth

/*
    cycle.js
    2013-02-19

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*jslint evil: true, regexp: true */

/*members $ref, apply, call, decycle, hasOwnProperty, length, prototype, push,
    retrocycle, stringify, test, toString, nodeType
*/
/* exported decycle */
'use strict';

function decycle(object, maxDepth) {
  // Make a deep copy of an object or array, assuring that there is at most
  // one instance of each object or array in the resulting structure. The
  // duplicate references (which might be forming cycles) are replaced with
  // an object of the form
  //      {$ref: PATH}
  // where the PATH is a JSONPath string that locates the first occurance.
  // So,
  //      var a = [];
  //      a[0] = a;
  //      return JSON.stringify(JSON.decycle(a));
  // produces the string '[{"$ref":"$"}]'.

  // JSONPath is used to locate the unique object. $ indicates the top level of
  // the object or array. [NUMBER] or [STRING] indicates a child member or
  // property.

  var objects = [];   // Keep a reference to each unique object or array
  var paths = [];     // Keep the path to each unique object or array

  maxDepth = maxDepth || 5;
  return (function derez(value, path, depth) {
    if (depth > maxDepth) {
      return 'Max depth.';
    }

    // The derez recurses through the object, producing the deep copy.

    var i,          // The loop counter
        name,       // Property name
        nu;         // The new object or array

    // typeof null === 'object', so go on if this value is really an object but not
    // one of the weird builtin objects.
    // Handle DOM elements
    if (value === null || typeof value === 'undefined' || value instanceof Boolean || value instanceof Number) {
      return value;
    }
    if (typeof value === 'object' && typeof value.nodeType === 'number') {
      return String(value);
    }

    if (typeof value === 'object' && value !== null &&
            !(value instanceof Date)    &&
            !(value instanceof RegExp)  &&
            !(value instanceof String)) {

      // If the value is an object or array, look to see if we have already
      // encountered it. If so, return a $ref/path object. This is a hard way,
      // linear search that will get slower as the number of unique objects grows.

      for (i = 0; i < objects.length; i += 1) {
        if (objects[i] === value) {
          return {$ref: paths[i]};
        }
      }

      // Otherwise, accumulate the unique value and its path.

      objects.push(value);
      paths.push(path);

      // If it is an array, replicate the array.

      if (Object.prototype.toString.apply(value) === '[object Array]') {
        nu = [];
        for (i = 0; i < value.length; i += 1) {
          nu[i] = derez(value[i], path + '[' + i + ']', depth + 1);
        }
      } else {

        // If it is an object, replicate the object.

        nu = {};
        for (name in value) {
          if (Object.prototype.hasOwnProperty.call(value, name)) {
            nu[name] = derez(value[name],
              path + '[' + JSON.stringify(name) + ']', depth + 1);
          }
        }
      }
      return nu;
    }
    return value;
  }(object, '$', 0));
}
<commit_msg>Better message about client_cycle_depth (#1171)<commit_after>// Modified version of https://github.com/douglascrockford/JSON-js/blob/master/cycle.js
// Handle DOM elements
// Removed global reference
// Stop traversing beyond a max depth

/*
    cycle.js
    2013-02-19

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*jslint evil: true, regexp: true */

/*members $ref, apply, call, decycle, hasOwnProperty, length, prototype, push,
    retrocycle, stringify, test, toString, nodeType
*/
/* exported decycle */
'use strict';

function decycle(object, maxDepth) {
  // Make a deep copy of an object or array, assuring that there is at most
  // one instance of each object or array in the resulting structure. The
  // duplicate references (which might be forming cycles) are replaced with
  // an object of the form
  //      {$ref: PATH}
  // where the PATH is a JSONPath string that locates the first occurance.
  // So,
  //      var a = [];
  //      a[0] = a;
  //      return JSON.stringify(JSON.decycle(a));
  // produces the string '[{"$ref":"$"}]'.

  // JSONPath is used to locate the unique object. $ indicates the top level of
  // the object or array. [NUMBER] or [STRING] indicates a child member or
  // property.

  var objects = [];   // Keep a reference to each unique object or array
  var paths = [];     // Keep the path to each unique object or array

  maxDepth = maxDepth || 5;
  return (function derez(value, path, depth) {
    if (depth > maxDepth) {
      return 'Decycle max depth reached at ' + maxDepth + '. You may override the default by setting "client_decycle_depth" in your testem config.';
    }

    // The derez recurses through the object, producing the deep copy.

    var i,          // The loop counter
        name,       // Property name
        nu;         // The new object or array

    // typeof null === 'object', so go on if this value is really an object but not
    // one of the weird builtin objects.
    // Handle DOM elements
    if (value === null || typeof value === 'undefined' || value instanceof Boolean || value instanceof Number) {
      return value;
    }
    if (typeof value === 'object' && typeof value.nodeType === 'number') {
      return String(value);
    }

    if (typeof value === 'object' && value !== null &&
            !(value instanceof Date)    &&
            !(value instanceof RegExp)  &&
            !(value instanceof String)) {

      // If the value is an object or array, look to see if we have already
      // encountered it. If so, return a $ref/path object. This is a hard way,
      // linear search that will get slower as the number of unique objects grows.

      for (i = 0; i < objects.length; i += 1) {
        if (objects[i] === value) {
          return {$ref: paths[i]};
        }
      }

      // Otherwise, accumulate the unique value and its path.

      objects.push(value);
      paths.push(path);

      // If it is an array, replicate the array.

      if (Object.prototype.toString.apply(value) === '[object Array]') {
        nu = [];
        for (i = 0; i < value.length; i += 1) {
          nu[i] = derez(value[i], path + '[' + i + ']', depth + 1);
        }
      } else {

        // If it is an object, replicate the object.

        nu = {};
        for (name in value) {
          if (Object.prototype.hasOwnProperty.call(value, name)) {
            nu[name] = derez(value[name],
              path + '[' + JSON.stringify(name) + ']', depth + 1);
          }
        }
      }
      return nu;
    }
    return value;
  }(object, '$', 0));
}
<|endoftext|>


<commit_before>if ( typeof Fuzzy == 'undefined') {
    Fuzzy = {};
}

(function() {
    this.ColorFilters = {
        RED: "red",
        GREEN: "green",
        BLUE: "blue",
        NONE: "none"
    }

    this.Pixelate = function(ctx, pixelsize) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);
        pixelsize = pixelsize <= 0 ? 1 : pixelsize;

        for(var i = 0; i < width; i += pixelsize) {
            for(var j = 0; j < width; j += pixelsize) {
                var offsetx = (pixelsize / 2) | 0;
                var offsety = (pixelsize / 2) | 0;

		        while(i + offsetx >= width) {
		            offsetx--;
		        }

		        while(j + offsety >= height) {
		            offsety--;
		        }

		        var pixel = _getPixel(imgData, i + offsetx, j + offsety);

		        for(var x = i; x < i + pixelsize && x < width; x++) {
		            for(var y = j; y < j + pixelsize && y < height; y++){
		                _setPixel(imgData, x, y, pixel) {
                    }
                }
            }
        }

        ctx.putImageData(imgData, 0, 0);
    }

    this.ColorFilter = function(ctx, colorFilter) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);

        for (var i = 0; i < imgData.data.length; i += 4) {
            var r, g, b;
            switch (colorFilter) {
                case this.ColorFilters.RED:
                    r = imgData.data[i];
                    g = imgData.data[i + 1] - 255;
                    b = imgData.data[i + 2] - 255;
                    break;
                case this.ColorFilters.GREEN:
                    r = imgData.data[i] - 255;
                    g = imgData.data[i + 1];
                    b = imgData.data[i + 2] - 255;
                    break;
                case this.ColorFilters.GREEN:
                    r = imgData.data[i] - 255;
                    g = imgData.data[i + 1] - 255;
                    b = imgData.data[i + 2];
                    break;
                default:
                    r = imgData.data[i];
                    g = imgData.data[i + 1];
                    b = imgData.data[i + 2];
                    break;
            }

            imgData.data[i] = Math.min(255, Math.max(0, r));
            imgData.data[i + 1] = Math.min(255, Math.max(0, g));
            imgData.data[i + 2] = Math.min(255, Math.max(0, b));
        }

        ctx.putImageData(imgData, 0, 0);
    }

    this.Invert = function(ctx) {
        _invertColorFilter(ctx, this.ColorFilters.NONE);
    }

    this.InvertedColorFilter = function(ctx, colorFilter) {
        _invertColorFilter(ctx, colorFilter);
    }

    this.Greyscale = function(ctx) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);

        for (var i = 0; i < imgData.data.length; i += 4) {
            var grey = 0.299 * imgData.data[i] + 0.587 * imgData.data[i + 1] + 0.114 * imgData.data[i + 2];
            imgData.data[i] = imgData.data[i + 1] = imgData.data[i + 2] = grey;
        }

        ctx.putImageData(imgData, 0, 0);
    }

    function _invertColorFilter(ctx, colorFilter) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);

        for (var i = 0; i < imgData.data.length; i += 4) {
            var r, g, b;
            switch (colorFilter) {
                case Fuzzy.ColorFilters.RED:
                    r = imgData.data[i];
                    g = 255 - imgData.data[i + 1];
                    b = 255 - imgData.data[i + 2];
                    break;
                case Fuzzy.ColorFilters.GREEN:
                    r = 255 - imgData.data[i];
                    g = imgData.data[i + 1];
                    b = 255 - imgData.data[i + 2];
                    break;
                case Fuzzy.ColorFilters.GREEN:
                    r = 255 - imgData.data[i];
                    g = 255 - imgData.data[i + 1];
                    b = imgData.data[i + 2];
                    break;
                default:
                    r = 255 - imgData.data[i];
                    g = 255 - imgData.data[i + 1];
                    b = 255 - imgData.data[i + 2];
                    break;
            }

            imgData.data[i] = Math.min(255, Math.max(0, r));
            imgData.data[i + 1] = Math.min(255, Math.max(0, g));
            imgData.data[i + 2] = Math.min(255, Math.max(0, b));
        }

        ctx.putImageData(imgData, 0, 0);
    }

    function _getPixel(imgData, x, y) {
        index = (x + y * imgData.width) * 4;
        return {
            r : imgData.data[index + 0],
            g : imgData.data[index + 1],
            b : imgData.data[index + 2],
            a : imgData.data[index + 3]
        };
    }

    function _setPixel(imgData, x, y, pixel) {
        index = (x + y * imgData.width) * 4;
        imgData.data[index + 0] = pixel.r;
        imgData.data[index + 1] = pixel.g;
        imgData.data[index + 2] = pixel.b;
        imgData.data[index + 3] = pixel.a;
    }

    function _reset() {
        ctx.mozImageSmoothingEnabled = true;
        ctx.webkitImageSmoothingEnabled = true;
        ctx.imageSmoothingEnabled = true;
    }

}).call(Fuzzy); <commit_msg>Fixing typo in invertedColorFilter<commit_after>if ( typeof Fuzzy == 'undefined') {
    Fuzzy = {};
}

(function() {
    this.ColorFilters = {
        RED: "red",
        GREEN: "green",
        BLUE: "blue",
        NONE: "none"
    }

    this.Pixelate = function(ctx, pixelsize) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);
        pixelsize = pixelsize <= 0 ? 1 : pixelsize;

        for(var i = 0; i < width; i += pixelsize) {
            for(var j = 0; j < width; j += pixelsize) {
                var offsetx = (pixelsize / 2) | 0;
                var offsety = (pixelsize / 2) | 0;

		        while(i + offsetx >= width) {
		            offsetx--;
		        }

		        while(j + offsety >= height) {
		            offsety--;
		        }

		        var pixel = _getPixel(imgData, i + offsetx, j + offsety);

		        for(var x = i; x < i + pixelsize && x < width; x++) {
		            for(var y = j; y < j + pixelsize && y < height; y++){
		                _setPixel(imgData, x, y, pixel) {
                    }
                }
            }
        }

        ctx.putImageData(imgData, 0, 0);
    }

    this.ColorFilter = function(ctx, colorFilter) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);

        for (var i = 0; i < imgData.data.length; i += 4) {
            var r, g, b;
            switch (colorFilter) {
                case this.ColorFilters.RED:
                    r = imgData.data[i];
                    g = imgData.data[i + 1] - 255;
                    b = imgData.data[i + 2] - 255;
                    break;
                case this.ColorFilters.GREEN:
                    r = imgData.data[i] - 255;
                    g = imgData.data[i + 1];
                    b = imgData.data[i + 2] - 255;
                    break;
                case this.ColorFilters.GREEN:
                    r = imgData.data[i] - 255;
                    g = imgData.data[i + 1] - 255;
                    b = imgData.data[i + 2];
                    break;
                default:
                    r = imgData.data[i];
                    g = imgData.data[i + 1];
                    b = imgData.data[i + 2];
                    break;
            }

            imgData.data[i] = Math.min(255, Math.max(0, r));
            imgData.data[i + 1] = Math.min(255, Math.max(0, g));
            imgData.data[i + 2] = Math.min(255, Math.max(0, b));
        }

        ctx.putImageData(imgData, 0, 0);
    }

    this.Invert = function(ctx) {
        _invertColorFilter(ctx, this.ColorFilters.NONE);
    }

    this.InvertedColorFilter = function(ctx, colorFilter) {
        _invertColorFilter(ctx, colorFilter);
    }

    this.Greyscale = function(ctx) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);

        for (var i = 0; i < imgData.data.length; i += 4) {
            var grey = 0.299 * imgData.data[i] + 0.587 * imgData.data[i + 1] + 0.114 * imgData.data[i + 2];
            imgData.data[i] = imgData.data[i + 1] = imgData.data[i + 2] = grey;
        }

        ctx.putImageData(imgData, 0, 0);
    }

    function _invertColorFilter(ctx, colorFilter) {
        var width = ctx.canvas.width;
        var height = ctx.canvas.height;
        var imgData = ctx.getImageData(0, 0, width, height);

        for (var i = 0; i < imgData.data.length; i += 4) {
            var r, g, b;
            switch (colorFilter) {
                case Fuzzy.ColorFilters.RED:
                    r = imgData.data[i];
                    g = 255 - imgData.data[i + 1];
                    b = 255 - imgData.data[i + 2];
                    break;
                case Fuzzy.ColorFilters.GREEN:
                    r = 255 - imgData.data[i];
                    g = imgData.data[i + 1];
                    b = 255 - imgData.data[i + 2];
                    break;
                case Fuzzy.ColorFilters.BLUE:
                    r = 255 - imgData.data[i];
                    g = 255 - imgData.data[i + 1];
                    b = imgData.data[i + 2];
                    break;
                default:
                    r = 255 - imgData.data[i];
                    g = 255 - imgData.data[i + 1];
                    b = 255 - imgData.data[i + 2];
                    break;
            }

            imgData.data[i] = Math.min(255, Math.max(0, r));
            imgData.data[i + 1] = Math.min(255, Math.max(0, g));
            imgData.data[i + 2] = Math.min(255, Math.max(0, b));
        }

        ctx.putImageData(imgData, 0, 0);
    }

    function _getPixel(imgData, x, y) {
        index = (x + y * imgData.width) * 4;
        return {
            r : imgData.data[index + 0],
            g : imgData.data[index + 1],
            b : imgData.data[index + 2],
            a : imgData.data[index + 3]
        };
    }

    function _setPixel(imgData, x, y, pixel) {
        index = (x + y * imgData.width) * 4;
        imgData.data[index + 0] = pixel.r;
        imgData.data[index + 1] = pixel.g;
        imgData.data[index + 2] = pixel.b;
        imgData.data[index + 3] = pixel.a;
    }

    function _reset() {
        ctx.mozImageSmoothingEnabled = true;
        ctx.webkitImageSmoothingEnabled = true;
        ctx.imageSmoothingEnabled = true;
    }

}).call(Fuzzy); <|endoftext|>


<commit_before>'use strict';

angular.module('arachne.controllers')

/**
 * @author: Daniel M. de Oliveira
 * @author: Sebastian Cuy
 */
.controller('ProjectsController', ['$scope', '$http',
    function ($scope, $http ) {

        $scope.columns = [];
        $http.get('con10t/projects.json').success(function(data){

            $scope.projects = data[0].children;

            // TODO adjust title according to language
            // for now, set it to german language

            for (var i=0;i<$scope.projects.length;i++){ // 1st order elements
                $scope.projects[i].title=$scope.projects[i].title['de'];

                if (! $scope.projects[i].children) continue;

                for (var j=0;j<$scope.projects[i].children.length;j++){ // 2nd order elements

                    $scope.projects[i].children[j].title=$scope.projects[i].children[j].title['de'];
                    if (! $scope.projects[i].children[j].children) continue;

                    for (var k = 0; k < $scope.projects[i].children[j].children.length; k++) { // 3nd order elements
                        $scope.projects[i].children[j].children[k].title = $scope.projects[i].children[j].children[k].title['de'];
                    }

                }

            }

            $scope.columns[0] = $scope.projects.slice(0,3);
            $scope.columns[1] = $scope.projects.slice(3,5);
            $scope.columns[2] = $scope.projects.slice(5);
        });
    }
]);<commit_msg>Improve code structure in preparation for implementation of localization for projects page.<commit_after>'use strict';

angular.module('arachne.controllers')

/**
 * TODO adjust title according to language
 *   for now, set it to german language
 *
 * @author: Daniel M. de Oliveira
 * @author: Sebastian Cuy
 */
.controller('ProjectsController', ['$scope', '$http',
    function ($scope, $http ) {

        var restructureByLang = function(el,lang){
            el.title=el.title[lang];
            el.selectedLang=lang;
        }

        var restructureRecursively = function(el){

            restructureByLang(el,'de');

            if (! el.children) return;
            for (var i=0;i<el.children.length;i++) {
                restructureRecursively(el.children[i]);
            }
        }

        $scope.columns = [];
        var sliceColumns = function(){
            $scope.columns[0] = $scope.projects.slice(0,3);
            $scope.columns[1] = $scope.projects.slice(3,5);
            $scope.columns[2] = $scope.projects.slice(5);
        }

        $http.get('con10t/projects.json').success(function(data){
            $scope.projects = data[0].children;

            for (var i=0;i<$scope.projects.length;i++)
                restructureRecursively($scope.projects[i]);

            sliceColumns();
        });
    }
]);<|endoftext|>


<commit_before>/**
 * Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
 * Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
var yslow = require('./yslow'),
  gpsi = require('./gpsi'),
  browsertime = require('./browsertime'),
  webpagetest = require('./webpagetest'),
  screenshots = require('./screenshots'),
  phantomjs = require('./phantom'),
  async = require('async');

function Analyzer() {}

Analyzer.prototype.analyze = function(urls, collector, config, downloadErrors, analysisErrors, urlAnalysedCallback,
  completionCallback) {

  /**
  To keep it simple, we run each task in a serie so
  that they will not interfer with each other
  */

  var tasks = [

    function(cb) {
      if (config.runYslow) {
        yslow.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.phantomjs) {
        phantomjs.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.gpsiKey) {
        gpsi.analyze(urls, config,  cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.browsertime) {
        browsertime.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.wptUrl) {
        webpagetest.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.screenshot) {
        screenshots.takeScreenshots(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    }
  ];

  async.series(tasks, function(errors, results) {
    // Lets go through all the urls and create
    // pageData and collect it
    urls.forEach(function(url) {
      var err = '';
      var pageData = {};
      results.forEach(function(result) {
        // if the result is empty, take the next one
        if (!result.type) {
          return;
        } else {
          Object.keys(result.data).forEach(function(dataUrl) {

            // for the mathing URL, take the data and populate the pageData objekt
            if (dataUrl === url) {
              // all browser time data is in an array, because
              // we will run browsertime for eahc
              if (result.type === 'browsertime') {
                result.data[url].forEach(function(runPerBrowser) {
                  if (pageData.browsertime) {
                    pageData.browsertime.push(runPerBrowser.browsertime);
                  } else {
                    pageData.browsertime = [runPerBrowser.browsertime];
                  }
                  if (pageData.har) {
                    pageData.har.push(runPerBrowser.har);
                  } else {
                    pageData.har = [runPerBrowser.har];
                  }
                });
              }
              // WPT holds both the WPT and HAR info
              else if (result.type === 'webpagetest') {
                pageData[result.type] = result.data[url].wpt;
                if (pageData.har) {
                  pageData.har.push(result.data[dataUrl].har);
                } else {
                  pageData.har = [result.data[dataUrl].har];
                }
                // take care of all the other cases
              } else {
                pageData[result.type] = result.data[url];
              }
            }
          });
        }

        Object.keys(result.errors).forEach(function(errorUrl) {
          if (errorUrl === url) {
            err += result.type + ' ' + result.errors[url];
          }
        });

      });

      collector.collectPageData(pageData);
      urlAnalysedCallback(err, url, pageData);
    });

    completionCallback(null, downloadErrors, analysisErrors);
  });
};

module.exports = Analyzer;
<commit_msg>syntax<commit_after>/**
 * Sitespeed.io - How speedy is your site? (http://www.sitespeed.io)
 * Copyright (c) 2014, Peter Hedenskog, Tobias Lidskog
 * and other contributors
 * Released under the Apache 2.0 License
 */
var yslow = require('./yslow'),
  gpsi = require('./gpsi'),
  browsertime = require('./browsertime'),
  webpagetest = require('./webpagetest'),
  screenshots = require('./screenshots'),
  phantomjs = require('./phantom'),
  async = require('async');

function Analyzer() {}

Analyzer.prototype.analyze = function(urls, collector, config, downloadErrors, analysisErrors, urlAnalysedCallback,
  completionCallback) {

  /**
  To keep it simple, we run each task in a serie so
  that they will not interfer with each other
  */

  var tasks = [

    function(cb) {
      if (config.runYslow) {
        yslow.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.phantomjs) {
        phantomjs.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.gpsiKey) {
        gpsi.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.browsertime) {
        browsertime.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.wptUrl) {
        webpagetest.analyze(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    },
    function(cb) {
      if (config.screenshot) {
        screenshots.takeScreenshots(urls, config, cb);
      } else {
        cb(undefined, {});
      }
    }
  ];

  async.series(tasks, function(errors, results) {
    // Lets go through all the urls and create
    // pageData and collect it
    urls.forEach(function(url) {
      var err = '';
      var pageData = {};
      results.forEach(function(result) {
        // if the result is empty, take the next one
        if (!result.type) {
          return;
        } else {
          Object.keys(result.data).forEach(function(dataUrl) {

            // for the mathing URL, take the data and populate the pageData objekt
            if (dataUrl === url) {
              // all browser time data is in an array, because
              // we will run browsertime for eahc
              if (result.type === 'browsertime') {
                result.data[url].forEach(function(runPerBrowser) {
                  if (pageData.browsertime) {
                    pageData.browsertime.push(runPerBrowser.browsertime);
                  } else {
                    pageData.browsertime = [runPerBrowser.browsertime];
                  }
                  if (pageData.har) {
                    pageData.har.push(runPerBrowser.har);
                  } else {
                    pageData.har = [runPerBrowser.har];
                  }
                });
              }
              // WPT holds both the WPT and HAR info
              else if (result.type === 'webpagetest') {
                pageData[result.type] = result.data[url].wpt;
                if (pageData.har) {
                  pageData.har.push(result.data[dataUrl].har);
                } else {
                  pageData.har = [result.data[dataUrl].har];
                }
                // take care of all the other cases
              } else {
                pageData[result.type] = result.data[url];
              }
            }
          });
        }

        Object.keys(result.errors).forEach(function(errorUrl) {
          if (errorUrl === url) {
            err += result.type + ' ' + result.errors[url];
          }
        });

      });

      collector.collectPageData(pageData);
      urlAnalysedCallback(err, url, pageData);
    });

    completionCallback(null, downloadErrors, analysisErrors);
  });
};

module.exports = Analyzer;<|endoftext|>