<commit_before>// Copyright 2019, University of Colorado Boulder

/**
 * The popup list box for a ComboBox.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const ComboBoxListItemNode = require( 'SUN/ComboBoxListItemNode' );
  const Emitter = require( 'AXON/Emitter' );
  const EmitterIO = require( 'AXON/EmitterIO' );
  const Event = require( 'SCENERY/input/Event' );
  const KeyboardUtil = require( 'SCENERY/accessibility/KeyboardUtil' );
  const Panel = require( 'SUN/Panel' );
  const sun = require( 'SUN/sun' );
  const Tandem = require( 'TANDEM/Tandem' );
  const VBox = require( 'SCENERY/nodes/VBox' );
  const VoidIO = require( 'TANDEM/types/VoidIO' );

  class ComboBoxListBox extends Panel {

    /**
     * @param {Property} property
     * @param {ComboBoxItem[]} items
     * @param {function} hideListBoxCallback - called to hide the list box
     * @param {function} focusButtonCallback - called to transfer focus to the combo box's button
     * @param {Tandem} tandem
     * @param {Object} [options]
     */
    constructor( property, items, hideListBoxCallback, focusButtonCallback, tandem, options ) {

      options = _.extend( {

        // {Color|string} fill for the highlight behind items in the list
        highlightFill: 'rgb( 245, 245, 245 )',

        // Panel options
        xMargin: 12,
        yMargin: 8,

        // a11y
        tagName: 'ul',
        ariaRole: 'listbox',
        groupFocusHighlight: true,
        focusable: true

        // Not instrumented for PhET-iO because the list's location isn't valid until it has been popped up.
        // See https://github.com/phetsims/phet-io/issues/1102

      }, options );

      assert && assert( options.xMargin > 0 && options.yMargin > 0,
        'margins must be > 0, xMargin=' + options.xMargin + ', yMargin=' + options.yMargin );

      //TODO sun#462 replace fireEmitter and selectionListener with a standard scenery listener
      const firedEmitter = new Emitter( {
        argumentTypes: [ { validValue: Event } ],

        // Pops down the list box and sets the property.value to match the chosen item.
        listener: event => {

          const listItemNode = event.currentTarget;
          assert && assert( listItemNode instanceof ComboBoxListItemNode, 'expected a ComboBoxListItemNode' );

          // hide the list
          hideListBoxCallback();

          // prevent nodes (eg, controls) behind the list from receiving the event
          event.abort();

          // set value based on which item was chosen in the list box
          property.value = listItemNode.item.value;
        },

        // phet-io
        tandem: tandem.createTandem( 'firedEmitter' ),

        //TODO https://github.com/phetsims/phet-io/issues/1426, use type:EventIO, phetioDataStream:false
        phetioType: EmitterIO( [ { name: 'event', type: VoidIO } ] ),
        phetioEventType: 'user'
      } );

      //TODO sun#462 replace fireEmitter and selectionListener with a standard scenery listener
      // Handles selection from the list box.
      const selectionListener = {

        down( event ) {
          event.abort(); // prevent click-to-dismiss on the list
        },

        up( event ) {
          firedEmitter.emit( event );
        },

        // Handle keyup on each item in the list box, for a11y.
        //TODO sun#447, scenery#931 we're using keyup because keydown fires continuously
        keyup: event => {
          if ( KeyboardUtil.KEY_ENTER === event.domEvent.keyCode || KeyboardUtil.KEY_SPACE === event.domEvent.keyCode ) {
            firedEmitter.emit( event );
            focusButtonCallback();
          }
        }
      };

      // Compute max item dimensions
      const maxItemWidth = _.maxBy( items, item => item.node.width ).node.width;
      const maxItemHeight = _.maxBy( items, item => item.node.height ).node.height;

      // Uniform dimensions for all highlighted items in the list, highlight overlaps margin by 50%
      const highlightWidth = maxItemWidth + options.xMargin;
      const highlightHeight = maxItemHeight + options.yMargin;

      // Create a node for each item in the list, and attach a listener.
      const listItemNodes = []; // {ComboBoxListItemNode[]}
      items.forEach( ( item, index ) => {

        // Create the list item node
        const listItemNode = new ComboBoxListItemNode( item, highlightWidth, highlightHeight, {
          align: options.align,
          highlightFill: options.highlightFill,
          highlightCornerRadius: options.cornerRadius,

          // highlight overlaps half of margins
          xMargin: 0.5 * options.xMargin,
          left: 0.5 * options.xMargin,
          top: ( 0.5 * options.yMargin ) + ( index * highlightHeight ),
          tandem: item.tandemName ? tandem.createTandem( item.tandemName ) : Tandem.optional
        } );
        listItemNodes.push( listItemNode );

        listItemNode.addInputListener( selectionListener );
      } );

      const content = new VBox( {
        spacing: 0,
        children: listItemNodes
      } );

      // Adjust margins to account for highlight overlap
      options.xMargin = options.xMargin / 2;
      options.yMargin = options.yMargin / 2;

      super( content, options );

      // @public {ComboBoxListItemNode|null} the ComboBoxListItemNode that has focus
      this.focusedItemNode = null;

      // Handle keydown on the entire list box, for a11y
      this.addInputListener( {

        // When we get focus, transfer focus to the ComboBoxListItemNode that matches property.value.
        focus: event => {
          if ( this.visible ) {
            for ( let i = 0; i < this.listItemNodes.length; i++ ) {
              const listItemNode = this.listItemNodes[ i ];
              if ( this.property.value === listItemNode.item.value ) {
                this.focusedItemNode = listItemNode;
                this.focusedItemNode.focus();
                break;
              }
            }
          }
        },

        keydown: event => {
          var keyCode = event.domEvent.keyCode;
          if ( keyCode === KeyboardUtil.KEY_ESCAPE || keyCode === KeyboardUtil.KEY_TAB ) {
            hideListBoxCallback();
            focusButtonCallback();
          }
          else if ( keyCode === KeyboardUtil.KEY_DOWN_ARROW || keyCode === KeyboardUtil.KEY_UP_ARROW ) {

            // Up/down arrow keys move the focus between items in the list box
            const direction = ( keyCode === KeyboardUtil.KEY_DOWN_ARROW ) ? 1 : -1;
            for ( let i = 0; i < listItemNodes.length; i++ ) {
              if ( this.focusedItemNode === listItemNodes[ i ] ) {
                const nextListItemNode = listItemNodes[ i + direction ];
                if ( nextListItemNode ) {

                  // set focus for next item
                  this.focusedItemNode = nextListItemNode;
                  this.focusedItemNode.focus();
                  break;
                }
              }
            }
          }
        }
      } );

      // @private
      this.disposeComboBoxListBox = () => {
        for ( let i = 0; i < listItemNodes; i++ ) {
          listItemNodes[ i ].dispose(); // to unregister tandem
        }
      };

      // @private needed by methods
      this.property = property;
      this.listItemNodes = listItemNodes;
    }

    /**
     * @public
     * @override
     */
    dispose() {
      this.disposeComboBoxListBox();
      super.dispose();
    }
  }

  return sun.register( 'ComboBoxListBox', ComboBoxListBox );
} );<commit_msg>doc<commit_after>// Copyright 2019, University of Colorado Boulder

/**
 * The popup list box for a ComboBox.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const ComboBoxListItemNode = require( 'SUN/ComboBoxListItemNode' );
  const Emitter = require( 'AXON/Emitter' );
  const EmitterIO = require( 'AXON/EmitterIO' );
  const Event = require( 'SCENERY/input/Event' );
  const KeyboardUtil = require( 'SCENERY/accessibility/KeyboardUtil' );
  const Panel = require( 'SUN/Panel' );
  const sun = require( 'SUN/sun' );
  const Tandem = require( 'TANDEM/Tandem' );
  const VBox = require( 'SCENERY/nodes/VBox' );
  const VoidIO = require( 'TANDEM/types/VoidIO' );

  class ComboBoxListBox extends Panel {

    /**
     * @param {Property} property
     * @param {ComboBoxItem[]} items
     * @param {function} hideListBoxCallback - called to hide the list box
     * @param {function} focusButtonCallback - called to transfer focus to the combo box's button
     * @param {Tandem} tandem
     * @param {Object} [options]
     */
    constructor( property, items, hideListBoxCallback, focusButtonCallback, tandem, options ) {

      options = _.extend( {

        // {Color|string} fill for the highlight behind items in the list
        highlightFill: 'rgb( 245, 245, 245 )',

        // Panel options
        xMargin: 12,
        yMargin: 8,

        // a11y
        tagName: 'ul',
        ariaRole: 'listbox',
        groupFocusHighlight: true,
        focusable: true

        // Not instrumented for PhET-iO because the list's location isn't valid until it has been popped up.
        // See https://github.com/phetsims/phet-io/issues/1102

      }, options );

      assert && assert( options.xMargin > 0 && options.yMargin > 0,
        'margins must be > 0, xMargin=' + options.xMargin + ', yMargin=' + options.yMargin );

      //TODO sun#462 replace fireEmitter and selectionListener with a standard scenery listener
      const firedEmitter = new Emitter( {
        argumentTypes: [ { validValue: Event } ],

        // Pops down the list box and sets the property.value to match the chosen item.
        listener: event => {

          const listItemNode = event.currentTarget;
          assert && assert( listItemNode instanceof ComboBoxListItemNode, 'expected a ComboBoxListItemNode' );

          // hide the list
          hideListBoxCallback();

          // prevent nodes (eg, controls) behind the list from receiving the event
          event.abort();

          // set value based on which item was chosen in the list box
          property.value = listItemNode.item.value;
        },

        // phet-io
        tandem: tandem.createTandem( 'firedEmitter' ),

        //TODO https://github.com/phetsims/phet-io/issues/1426, use type:EventIO, phetioDataStream:false
        phetioType: EmitterIO( [ { name: 'event', type: VoidIO } ] ),
        phetioEventType: 'user'
      } );

      //TODO sun#462 replace fireEmitter and selectionListener with a standard scenery listener
      // Handles selection from the list box.
      const selectionListener = {

        down( event ) {
          event.abort(); // prevent click-to-dismiss on the list
        },

        up( event ) {
          firedEmitter.emit( event );
        },

        // Handle keyup on each item in the list box, for a11y.
        //TODO sun#447, scenery#931 we're using keyup because keydown fires continuously
        keyup: event => {
          if ( KeyboardUtil.KEY_ENTER === event.domEvent.keyCode || KeyboardUtil.KEY_SPACE === event.domEvent.keyCode ) {
            firedEmitter.emit( event );
            focusButtonCallback();
          }
        }
      };

      // Compute max item dimensions
      const maxItemWidth = _.maxBy( items, item => item.node.width ).node.width;
      const maxItemHeight = _.maxBy( items, item => item.node.height ).node.height;

      // Uniform dimensions for all highlighted items in the list, highlight overlaps margin by 50%
      const highlightWidth = maxItemWidth + options.xMargin;
      const highlightHeight = maxItemHeight + options.yMargin;

      // Create a node for each item in the list, and attach a listener.
      const listItemNodes = []; // {ComboBoxListItemNode[]}
      items.forEach( ( item, index ) => {

        // Create the list item node
        const listItemNode = new ComboBoxListItemNode( item, highlightWidth, highlightHeight, {
          align: options.align,
          highlightFill: options.highlightFill,
          highlightCornerRadius: options.cornerRadius,

          // highlight overlaps half of margins
          xMargin: 0.5 * options.xMargin,
          left: 0.5 * options.xMargin,
          top: ( 0.5 * options.yMargin ) + ( index * highlightHeight ),
          tandem: item.tandemName ? tandem.createTandem( item.tandemName ) : Tandem.optional
        } );
        listItemNodes.push( listItemNode );

        listItemNode.addInputListener( selectionListener );
      } );

      const content = new VBox( {
        spacing: 0,
        children: listItemNodes
      } );

      // Adjust margins to account for highlight overlap
      options.xMargin = options.xMargin / 2;
      options.yMargin = options.yMargin / 2;

      super( content, options );

      // @public {ComboBoxListItemNode|null} the ComboBoxListItemNode that has focus
      this.focusedItemNode = null;

      // a11y listener for the entire list box
      this.addInputListener( {

        // When the list box gets focus, transfer focus to the ComboBoxListItemNode that matches property.value.
        focus: event => {
          if ( this.visible ) {
            for ( let i = 0; i < this.listItemNodes.length; i++ ) {
              const listItemNode = this.listItemNodes[ i ];
              if ( this.property.value === listItemNode.item.value ) {
                this.focusedItemNode = listItemNode;
                this.focusedItemNode.focus();
                break;
              }
            }
          }
        },

        // Handle keydown
        keydown: event => {
          var keyCode = event.domEvent.keyCode;
          if ( keyCode === KeyboardUtil.KEY_ESCAPE || keyCode === KeyboardUtil.KEY_TAB ) {

            // Escape and Tab hide the list box and return focus to the button
            hideListBoxCallback();
            focusButtonCallback();
          }
          else if ( keyCode === KeyboardUtil.KEY_DOWN_ARROW || keyCode === KeyboardUtil.KEY_UP_ARROW ) {

            // Up/down arrow keys move the focus between items in the list box
            const direction = ( keyCode === KeyboardUtil.KEY_DOWN_ARROW ) ? 1 : -1;
            for ( let i = 0; i < listItemNodes.length; i++ ) {
              if ( this.focusedItemNode === listItemNodes[ i ] ) {
                const nextListItemNode = listItemNodes[ i + direction ];
                if ( nextListItemNode ) {

                  // set focus for next item
                  this.focusedItemNode = nextListItemNode;
                  this.focusedItemNode.focus();
                  break;
                }
              }
            }
          }
        }
      } );

      // @private
      this.disposeComboBoxListBox = () => {
        for ( let i = 0; i < listItemNodes; i++ ) {
          listItemNodes[ i ].dispose(); // to unregister tandem
        }
      };

      // @private needed by methods
      this.property = property;
      this.listItemNodes = listItemNodes;
    }

    /**
     * @public
     * @override
     */
    dispose() {
      this.disposeComboBoxListBox();
      super.dispose();
    }
  }

  return sun.register( 'ComboBoxListBox', ComboBoxListBox );
} );<|endoftext|>


<commit_before>/**
 * A toolbar button that calls up a whole world of media.
 */
UI.Media_Button = function MediaButton() {
	var self = this;

	Util.OOP.inherits(this, UI.Button);

	this.image = 'media.png';
	this.title = 'Insert Media';

	var helper = null;

	this.init = function(loki) {
		this.superclass.init.call(this, loki);
		helper = new UI.Media_Helper(this._loki);
		return this;
	};

	this.click_listener = function open_media_dialog() {
		helper.open_dialog();
	};
};
<commit_msg>Have the media toolbar button look for selected media before opening the dialog.<commit_after>/**
 * A toolbar button that calls up a whole world of media.
 */
UI.Media_Button = function MediaButton() {
	var self = this;

	Util.OOP.inherits(this, UI.Button);

	this.image = 'media.png';
	this.title = 'Insert Media';

	var helper = null;

	this.init = function(loki) {
		this.superclass.init.call(this, loki);
		helper = new UI.Media_Helper(this._loki);
		return this;
	};

	this.click_listener = function open_media_dialog() {
		helper.open_dialog(helper.get_selected());
	};
};
<|endoftext|>


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

const React = require('react')
const BrowserButton = require('../../app/renderer/components/common/browserButton')

const appActions = require('../../js/actions/appActions')
const tabActions = require('../../app/common/actions/tabActions')

require('../../less/button.less')
require('../../less/window.less')
require('../../less/about/error.less')

class ErrorPage extends React.Component {
  constructor (props) {
    super(props)
    this.state = {}
  }

  goBack () {
    appActions.onGoBack()
  }

  reload () {
    tabActions.reload(null, true)
  }

  get showBackButton () {
    return this.state.previousLocation && this.state.previousLocation !== this.state.url
  }

  render () {
    return

        {this.state.url}

        {this.showBackButton ? <BrowserButton actionItem l10nId='back' onClick={this.goBack} /> : null}
        {this.state.url ? <BrowserButton actionItem l10nId='errorReload' l10nArgs={{url: this.state.url}} onClick={this.reload} /> : null}

  }
}

module.exports = <ErrorPage />
<commit_msg>add proper margin around buttons in about:error page Fix #9916<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const BrowserButton = require('../../app/renderer/components/common/browserButton')

const appActions = require('../../js/actions/appActions')
const tabActions = require('../../app/common/actions/tabActions')

require('../../less/button.less')
require('../../less/window.less')
require('../../less/about/error.less')

class ErrorPage extends React.Component {
  constructor (props) {
    super(props)
    this.state = {}
  }

  goBack () {
    appActions.onGoBack()
  }

  reload () {
    tabActions.reload(null, true)
  }

  get showBackButton () {
    return this.state.previousLocation && this.state.previousLocation !== this.state.url
  }

  render () {
    return

        {this.state.url}

        {this.showBackButton ? <BrowserButton actionItem l10nId='back' onClick={this.goBack} /> : null}
        {this.state.url ? <BrowserButton actionItem groupedItem l10nId='errorReload' l10nArgs={{url: this.state.url}} onClick={this.reload} /> : null}

  }
}

module.exports = <ErrorPage />
<|endoftext|>


<commit_before>var Views = {
    station: null,
    stationLogo: null,
    stationLogoWrapper: null,
    channelBroadcastInfoWrapper: null,
    channelBroadcastInfo: null,
    loader: null,
    console: null,
    version_info: null,
    progressBar: null,
    player: null,
    showPlayerWrapper: null,
    showInfo: null,
    showLogo: null,
    showTitle: null,
    showDescription: null,
    showingBroadcastInfo: false,
    state: 'playing',
    hd_on: false,
    qualityCanBeSwitched: false,
}

Views.init = function(_xhr){
    this.console = document.getElementById('Console');
    this.version_info = document.getElementById('version_info');

    if(@ENABLE_DEBUG_MODE@){
        this.console.style.display = 'block';
        this.version_info.style.display = 'block';
    }

    this.loader = Loader;
    this.stationLogo = document.getElementById('stationLogo');
    this.stationLogoWrapper = document.getElementById('stationLogoWrapper');
    this.channelBroadcastInfo = document.getElementById('channelBroadcastInfo');
    this.channelBroadcastInfoWrapper = document.getElementById('channelBroadcastInfoWrapper');
    this.controlBar = document.getElementById('controlBar');
    this.blueButtonLabel = document.getElementById('blueButtonLabel');
    this.greenButtonLabel = document.getElementById('greenButtonLabel');

    this.player = Player.init();

    this.showPlayerWrapper = document.getElementById('showPlayerWrapper');
    this.showInfo = document.getElementById('showInfo');
    this.showLogo = document.getElementById('showLogo');
    this.showTitle = document.getElementById('showTitle');
    this.showDescription = document.getElementById('showDescription');

    this.rewindButton = document.getElementById('rewindButton');
    this.playPauseButton = document.getElementById('playPauseButton');

    this.forwardButton = document.getElementById('forwardButton');

    this.state = document.getElementById('playerControls').className;
    return this;
};

Views.initWithStation = function(_station){
    this.station = _station;
    this.currentSelection = this.playPauseButton;
    this.selectButton(this.playPauseButton);
    if(_station.stationLogoDisplay){
        this.stationLogo.src = _station.stationLogoUrl;
        this.stationLogoWrapper.style.display = 'block';
    }
    this.player.setAndPlayStation(_station);

    if(_station.showLogoUrl != ""){
        this.showLogo.src = _station.showLogoUrl;
        this.showLogo.style.display = 'block';
    }
    else{
        this.showLogo.style.display = 'none';
    }

    this.channelBroadcastInfo.innerHTML = _station.channelBroadcastInfo;
    document.getElementById('channelLogo').src = _station.stationLogoUrl;
    document.getElementById('showInfoButtonWrapper').style.display = 'block';

    if(_station.showVideoHDUrl != ''){
        this.qualityCanBeSwitched = true;
        document.getElementById('hdsdButtonWrapper').style.display = 'block';
    }

    this.showTitle.innerHTML = _station.showTitle;
    this.showDescription.innerHTML = _station.showSubtitle;

    Util.preloadImages(['img/bg_mabb2.jpg'],[]); // preloading so we can see background image immediatelly
};

Views.showUI = function(){
    this.showPlayerWrapper.style.display = 'block';
    if(this.showingBroadcastInfo){
        if(this.station.stationLogoDisplay)
            this.stationLogoWrapper.style.display = 'none';
    }
};
Views.hideUI = function(){
    this.showPlayerWrapper.style.display = 'none';
    if(this.showingBroadcastInfo){
        if(this.station.stationLogoDisplay)
            this.stationLogoWrapper.style.display = 'block';
    }
};
Views.showBroadcastInfo = function(){
    this.showingBroadcastInfo = true;
    this.showInfo.style.display = 'none';
    this.stationLogoWrapper.style.display = 'none';
    this.channelBroadcastInfoWrapper.style.display = 'block';
    this.blueButtonLabel.innerHTML = "Infos zur Sendung";
};
Views.hideBroadcastInfo = function(){
    this.showingBroadcastInfo = false;
    this.showInfo.style.display = 'block';

    if(this.station.stationLogoDisplay)
        this.stationLogoWrapper.style.display = 'block';

    this.channelBroadcastInfoWrapper.style.display = 'none';
    this.blueButtonLabel.innerHTML = "Sendetermine";
};
Views.handleKey = function(_keyCode){
    switch(_keyCode){
        case VK_GREEN:
            this.toggleQuality()
            break;
        case VK_BLUE:
            if(this.showingBroadcastInfo)
                this.hideBroadcastInfo();
            else
               this.showBroadcastInfo();

            break;
        case VK_STOP:
              App.debug("VK_STOP");
              this.selectButton(this.playPauseButton);
              this.player.stop();
              this.setupStopped();
              break;
        case VK_PAUSE:
              App.debug("VK_PAUSE");
              this.player.pause();
              this.setupPaused();
              break;
        case VK_PLAY:
              App.debug("VK_PLAY");
              this.player.play();
              this.setupPlaying();
              break;
        case VK_FAST_FWD:
              App.debug("VK_FAST_FWD");
              this.player.seek_forward();
              break;
        case VK_REWIND:
              App.debug("VK_REWIND");
              this.player.seek_backward();
              break;
        case VK_PLAY_PAUSE:
              App.debug("VK_PLAY_PAUSE");
              this.player.play_pause();
              break;
        case VK_RIGHT:
            switch(this.currentSelection){
                case this.rewindButton:
                        this.selectButton(this.playPauseButton);
                    break;
                case this.playPauseButton:
                        this.selectButton(this.forwardButton);
                    break;
            }
            break;
        case VK_LEFT:
            switch(this.currentSelection){
                case this.playPauseButton:
                        this.selectButton(this.rewindButton);
                    break;
                case this.forwardButton:
                    this.selectButton(this.playPauseButton);
                    break;
            }
            break;
        case VK_ENTER:
            switch(this.currentSelection){
                case this.rewindButton:
                    this.player.seek_backward();
                    break;
                case this.playPauseButton:
                    switch(this.state){
                        case 'playing':
                            this.setupPaused();
                            this.player.pause();
                            break;
                        case 'stopped':
                        case 'paused':
                            this.setupPlaying();
                            this.player.play();
                            break;
                    }
                    break;
                case this.forwardButton:
                    this.player.seek_forward();
                    break;
            }
            break;
    }

};

Views.selectButton = function(_button){
    this.deselectButton(this.currentSelection);
    _button.className = "button selected";
    this.currentSelection = _button;
};
Views.deselectButton = function(_button){
    this.currentSelection = null;
    _button.className = "button";
};

Views.setupPlaying = function(){
    App.showUI(false);
    this.state = 'playing';
    this.selectButton(this.playPauseButton);
    document.getElementById('playerControls').className = "playing";
    document.getElementById('big_pause_button').className = "";

    // lets see if we are resuming the video
    if(this.showingBroadcastInfo){
        document.getElementById('app').className = "loading";
        App.videoIsLoading = true;
        this.hideBroadcastInfo();
    }
    else{
        document.getElementById('app').className = "";
    }

};
Views.setupPaused = function(){
    App.showUI(false);
    this.state = 'paused';
    this.selectButton(this.playPauseButton);
    document.getElementById('playerControls').className = "paused";
    document.getElementById('big_pause_button').className = "paused";
    document.getElementById('app').className = "";

};
Views.setupStopped = function(){
    App.showUI(false);
    App.hideLoader();
    this.state = 'stopped';
    this.selectButton(this.playPauseButton);
    document.getElementById('playerControls').className = "stopped";
    document.getElementById('big_pause_button').className = "";
    document.getElementById('app').className = "stopped";
    this.showBroadcastInfo();
    App.showUI(true);
};

Views.setupError = function(_isAPIError){
    this.state = 'failed';
    App.hideLoader();
    if(_isAPIError){
        App.views.showTitle.innerHTML = "Die Sendung konnte nicht geladen werden.";
        App.views.showDescription.innerHTML = "Bitte versuchen Sie es später noch einmal.";
        App.views.showLogo.style.display = 'none';
    }
    document.getElementById('app').className = "stopped";
    document.getElementById('playerControls').className = "failed";

    App.showUI(true);
};

Views.toggleQuality = function(){
    //var lastPosition = this.player.video.playPosition;
    var lastPosition = this.player.currentTime-2;
    App.debug('toggleQuality: '+lastPosition);
    if(!this.qualityCanBeSwitched)
        return;
    this.selectButton(this.playPauseButton);
    this.player.stop();
    App.videoIsLoading = true;
    if(this.hd_on){
        this.player.playVideoURL(this.station.showVideoSDUrl,lastPosition);
        this.hd_on = false;
        this.greenButtonLabel.className = "hd_off";
    }
    else{
        this.hd_on = true;
        this.greenButtonLabel.className = "hd_on";
        this.player.playVideoURL(this.station.showVideoSDUrl,lastPosition);
    }
    if(this.player.canSeekImmediatelly)
        this.player.seek_if_needed();
};

 <commit_msg>FIX: video playing in SD instead of HD<commit_after>var Views = {
    station: null,
    stationLogo: null,
    stationLogoWrapper: null,
    channelBroadcastInfoWrapper: null,
    channelBroadcastInfo: null,
    loader: null,
    console: null,
    version_info: null,
    progressBar: null,
    player: null,
    showPlayerWrapper: null,
    showInfo: null,
    showLogo: null,
    showTitle: null,
    showDescription: null,
    showingBroadcastInfo: false,
    state: 'playing',
    hd_on: false,
    qualityCanBeSwitched: false,
}

Views.init = function(_xhr){
    this.console = document.getElementById('Console');
    this.version_info = document.getElementById('version_info');

    if(@ENABLE_DEBUG_MODE@){
        this.console.style.display = 'block';
        this.version_info.style.display = 'block';
    }

    this.loader = Loader;
    this.stationLogo = document.getElementById('stationLogo');
    this.stationLogoWrapper = document.getElementById('stationLogoWrapper');
    this.channelBroadcastInfo = document.getElementById('channelBroadcastInfo');
    this.channelBroadcastInfoWrapper = document.getElementById('channelBroadcastInfoWrapper');
    this.controlBar = document.getElementById('controlBar');
    this.blueButtonLabel = document.getElementById('blueButtonLabel');
    this.greenButtonLabel = document.getElementById('greenButtonLabel');

    this.player = Player.init();

    this.showPlayerWrapper = document.getElementById('showPlayerWrapper');
    this.showInfo = document.getElementById('showInfo');
    this.showLogo = document.getElementById('showLogo');
    this.showTitle = document.getElementById('showTitle');
    this.showDescription = document.getElementById('showDescription');

    this.rewindButton = document.getElementById('rewindButton');
    this.playPauseButton = document.getElementById('playPauseButton');

    this.forwardButton = document.getElementById('forwardButton');

    this.state = document.getElementById('playerControls').className;
    return this;
};

Views.initWithStation = function(_station){
    this.station = _station;
    this.currentSelection = this.playPauseButton;
    this.selectButton(this.playPauseButton);
    if(_station.stationLogoDisplay){
        this.stationLogo.src = _station.stationLogoUrl;
        this.stationLogoWrapper.style.display = 'block';
    }
    this.player.setAndPlayStation(_station);

    if(_station.showLogoUrl != ""){
        this.showLogo.src = _station.showLogoUrl;
        this.showLogo.style.display = 'block';
    }
    else{
        this.showLogo.style.display = 'none';
    }

    this.channelBroadcastInfo.innerHTML = _station.channelBroadcastInfo;
    document.getElementById('channelLogo').src = _station.stationLogoUrl;
    document.getElementById('showInfoButtonWrapper').style.display = 'block';

    if(_station.showVideoHDUrl != ''){
        this.qualityCanBeSwitched = true;
        document.getElementById('hdsdButtonWrapper').style.display = 'block';
    }

    this.showTitle.innerHTML = _station.showTitle;
    this.showDescription.innerHTML = _station.showSubtitle;

    Util.preloadImages(['img/bg_mabb2.jpg'],[]); // preloading so we can see background image immediatelly
};

Views.showUI = function(){
    this.showPlayerWrapper.style.display = 'block';
    if(this.showingBroadcastInfo){
        if(this.station.stationLogoDisplay)
            this.stationLogoWrapper.style.display = 'none';
    }
};
Views.hideUI = function(){
    this.showPlayerWrapper.style.display = 'none';
    if(this.showingBroadcastInfo){
        if(this.station.stationLogoDisplay)
            this.stationLogoWrapper.style.display = 'block';
    }
};
Views.showBroadcastInfo = function(){
    this.showingBroadcastInfo = true;
    this.showInfo.style.display = 'none';
    this.stationLogoWrapper.style.display = 'none';
    this.channelBroadcastInfoWrapper.style.display = 'block';
    this.blueButtonLabel.innerHTML = "Infos zur Sendung";
};
Views.hideBroadcastInfo = function(){
    this.showingBroadcastInfo = false;
    this.showInfo.style.display = 'block';

    if(this.station.stationLogoDisplay)
        this.stationLogoWrapper.style.display = 'block';

    this.channelBroadcastInfoWrapper.style.display = 'none';
    this.blueButtonLabel.innerHTML = "Sendetermine";
};
Views.handleKey = function(_keyCode){
    switch(_keyCode){
        case VK_GREEN:
            this.toggleQuality()
            break;
        case VK_BLUE:
            if(this.showingBroadcastInfo)
                this.hideBroadcastInfo();
            else
               this.showBroadcastInfo();

            break;
        case VK_STOP:
              App.debug("VK_STOP");
              this.selectButton(this.playPauseButton);
              this.player.stop();
              this.setupStopped();
              break;
        case VK_PAUSE:
              App.debug("VK_PAUSE");
              this.player.pause();
              this.setupPaused();
              break;
        case VK_PLAY:
              App.debug("VK_PLAY");
              this.player.play();
              this.setupPlaying();
              break;
        case VK_FAST_FWD:
              App.debug("VK_FAST_FWD");
              this.player.seek_forward();
              break;
        case VK_REWIND:
              App.debug("VK_REWIND");
              this.player.seek_backward();
              break;
        case VK_PLAY_PAUSE:
              App.debug("VK_PLAY_PAUSE");
              this.player.play_pause();
              break;
        case VK_RIGHT:
            switch(this.currentSelection){
                case this.rewindButton:
                        this.selectButton(this.playPauseButton);
                    break;
                case this.playPauseButton:
                        this.selectButton(this.forwardButton);
                    break;
            }
            break;
        case VK_LEFT:
            switch(this.currentSelection){
                case this.playPauseButton:
                        this.selectButton(this.rewindButton);
                    break;
                case this.forwardButton:
                    this.selectButton(this.playPauseButton);
                    break;
            }
            break;
        case VK_ENTER:
            switch(this.currentSelection){
                case this.rewindButton:
                    this.player.seek_backward();
                    break;
                case this.playPauseButton:
                    switch(this.state){
                        case 'playing':
                            this.setupPaused();
                            this.player.pause();
                            break;
                        case 'stopped':
                        case 'paused':
                            this.setupPlaying();
                            this.player.play();
                            break;
                    }
                    break;
                case this.forwardButton:
                    this.player.seek_forward();
                    break;
            }
            break;
    }

};

Views.selectButton = function(_button){
    this.deselectButton(this.currentSelection);
    _button.className = "button selected";
    this.currentSelection = _button;
};
Views.deselectButton = function(_button){
    this.currentSelection = null;
    _button.className = "button";
};

Views.setupPlaying = function(){
    App.showUI(false);
    this.state = 'playing';
    this.selectButton(this.playPauseButton);
    document.getElementById('playerControls').className = "playing";
    document.getElementById('big_pause_button').className = "";

    // lets see if we are resuming the video
    if(this.showingBroadcastInfo){
        document.getElementById('app').className = "loading";
        App.videoIsLoading = true;
        this.hideBroadcastInfo();
    }
    else{
        document.getElementById('app').className = "";
    }

};
Views.setupPaused = function(){
    App.showUI(false);
    this.state = 'paused';
    this.selectButton(this.playPauseButton);
    document.getElementById('playerControls').className = "paused";
    document.getElementById('big_pause_button').className = "paused";
    document.getElementById('app').className = "";

};
Views.setupStopped = function(){
    App.showUI(false);
    App.hideLoader();
    this.state = 'stopped';
    this.selectButton(this.playPauseButton);
    document.getElementById('playerControls').className = "stopped";
    document.getElementById('big_pause_button').className = "";
    document.getElementById('app').className = "stopped";
    this.showBroadcastInfo();
    App.showUI(true);
};

Views.setupError = function(_isAPIError){
    this.state = 'failed';
    App.hideLoader();
    if(_isAPIError){
        App.views.showTitle.innerHTML = "Die Sendung konnte nicht geladen werden.";
        App.views.showDescription.innerHTML = "Bitte versuchen Sie es später noch einmal.";
        App.views.showLogo.style.display = 'none';
    }
    document.getElementById('app').className = "stopped";
    document.getElementById('playerControls').className = "failed";

    App.showUI(true);
};

Views.toggleQuality = function(){
    //var lastPosition = this.player.video.playPosition;
    var lastPosition = this.player.currentTime-2;
    App.debug('toggleQuality: '+lastPosition);
    if(!this.qualityCanBeSwitched)
        return;
    this.selectButton(this.playPauseButton);
    this.player.stop();
    App.videoIsLoading = true;
    if(this.hd_on){
        this.player.playVideoURL(this.station.showVideoSDUrl,lastPosition);
        this.hd_on = false;
        this.greenButtonLabel.className = "hd_off";
    }
    else{
        this.hd_on = true;
        this.greenButtonLabel.className = "hd_on";
        this.player.playVideoURL(this.station.showVideoHDUrl,lastPosition);
    }
    if(this.player.canSeekImmediatelly)
        this.player.seek_if_needed();
};

 <|endoftext|>


<commit_before>//= require "codemirror"
//= require "mobileCodeMirror"
//= require "library"
//= require "unsaved"
var focusPanel = 'javascript';
var editors = {};
var row = {};
var sql = new Array();

window.editors = editors;

editors.html = CodeMirror.fromTextArea(document.getElementById('html'), {
  parserfile: [],
  tabMode: 'shift',
  mode: 'text/html',
  onChange: changecontrol,
  theme: "eclipse",
  indentUnit: 4,
  lineNumbers: true
});

editors.javascript = CodeMirror.fromTextArea(document.getElementById('javascript'), {
  mode: 'css',
  tabMode: 'shift',
  onChange: changecontrol,
  theme: "eclipse",
  matchBrackets: true,
  indentUnit: 4,
  lineNumbers: true
});

setupEditor('javascript');
setupEditor('html');

var editorsReady = setInterval(function () {
  if (editors.html.ready && editors.javascript.ready) {

    editors.html.setCursor(7, 8);

    clearInterval(editorsReady);
    editors.ready = true;
    if (typeof editors.onReady == 'function') editors.onReady();

    var scrollers = {
      html: $(editors.html.getScrollerElement()),
      javascript: $(editors.javascript.getScrollerElement())
    };

    $document.bind('sizeeditors', function () {
      var top = 0, //$el.offset().top,
          height = $('#bin').height();
      scrollers.html.height(height - top);
      scrollers.javascript.height(height - top - $error.filter(':visible').height());
      editors.javascript.refresh();
      editors.html.refresh();
    });

    $(window).resize(function () {
      setTimeout(function () {
        $document.trigger('sizeeditors');
      }, 100);
    });

    $document.trigger('sizeeditors');
    $document.trigger('jsbinReady');
  }
}, 100);

// $('#javascript').replaceWith('

');
// $('#javascript').css({ height: '100%', width: '100%' });
// $('#html').replaceWith('

');
// $('#html').css({ height: '100%', width: '100%' });
//
// editors.javascript = ace.edit("javascript");
// editors.html = ace.edit("html");
//
// var JavaScriptMode = require("ace/mode/javascript").Mode,
//     HTMLMode = require("ace/mode/html").Mode;
//
// setupAce(editors, 'javascript');
// setupAce(editors, 'html');
//
// function setupAce(editor, type) {
//   var session = editors[type].getSession(),
//       renderer = editors[type].renderer;
//   if (type == 'javascript') {
//     session.setMode(new JavaScriptMode());
//   } else {
//     session.setMode(new HTMLMode());
//   }
//
//   editors[type].setHighlightActiveLine(false);
//   session.setUseWrapMode(true);
//   session.setUseSoftTabs(true);
//   session.setWrapLimitRange(null, null);
//
//   renderer.setShowPrintMargin(false);
//   renderer.setShowGutter(false);
//   renderer.setHScrollBarAlwaysVisible(false);
// }

function focused(editor, event) {
  focusPanel = editor.id;
  snapshot(focusPanel);
  console.log(focusPanel);
}

function getFocusedPanel() {
  return focusPanel;
}

function setupEditor(panel) {
  var e = editors[panel],
      focusedPanel = sessionStorage.getItem('panel');

  // overhang from CodeMirror1
  e.setCode = function (str) {
    e.setValue(str);
  };

  e.getCode = function () {
    return e.getValue();
  };

  e.currentLine = function () {
    var pos = e.getCursor();
    return pos.line;
  };

  e.setOption('onChange', changecontrol);
  e.setOption('onKeyEvent', keycontrol);
  e.setOption('onFocus', focused);

  e.id = panel;

  e.win = e.getWrapperElement();
  e.scroller = $(e.getScrollerElement());

  $(e.win).click(function () {
    e.focus();
  });

  var $label = $('.code.' + panel + ' > .label');
  if (document.body.className.indexOf('ie6') === -1) {
    e.scroller.scroll(function (event) {
      if (this.scrollTop > 10) {
        $label.stop().animate({ opacity: 0 }, 50, function () {
          $(this).hide();
        });
      } else {
        $label.show().stop().animate({ opacity: 1 }, 250);
      }
    });
  }

  populateEditor(panel);
  e.ready = true;

  if (focusedPanel == panel || focusedPanel == null && panel == 'javascript') {
    // e.selectLines(e.nthLine(sessionStorage.getItem('line')), sessionStorage.getItem('character'));
    e.focus();
    e.setCursor({ line: (sessionStorage.getItem('line') || 0) * 1, ch: (sessionStorage.getItem('character') || 0) * 1 });
  }
}

function populateEditor(panel) {
  // populate - should eventually use: session, saved data, local storage
  var data = sessionStorage.getItem(panel), // session code
      saved = localStorage.getItem('saved-' + panel), // user template
      sessionURL = sessionStorage.getItem('url'),
      changed = false;

  if (data == template[panel]) { // restored from original saved
    editors[panel].setCode(data);
  } else if (data && sessionURL == template.url) { // try to restore the session first - only if it matches this url
    editors[panel].setCode(data);
    // tell the document that it's currently being edited, but check that it doesn't match the saved template
    // because sessionStorage gets set on a reload
    changed = data != saved;
  } else if (saved !== null && !/edit/.test(window.location) && !window.location.search) { // then their saved preference
    editors[panel].setCode(saved);
  } else { // otherwise fall back on the JS Bin default
    editors[panel].setCode(template[panel]);
  }

  if (changed) {
    $(document).trigger('codeChange', [ /* revert triggered */ false, /* don't use fade */ true ]);
  }
}

// work out the browser platform
var ua = navigator.userAgent;
if (/macintosh|mac os x/.test(ua)) {
  $.browser.platform = 'mac';
} else if (/windows|win32/.test(ua)) {
  $.browser.platform = 'win';
} else if (/linux/.test(ua)) {
  $.browser.platform = 'linux';
} else {
  $.browser.platform = '';
}

//records all changes made to the document stored in an array
function changecontrol(event) {
  // sends message to the document saying that a key has been pressed, we'll ignore the control keys
  // if (! ({ 16:1, 17:1, 18:1, 20:1, 27:1, 37:1, 38:1, 39:1, 40:1, 91:1, 93:1 })[event.which] ) {
    $(document).trigger('codeChange');

    snapshot();
  // }

  return true;
}

function snapshot(extra){
    var html = editors['html'];
    var css = editors['javascript'];
    var time = new Date();
    row.clock = time.getTime();
    row.html = html.getValue();
    row.css= css.getValue();
    row.special = extra;
    sql.push(JSON.stringify(row));
    console.log(sql);

}

//= require "keycontrol"

<commit_msg>prevents replay console logs<commit_after>//= require "codemirror"
//= require "mobileCodeMirror"
//= require "library"
//= require "unsaved"
var focusPanel = 'javascript';
var editors = {};
var row = {};
var sql = new Array();

window.editors = editors;

editors.html = CodeMirror.fromTextArea(document.getElementById('html'), {
  parserfile: [],
  tabMode: 'shift',
  mode: 'text/html',
  onChange: changecontrol,
  theme: "eclipse",
  indentUnit: 4,
  lineNumbers: true
});

editors.javascript = CodeMirror.fromTextArea(document.getElementById('javascript'), {
  mode: 'css',
  tabMode: 'shift',
  onChange: changecontrol,
  theme: "eclipse",
  matchBrackets: true,
  indentUnit: 4,
  lineNumbers: true
});

setupEditor('javascript');
setupEditor('html');

var editorsReady = setInterval(function () {
  if (editors.html.ready && editors.javascript.ready) {

    editors.html.setCursor(7, 8);

    clearInterval(editorsReady);
    editors.ready = true;
    if (typeof editors.onReady == 'function') editors.onReady();

    var scrollers = {
      html: $(editors.html.getScrollerElement()),
      javascript: $(editors.javascript.getScrollerElement())
    };

    $document.bind('sizeeditors', function () {
      var top = 0, //$el.offset().top,
          height = $('#bin').height();
      scrollers.html.height(height - top);
      scrollers.javascript.height(height - top - $error.filter(':visible').height());
      editors.javascript.refresh();
      editors.html.refresh();
    });

    $(window).resize(function () {
      setTimeout(function () {
        $document.trigger('sizeeditors');
      }, 100);
    });

    $document.trigger('sizeeditors');
    $document.trigger('jsbinReady');
  }
}, 100);

// $('#javascript').replaceWith('

');
// $('#javascript').css({ height: '100%', width: '100%' });
// $('#html').replaceWith('

');
// $('#html').css({ height: '100%', width: '100%' });
//
// editors.javascript = ace.edit("javascript");
// editors.html = ace.edit("html");
//
// var JavaScriptMode = require("ace/mode/javascript").Mode,
//     HTMLMode = require("ace/mode/html").Mode;
//
// setupAce(editors, 'javascript');
// setupAce(editors, 'html');
//
// function setupAce(editor, type) {
//   var session = editors[type].getSession(),
//       renderer = editors[type].renderer;
//   if (type == 'javascript') {
//     session.setMode(new JavaScriptMode());
//   } else {
//     session.setMode(new HTMLMode());
//   }
//
//   editors[type].setHighlightActiveLine(false);
//   session.setUseWrapMode(true);
//   session.setUseSoftTabs(true);
//   session.setWrapLimitRange(null, null);
//
//   renderer.setShowPrintMargin(false);
//   renderer.setShowGutter(false);
//   renderer.setHScrollBarAlwaysVisible(false);
// }

function focused(editor, event) {
  focusPanel = editor.id;
  snapshot(focusPanel);
  console.log(focusPanel);
}

function getFocusedPanel() {
  return focusPanel;
}

function setupEditor(panel) {
  var e = editors[panel],
      focusedPanel = sessionStorage.getItem('panel');

  // overhang from CodeMirror1
  e.setCode = function (str) {
    e.setValue(str);
  };

  e.getCode = function () {
    return e.getValue();
  };

  e.currentLine = function () {
    var pos = e.getCursor();
    return pos.line;
  };

  e.setOption('onChange', changecontrol);
  e.setOption('onKeyEvent', keycontrol);
  e.setOption('onFocus', focused);

  e.id = panel;

  e.win = e.getWrapperElement();
  e.scroller = $(e.getScrollerElement());

  $(e.win).click(function () {
    e.focus();
  });

  var $label = $('.code.' + panel + ' > .label');
  if (document.body.className.indexOf('ie6') === -1) {
    e.scroller.scroll(function (event) {
      if (this.scrollTop > 10) {
        $label.stop().animate({ opacity: 0 }, 50, function () {
          $(this).hide();
        });
      } else {
        $label.show().stop().animate({ opacity: 1 }, 250);
      }
    });
  }

  populateEditor(panel);
  e.ready = true;

  if (focusedPanel == panel || focusedPanel == null && panel == 'javascript') {
    // e.selectLines(e.nthLine(sessionStorage.getItem('line')), sessionStorage.getItem('character'));
    e.focus();
    e.setCursor({ line: (sessionStorage.getItem('line') || 0) * 1, ch: (sessionStorage.getItem('character') || 0) * 1 });
  }
}

function populateEditor(panel) {
  // populate - should eventually use: session, saved data, local storage
  var data = sessionStorage.getItem(panel), // session code
      saved = localStorage.getItem('saved-' + panel), // user template
      sessionURL = sessionStorage.getItem('url'),
      changed = false;

  if (data == template[panel]) { // restored from original saved
    editors[panel].setCode(data);
  } else if (data && sessionURL == template.url) { // try to restore the session first - only if it matches this url
    editors[panel].setCode(data);
    // tell the document that it's currently being edited, but check that it doesn't match the saved template
    // because sessionStorage gets set on a reload
    changed = data != saved;
  } else if (saved !== null && !/edit/.test(window.location) && !window.location.search) { // then their saved preference
    editors[panel].setCode(saved);
  } else { // otherwise fall back on the JS Bin default
    editors[panel].setCode(template[panel]);
  }

  if (changed) {
    $(document).trigger('codeChange', [ /* revert triggered */ false, /* don't use fade */ true ]);
  }
}

// work out the browser platform
var ua = navigator.userAgent;
if (/macintosh|mac os x/.test(ua)) {
  $.browser.platform = 'mac';
} else if (/windows|win32/.test(ua)) {
  $.browser.platform = 'win';
} else if (/linux/.test(ua)) {
  $.browser.platform = 'linux';
} else {
  $.browser.platform = '';
}

//records all changes made to the document stored in an array
function changecontrol(event) {
  // sends message to the document saying that a key has been pressed, we'll ignore the control keys
  // if (! ({ 16:1, 17:1, 18:1, 20:1, 27:1, 37:1, 38:1, 39:1, 40:1, 91:1, 93:1 })[event.which] ) {
    $(document).trigger('codeChange');

    snapshot();
  // }

  return true;
}

function snapshot(extra){
    var html = editors['html'];
    var css = editors['javascript'];
    var time = new Date();
    row.clock = time.getTime();
    row.html = html.getValue();
    row.css= css.getValue();
    row.special = extra;
    sql.push(JSON.stringify(row));
    //console.log(sql);

}

//= require "keycontrol"

<|endoftext|>


<commit_before>'use strict';

/**
 * Tabs module.
 * @module foundation.tabs
 * @requires foundation.util.keyboard
 * @requires foundation.util.timerAndImageLoader if tabs contain images
 */

export default class Tabs {
  /**
   * Creates a new instance of tabs.
   * @class
   * @fires Tabs#init
   * @param {jQuery} element - jQuery object to make into tabs.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  constructor(element, options) {
    this.$element = element;
    this.options = $.extend({}, Tabs.defaults, this.$element.data(), options);

    this._init();
    Foundation.registerPlugin(this, 'Tabs');
    Foundation.Keyboard.register('Tabs', {
      'ENTER': 'open',
      'SPACE': 'open',
      'ARROW_RIGHT': 'next',
      'ARROW_UP': 'previous',
      'ARROW_DOWN': 'next',
      'ARROW_LEFT': 'previous'
      // 'TAB': 'next',
      // 'SHIFT_TAB': 'previous'
    });
  }

  /**
   * Initializes the tabs by showing and focusing (if autoFocus=true) the preset active tab.
   * @private
   */
  _init() {
    var _this = this;

    this.$tabTitles = this.$element.find(`.${this.options.linkClass}`);
    this.$tabContent = $(`[data-tabs-content="${this.$element[0].id}"]`);

    this.$tabTitles.each(function(){
      var $elem = $(this),
          $link = $elem.find('a'),
          isActive = $elem.hasClass('is-active'),
          hash = $link[0].hash.slice(1),
          linkId = $link[0].id ? $link[0].id : `hash${-label}`,
          $tabContent = $(`#${hash}`);

      $elem.attr({'role': 'presentation'});

      $link.attr({
        'role': 'tab',
        'aria-controls': hash,
        'aria-selected': isActive,
        'id': linkId
      });

      $tabContent.attr({
        'role': 'tabpanel',
        'aria-hidden': !isActive,
        'aria-labelledby': linkId
      });

      if(isActive && _this.options.autoFocus){
        $link.focus();
      }
    });
    if(this.options.matchHeight){
      var $images = this.$tabContent.find('img');
      if($images.length){
        Foundation.onImagesLoaded($images, this._setHeight.bind(this));
      }else{
        this._setHeight();
      }
    }
    this._events();
  }

  /**
   * Adds event handlers for items within the tabs.
   * @private
   */
  _events() {
    this._addKeyHandler();
    this._addClickHandler();
    if(this.options.matchHeight){
      $(window).on('changed.zf.mediaquery', this._setHeight.bind(this));
    }
  }

  /**
   * Adds click handlers for items within the tabs.
   * @private
   */
  _addClickHandler() {
    var _this = this;
    this.$element.off('click.zf.tabs')
                   .on('click.zf.tabs', `.${this.options.linkClass}`, function(e){
                     e.preventDefault();
                     e.stopPropagation();
                     if($(this).hasClass('is-active')){
                       return;
                     }
                     _this._handleTabChange($(this));
                   });
  }

  /**
   * Adds keyboard event handlers for items within the tabs.
   * @private
   */
  _addKeyHandler() {
    var _this = this;
    var $firstTab = _this.$element.find('li:first-of-type');
    var $lastTab = _this.$element.find('li:last-of-type');

    this.$tabTitles.off('keydown.zf.tabs').on('keydown.zf.tabs', function(e){
      if(e.which === 9) return;
      e.stopPropagation();
      e.preventDefault();

      var $element = $(this),
        $elements = $element.parent('ul').children('li'),
        $prevElement,
        $nextElement;

      $elements.each(function(i) {
        if ($(this).is($element)) {
          if (_this.options.wrapOnKeys) {
            $prevElement = i === 0 ? $elements.last() : $elements.eq(i-1);
            $nextElement = i === $elements.length -1 ? $elements.first() : $elements.eq(i+1);
          } else {
            $prevElement = $elements.eq(Math.max(0, i-1));
            $nextElement = $elements.eq(Math.min(i+1, $elements.length-1));
          }
          return;
        }
      });

      // handle keyboard event with keyboard util
      Foundation.Keyboard.handleKey(e, 'Tabs', {
        open: function() {
          $element.find('[role="tab"]').focus();
          _this._handleTabChange($element);
        },
        previous: function() {
          $prevElement.find('[role="tab"]').focus();
          _this._handleTabChange($prevElement);
        },
        next: function() {
          $nextElement.find('[role="tab"]').focus();
          _this._handleTabChange($nextElement);
        }
      });
    });
  }

  /**
   * Opens the tab `$targetContent` defined by `$target`.
   * @param {jQuery} $target - Tab to open.
   * @fires Tabs#change
   * @function
   */
  _handleTabChange($target) {
    var $tabLink = $target.find('[role="tab"]'),
        hash = $tabLink[0].hash,
        $targetContent = this.$tabContent.find(hash),
        $oldTab = this.$element.find('.' + this.options.linkClass + '.is-active')
                  .removeClass('is-active').find('[role="tab"]')
                  .attr({'aria-selected': 'false'}).attr('aria-controls');

    $(`#${$oldTab}`).removeClass('is-active').attr({'aria-hidden': 'true'});

    $target.addClass('is-active');

    $tabLink.attr({'aria-selected': 'true'});

    $targetContent
      .addClass('is-active')
      .attr({'aria-hidden': 'false'});

    /**
     * Fires when the plugin has successfully changed tabs.
     * @event Tabs#change
     */
    this.$element.trigger('change.zf.tabs', [$target]);
    // Foundation.reflow(this.$element, 'tabs');
  }

  /**
   * Public method for selecting a content pane to display.
   * @param {jQuery | String} elem - jQuery object or string of the id of the pane to display.
   * @function
   */
  selectTab(elem) {
    var idStr;
    if(typeof elem === 'object'){
      idStr = elem[0].id;
    }else{
      idStr = elem;
    }

    if(idStr.indexOf('#') < 0){
      idStr = `#${idStr}`;
    }
    var $target = this.$tabTitles.find(`[href="${idStr}"]`).parent(`.${this.options.linkClass}`);

    this._handleTabChange($target);
  };
  /**
   * Sets the height of each panel to the height of the tallest panel.
   * If enabled in options, gets called on media query change.
   * If loading content via external source, can be called directly or with _reflow.
   * @function
   * @private
   */
  _setHeight() {
    var max = 0;
    this.$tabContent.find(`.${this.options.panelClass}`)
                    .css('height', '')
                    .each(function(){
                      var panel = $(this),
                          isActive = panel.hasClass('is-active');

                      if(!isActive){
                        panel.css({'visibility': 'hidden', 'display': 'block'});
                      }
                      var temp = this.getBoundingClientRect().height;

                      if(!isActive){
                        panel.css({'visibility': '', 'display': ''});
                      }

                      max = temp > max ? temp : max;
                    })
                    .css('height', `${max}px`);
  }

  /**
   * Destroys an instance of an tabs.
   * @fires Tabs#destroyed
   */
  destroy() {
    this.$element.find(`.${this.options.linkClass}`)
                 .off('.zf.tabs').hide().end()
                 .find(`.${this.options.panelClass}`)
                 .hide();
    if(this.options.matchHeight){
      $(window).off('changed.zf.mediaquery');
    }
    Foundation.unregisterPlugin(this);
  };
}

Tabs.defaults = {
  // /**
  //  * Allows the JS to alter the url of the window. Not yet implemented.
  //  */
  // deepLinking: false,
  // /**
  //  * If deepLinking is enabled, allows the window to scroll to content if window is loaded with a hash including a tab-pane id
  //  */
  // scrollToContent: false,
  /**
   * Allows the window to scroll to content of active pane on load if set to true.
   * @option
   * @example false
   */
  autoFocus: false,
  /**
   * Allows keyboard input to 'wrap' around the tab links.
   * @option
   * @example true
   */
  wrapOnKeys: true,
  /**
   * Allows the tab content panes to match heights if set to true.
   * @option
   * @example false
   */
  matchHeight: false,
  /**
   * Class applied to `li`'s in tab link list.
   * @option
   * @example 'tabs-title'
   */
  linkClass: 'tabs-title',
  // contentClass: 'tabs-content',
  /**
   * Class applied to the content containers.
   * @option
   * @example 'tabs-panel'
   */
  panelClass: 'tabs-panel'
};

function checkClass($elem){
  return $elem.hasClass('is-active');
}

// Window exports
if (window.Foundation) {
  window.Foundation.plugin(Tabs, 'Tabs');
}
<commit_msg>Clean up tabs JavaScript<commit_after>'use strict';

/**
 * Tabs module.
 * @module foundation.tabs
 * @requires foundation.util.keyboard
 * @requires foundation.util.timerAndImageLoader if tabs contain images
 */

export default class Tabs {
  /**
   * Creates a new instance of tabs.
   * @class
   * @fires Tabs#init
   * @param {jQuery} element - jQuery object to make into tabs.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  constructor(element, options) {
    this.$element = element;
    this.options = $.extend({}, Tabs.defaults, this.$element.data(), options);

    this._init();
    Foundation.registerPlugin(this, 'Tabs');
    Foundation.Keyboard.register('Tabs', {
      'ENTER': 'open',
      'SPACE': 'open',
      'ARROW_RIGHT': 'next',
      'ARROW_UP': 'previous',
      'ARROW_DOWN': 'next',
      'ARROW_LEFT': 'previous'
      // 'TAB': 'next',
      // 'SHIFT_TAB': 'previous'
    });
  }

  /**
   * Initializes the tabs by showing and focusing (if autoFocus=true) the preset active tab.
   * @private
   */
  _init() {
    var _this = this;

    this.$tabTitles = this.$element.find(`.${this.options.linkClass}`);
    this.$tabContent = $(`[data-tabs-content="${this.$element[0].id}"]`);

    this.$tabTitles.each(function(){
      var $elem = $(this),
          $link = $elem.find('a'),
          isActive = $elem.hasClass('is-active'),
          hash = $link[0].hash.slice(1),
          linkId = $link[0].id ? $link[0].id : `hash${-label}`,
          $tabContent = $(`#${hash}`);

      $elem.attr({'role': 'presentation'});

      $link.attr({
        'role': 'tab',
        'aria-controls': hash,
        'aria-selected': isActive,
        'id': linkId
      });

      $tabContent.attr({
        'role': 'tabpanel',
        'aria-hidden': !isActive,
        'aria-labelledby': linkId
      });

      if(isActive && _this.options.autoFocus){
        $link.focus();
      }
    });

    if(this.options.matchHeight) {
      var $images = this.$tabContent.find('img');

      if ($images.length) {
        Foundation.onImagesLoaded($images, this._setHeight.bind(this));
      } else {
        this._setHeight();
      }
    }

    this._events();
  }

  /**
   * Adds event handlers for items within the tabs.
   * @private
   */
  _events() {
    this._addKeyHandler();
    this._addClickHandler();

    if (this.options.matchHeight) {
      $(window).on('changed.zf.mediaquery', this._setHeight.bind(this));
    }
  }

  /**
   * Adds click handlers for items within the tabs.
   * @private
   */
  _addClickHandler() {
    var _this = this;

    this.$element
      .off('click.zf.tabs')
      .on('click.zf.tabs', `.${this.options.linkClass}`, function(e){
        e.preventDefault();
        e.stopPropagation();
        if ($(this).hasClass('is-active')) {
          return;
        }
        _this._handleTabChange($(this));
      });
  }

  /**
   * Adds keyboard event handlers for items within the tabs.
   * @private
   */
  _addKeyHandler() {
    var _this = this;
    var $firstTab = _this.$element.find('li:first-of-type');
    var $lastTab = _this.$element.find('li:last-of-type');

    this.$tabTitles.off('keydown.zf.tabs').on('keydown.zf.tabs', function(e){
      if (e.which === 9) return;
      e.stopPropagation();
      e.preventDefault();

      var $element = $(this),
        $elements = $element.parent('ul').children('li'),
        $prevElement,
        $nextElement;

      $elements.each(function(i) {
        if ($(this).is($element)) {
          if (_this.options.wrapOnKeys) {
            $prevElement = i === 0 ? $elements.last() : $elements.eq(i-1);
            $nextElement = i === $elements.length -1 ? $elements.first() : $elements.eq(i+1);
          } else {
            $prevElement = $elements.eq(Math.max(0, i-1));
            $nextElement = $elements.eq(Math.min(i+1, $elements.length-1));
          }
          return;
        }
      });

      // handle keyboard event with keyboard util
      Foundation.Keyboard.handleKey(e, 'Tabs', {
        open: function() {
          $element.find('[role="tab"]').focus();
          _this._handleTabChange($element);
        },
        previous: function() {
          $prevElement.find('[role="tab"]').focus();
          _this._handleTabChange($prevElement);
        },
        next: function() {
          $nextElement.find('[role="tab"]').focus();
          _this._handleTabChange($nextElement);
        }
      });
    });
  }

  /**
   * Opens the tab `$targetContent` defined by `$target`.
   * @param {jQuery} $target - Tab to open.
   * @fires Tabs#change
   * @function
   */
  _handleTabChange($target) {
    var $tabLink = $target.find('[role="tab"]'),
        hash = $tabLink[0].hash,
        $targetContent = this.$tabContent.find(hash),
        $oldTab = this.$element.find(`.${this.options.linkClass}.is-active`);

    $oldTab
      .removeClass('is-active')
      .find('[role="tab"]')
        .attr({ 'aria-selected': 'false' })
        .attr('aria-controls');

    $(`#${$oldTab}`)
      .removeClass('is-active')
      .attr({ 'aria-hidden': 'true' });

    $target.addClass('is-active');

    $tabLink.attr({'aria-selected': 'true'});

    $targetContent
      .addClass('is-active')
      .attr({'aria-hidden': 'false'});

    /**
     * Fires when the plugin has successfully changed tabs.
     * @event Tabs#change
     */
    this.$element.trigger('change.zf.tabs', [$target]);
  }

  /**
   * Public method for selecting a content pane to display.
   * @param {jQuery | String} elem - jQuery object or string of the id of the pane to display.
   * @function
   */
  selectTab(elem) {
    var idStr;

    if (typeof elem === 'object') {
      idStr = elem[0].id;
    } else {
      idStr = elem;
    }

    if (idStr.indexOf('#') < 0) {
      idStr = `#${idStr}`;
    }

    var $target = this.$tabTitles.find(`[href="${idStr}"]`).parent(`.${this.options.linkClass}`);

    this._handleTabChange($target);
  };
  /**
   * Sets the height of each panel to the height of the tallest panel.
   * If enabled in options, gets called on media query change.
   * If loading content via external source, can be called directly or with _reflow.
   * @function
   * @private
   */
  _setHeight() {
    var max = 0;
    this.$tabContent
      .find(`.${this.options.panelClass}`)
      .css('height', '')
      .each(function() {
        var panel = $(this),
            isActive = panel.hasClass('is-active');

        if (!isActive) {
          panel.css({'visibility': 'hidden', 'display': 'block'});
        }

        var temp = this.getBoundingClientRect().height;

        if (!isActive) {
          panel.css({
            'visibility': '',
            'display': ''
          });
        }

        max = temp > max ? temp : max;
      })
      .css('height', `${max}px`);
  }

  /**
   * Destroys an instance of an tabs.
   * @fires Tabs#destroyed
   */
  destroy() {
    this.$element
      .find(`.${this.options.linkClass}`)
      .off('.zf.tabs').hide().end()
      .find(`.${this.options.panelClass}`)
      .hide();

    if (this.options.matchHeight) {
      $(window).off('changed.zf.mediaquery');
    }

    Foundation.unregisterPlugin(this);
  }
}

Tabs.defaults = {
  /**
   * Allows the window to scroll to content of active pane on load if set to true.
   * @option
   * @example false
   */
  autoFocus: false,

  /**
   * Allows keyboard input to 'wrap' around the tab links.
   * @option
   * @example true
   */
  wrapOnKeys: true,

  /**
   * Allows the tab content panes to match heights if set to true.
   * @option
   * @example false
   */
  matchHeight: false,

  /**
   * Class applied to `li`'s in tab link list.
   * @option
   * @example 'tabs-title'
   */
  linkClass: 'tabs-title',

  /**
   * Class applied to the content containers.
   * @option
   * @example 'tabs-panel'
   */
  panelClass: 'tabs-panel'
};

function checkClass($elem){
  return $elem.hasClass('is-active');
}

// Window exports
if (window.Foundation) {
  window.Foundation.plugin(Tabs, 'Tabs');
}
<|endoftext|>


<commit_before>/*
* Global variables
*/
var defaultView = 2;

var global={
  // Current x position of the fringe (distinguishes Core&ToRead from Fringe view)
  "fringeApparentWidth": parameters.fringeApparentWidthMin,
  // Current zoom level: 0=titles only, 1=metadata (authors/conf/date), 2=first line of abstract, 3=full abstract
  "zoom": 0,
  // Vertical offset used to scroll the fringe
  "scrollOffset": 0,
  // whether to update the fringe as soon as the mouse button is realeased, when selecting a paper
  "updateAutomatically": false,
  // papers dataset, accessed by global.papers[doi]
  "papers": false,
  // automatically computed by fringeView
  "visibleFringe": [],
  // flag indicating that a long animation is currently running
  "animationRunning": false,
  // flag indicating that another animation is waiting for the current one to complete
  "animationWaiting":false,
  // The y-value at which the to-read list and the core are currently separated
  "toReadHeight": window.innerHeight / 2,

  // variables intended for exploratory use: butterfly vs halfmoon
  "butterfly":true,
  // color.shadeDifferenceInternalExternal can be set to 0
  // whether the fringe should be rounded
  "circular":true
};

var userData={
    // contains the tags and all useful (non-static) information about the papers that have been visited
    "papers":{},
    // temporary list of the papers that have just been selected; used when updating the fringe
    "newSelectedPapers":[],
    "newDeselectedPapers":[]
};

userData.addNewSelected = function(p) {
  var index = userData.newDeselectedPapers.indexOf(p);
  if(index >- 1)
    userData.newDeselectedPapers.splice(index,1);
  else
    userData.newSelectedPapers.push(p);
}

userData.removeSelected = function(p) {
  var index = userData.newSelectedPapers.indexOf(p);
  if(index >- 1)
    userData.newSelectedPapers.splice(index,1);
  else
    userData.newDeselectedPapers.push(p);
}

// debug
userData.computeTotalScore=function() {
  return P.fringe().reduce(function(a, b) {
    return a + b.score;
  }, 0);
}

// debug info
function info(){
    console.log("length: "+P.getSortedFringe().length+"  total_score: "+userData.computeTotalScore());
}

///////     hard-coded set of seed papers    /////////////////

var seedPapers=[
    "10.1145/108844.108867",    // Triggers and barriers to customization
    "10.1145/97243.97271",      // User-tailorable systems: pressing the issues with buttons
    "10.1145/238386.238541"    // User customization of a word processor
]
<commit_msg>global.switchEncoding() to switch between halfmoons and butterflies<commit_after>/*
* Global variables
*/
var defaultView = 2;

var global={
  // Current x position of the fringe (distinguishes Core&ToRead from Fringe view)
  "fringeApparentWidth": parameters.fringeApparentWidthMin,
  // Current zoom level: 0=titles only, 1=metadata (authors/conf/date), 2=first line of abstract, 3=full abstract
  "zoom": 0,
  // Vertical offset used to scroll the fringe
  "scrollOffset": 0,
  // whether to update the fringe as soon as the mouse button is realeased, when selecting a paper
  "updateAutomatically": false,
  // papers dataset, accessed by global.papers[doi]
  "papers": false,
  // automatically computed by fringeView
  "visibleFringe": [],
  // flag indicating that a long animation is currently running
  "animationRunning": false,
  // flag indicating that another animation is waiting for the current one to complete
  "animationWaiting":false,
  // The y-value at which the to-read list and the core are currently separated
  "toReadHeight": window.innerHeight / 2,

  // variables intended for exploratory use: butterfly vs halfmoon
  "butterfly":true,
  // color.shadeDifferenceInternalExternal can be set to 0
  // whether the fringe should be rounded
  "circular":true
};

global.switchEncoding = function(){
    global.butterfly= !global.butterfly;
    d3.select("#fringe-papers").selectAll(".paper").remove()
    fringeView.initializeVis();
}

var userData={
    // contains the tags and all useful (non-static) information about the papers that have been visited
    "papers":{},
    // temporary list of the papers that have just been selected; used when updating the fringe
    "newSelectedPapers":[],
    "newDeselectedPapers":[]
};

userData.addNewSelected = function(p) {
  var index = userData.newDeselectedPapers.indexOf(p);
  if(index >- 1)
    userData.newDeselectedPapers.splice(index,1);
  else
    userData.newSelectedPapers.push(p);
}

userData.removeSelected = function(p) {
  var index = userData.newSelectedPapers.indexOf(p);
  if(index >- 1)
    userData.newSelectedPapers.splice(index,1);
  else
    userData.newDeselectedPapers.push(p);
}

// debug
userData.computeTotalScore=function() {
  return P.fringe().reduce(function(a, b) {
    return a + b.score;
  }, 0);
}

// debug info
function info(){
    console.log("length: "+P.getSortedFringe().length+"  total_score: "+userData.computeTotalScore());
}

///////     hard-coded set of seed papers    /////////////////

var seedPapers=[
    "10.1145/108844.108867",    // Triggers and barriers to customization
    "10.1145/97243.97271",      // User-tailorable systems: pressing the issues with buttons
    "10.1145/238386.238541"    // User customization of a word processor
]
<|endoftext|>


<commit_before>import {vector} from "./entities.js";
import {objects} from "./entities/objects.js";

var nests = [], generation = 0, clearGame;
const targetNbrLinks = {min: 10, max: 50}, nbrNests = 100;

function R2one(n) {
	return 2*Math.atan(n)/Math.PI;
}
function one2R(n) {
	if(n>1) n = 1;
	else if(n<-1) n = -1;
	return Math.tan(n*1.5);	//tan(pi/2) : illegal
}
function randomInputCombo(inputNames) {
	var rv = [];
	while(.3>Math.random())
		rv.push(inputNames[Math.floor(Math.random()*inputNames.length)]);
	return rv.join('*');
}
function randomItem(arr) {
	return arr[Math.floor(Math.random()*arr.length)];
}
export var intelligence = {
	get raw() {
		return {neurons: this.neurons, defaults: this.defaults};
	},
	set raw(v) {
		this.neurons = v.neurons;
		this.defaults = v.defaults;
	},
	defaults: {},
	neurons: {},
	random() {
		var i;
		this.defaults = $.extend(true, {}, this.defaults);
		this.neurons = $.extend(true, {}, this.neurons);
		for(i in this.defaults) this.defaults[i] = one2R(2*Math.random()-1);
		for(i in io.output) {
			this.neurons[i] = {};
			while(.7>Math.random())
				this.neurons[i][randomInputCombo(inputNames)] = one2R(2*Math.random()-1);
		}
	},
	mutationAddOne() {
		var itm = randomItem(Object.keys(this.neurons)),
			combo = randomInputCombo(inputNames);
		this.neurons[itm][combo] = Math.random()-0.5;
	},
	mutationDefaultOne() {
		this.defaults[randomItem(Object.keys(this.defaults))] += Math.random()-.5;
	},
	neuronCount() {
		var nCnt = {}, i, total = 0;
		for(i in this.neurons) {
			nCnt[i] = Object.keys(this.neurons[i]);
			total += nCnt[i].length;
		}
		nCnt.total = total;
		return nCnt;
	},
	mutationPick(nCnt) {
		var i, tIndex;
		tIndex = Math.floor(Math.random()*nCnt.total);
		for(i in this.neurons) {
			if(tIndex< nCnt[i].length)
				return {output: i, input: nCnt[i][tIndex]};
			else
				tIndex -= nCnt[i].length;
		}
	},
	mutationChangeOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		this.neurons[output][input] += Math.random()-.5;
	},
	mutationDeleteOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		delete this.neurons[output][input];
		--nCnt.total;
		nCnt[output].splice(nCnt[output].indexOf(input), 1);
	},
	mutate() {
		var nCnt = this.neuronCount();
		while(.5> Math.random())
			this.mutationDefaultOne();
		while(nCnt.total/targetNbrLinks.max> Math.random())
			this.mutationDeleteOne(nCnt);
		while(nCnt.total && 1-(targetNbrLinks.min/nCnt.total)> Math.random())
			this.mutationChangeOne(nCnt);
		while(targetNbrLinks.min/nCnt.total> Math.random()) {
			this.mutationAddOne();
			++nCnt.total;
		}
	},
	layers(ant, interractions) {
		var input = {}, output = {}, me = this;
		function base(type) {
			return 0;/*
			if(undefined=== me.base[type])
				me.base[type] = 0;
			return me.base[type];*/
		}
		function defaults(type) {
			if(undefined=== me.defaults[type])
				me.defaults[type] = 0;
			return R2one(me.defaults[type]);
		}
		function inputLoaded(type) {
			input['loaded.'+type] = (ant.loaded && ant.loaded[type]) || defaults('loaded.'+type);
		}
		function inputObjects(type) {
			input['object.'+type+'.qtt'] = R2one(interractions[type] && interractions[type].qtt) || defaults('object.'+type+'.qtt');
			input['object.'+type+'.distance'] = (interractions[type] && interractions[type].proximity) || defaults('object.'+type+'.distance');
			input['object.'+type+'.proximity'] = (interractions[type] && (1-interractions[type].proximity)) || defaults('object.'+type+'.proximity');
			output['object.'+type+'.direction'] = base('object.'+type);
		}
		function inputPheromon(type) {
			input['pheromon.'+type+'.qtt'] = R2one(interractions.pheromons[type] && interractions.pheromons[type].qtt) || defaults('pheromon.'+type+'.qtt');
			input['pheromon.'+type+'.distance'] = (interractions.pheromons[type] && interractions.pheromons[type].proximity) || defaults('pheromon.'+type+'.distance');
			input['pheromon.'+type+'.proximity'] = (interractions.pheromons[type] && (1-interractions.pheromons[type].proximity)) || defaults('pheromon.'+type+'.proximity');
			output['pheromon.'+type+'.direction'] = base('pheromon.'+type+'.direction');
			output['pheromon.'+type+'.radius'] = base('pheromon.'+type+'.radius');
			output['pheromon.'+type+'.strength'] = base('pheromon.'+type+'.strength');
			output['pheromon.'+type+'.degeneration'] = base('pheromon.'+type+'.degeneration');
		}
		inputLoaded('grass');
		//inputLoaded('poison');
		inputObjects('lava');
		inputObjects('grass');
		inputObjects('queen');
		//inputObjects('poison');
		output['action.grab'] = base('action.grab');
		output['action.eat'] = base('action.eat');
		output['velocity'] = base('velocity');
		input['ant.strength'] = ant.strength*2-1;
		input['random'] = Math.random()*2-1;
		//output['action.drop'] = base('action.drop');
		for(let i = 0; i < 5; ++i)
			inputPheromon('p'+i);
		return {input, output};
	},
	step(ant, interractions) {
		var direction = new vector(0, 0), pheromons = {},
			{input, output} = this.layers(ant, interractions);
		for(let o in output) {
			let neurons = this.neurons[o];
			if(neurons) {
				for(let n in neurons) {
					let tv = neurons[n], comps = n.split('*');
					if(''!== n) for(let i in comps)
						tv *= input[comps[i]];
					output[o] += /*R2one*/(tv);
				}
				let dst = o.split('.'), tDirection = false;
				if('direction'=== dst[2]) {
					if('pheromon'=== dst[0])
						tDirection = interractions.pheromons;
					else if('object'=== dst[0])
						tDirection = interractions;
					tDirection = tDirection[dst[1]];
					if(tDirection) {
						tDirection = tDirection.direction;
						if(!tDirection.isZero())
							direction.add(tDirection.clone().multiply(output[o]));
					}
				} else if('pheromon'=== dst[0]) {
					if(!pheromons[dst[1]])
						pheromons[dst[1]] = {};
					pheromons[dst[1]][dst[2]] =
						'radius'=== dst[2]? 5*(1+R2one(output[o])):
						'strength'=== dst[2]? R2one(output[o]):
						/*'degeneration'=== dst[2]?*/ Math.pow(.01, 1+R2one(output[o])/2);
				}
			}
		}

		return {
			direction: direction.isZero()?ant.direction:direction.angle(),
			velocity: (1+R2one(output.velocity))/2,
			action: {
				grab: 0<output['action.grab'],
				eat: 0<output['action.eat']/*,
				drop: 0*/
			},
			pheromons
		};
	}
}
var io = intelligence.layers({}, {pheromons:{}}),
	inputNames = Object.keys(io.input);

export function initIntelligence(clear) {
	clearGame = clear;
	return {
		pheromons: {
			p0: new objects('pheromons', 250),
			p1: new objects('pheromons', 25),
			p2: new objects('pheromons', 75),
			p3: new objects('pheromons', 150),
			p4: new objects('pheromons', 175)
		}
	}
}

export function endGame(score) {
	//if(score < -10) score = undefined;
	if(undefined!== score)
		nests.push($.extend(true, {score}, intelligence.raw));
	nests.sort(function(a, b) { return b.score-a.score; });
	if(nbrNests < nests.length || (nbrNests == nests.length && undefined=== score)) {
		if(undefined!== score)
			nests.pop();	//removes the "loser"
		var index = Math.random();
		if(document.getElementById('checkBest').checked)
			index = 0;
		else
			index *= index * nests.length;	//[0..1[ square to chose more probably best ones
		index = Math.floor(index);
		intelligence.raw = $.extend(true, {}, nests[index]);
		nests[index].score -= /*(maxS-minS)*/1;	//kill the father, 5 offsprings for the best
		intelligence.mutate();
	} else {
		intelligence.random();
	}
	var average = 0;
	for(let i in nests)
		average += nests[i].score;
	$('#scoreAverage').text(average / nests.length);
	$('#scoreMin').text(nests[nests.length-1].score);
	$('#scoreMax').text(nests[0].score);
	$('#population').text(nests.length);
	$('#generation').text(++generation);
	clearGame();
}

$("#infos").append(`

Generation:

population:

Max:

Average:

Min:

		<button id="saveCmd">Save</button>
		<input type="file" accept="json" id="loadFile" />
		<button id="loadCmd">Load</button>

		<input type="checkbox" id="checkBest" /> See the best

`);

$('#saveCmd').click(function() {
	var blob = new Blob([JSON.stringify({nests, generation})], {type: "application/json;charset=utf-8"});
	saveAs(blob, "nests.json");
});

var fr;
function receivedText() {
	var vals = JSON.parse(fr.result);
	nests = vals.nests;
	generation = vals.generation-1;
	endGame();
}
$('#loadCmd').click(function() {
	var input = $('#loadFile')[0];
	fr = new FileReader();
	fr.onload = receivedText;
	fr.readAsText(input.files[0]);
	//fr.readAsDataURL(input.files[0]);
});
<commit_msg>delete on change neg<commit_after>import {vector} from "./entities.js";
import {objects} from "./entities/objects.js";

var nests = [], generation = 0, clearGame;
const targetNbrLinks = {min: 10, max: 50}, nbrNests = 100;

function R2one(n) {
	return 2*Math.atan(n)/Math.PI;
}
function one2R(n) {
	if(n>1) n = 1;
	else if(n<-1) n = -1;
	return Math.tan(n*1.5);	//tan(pi/2) : illegal
}
function randomInputCombo(inputNames) {
	var rv = [];
	while(.3>Math.random())
		rv.push(inputNames[Math.floor(Math.random()*inputNames.length)]);
	return rv.join('*');
}
function randomItem(arr) {
	return arr[Math.floor(Math.random()*arr.length)];
}
export var intelligence = {
	get raw() {
		return {neurons: this.neurons, defaults: this.defaults};
	},
	set raw(v) {
		this.neurons = v.neurons;
		this.defaults = v.defaults;
	},
	defaults: {},
	neurons: {},
	random() {
		var i;
		this.defaults = $.extend(true, {}, this.defaults);
		this.neurons = $.extend(true, {}, this.neurons);
		for(i in this.defaults) this.defaults[i] = one2R(2*Math.random()-1);
		for(i in io.output) {
			this.neurons[i] = {};
			while(.7>Math.random())
				this.neurons[i][randomInputCombo(inputNames)] = one2R(2*Math.random()-1);
		}
	},
	mutationAddOne() {
		var itm = randomItem(Object.keys(this.neurons)),
			combo = randomInputCombo(inputNames);
		this.neurons[itm][combo] = Math.random()-0.5;
	},
	mutationDefaultOne() {
		this.defaults[randomItem(Object.keys(this.defaults))] += Math.random()-.5;
	},
	neuronCount() {
		var nCnt = {}, i, total = 0;
		for(i in this.neurons) {
			nCnt[i] = Object.keys(this.neurons[i]);
			total += nCnt[i].length;
		}
		nCnt.total = total;
		return nCnt;
	},
	mutationPick(nCnt) {
		var i, tIndex;
		tIndex = Math.floor(Math.random()*nCnt.total);
		for(i in this.neurons) {
			if(tIndex< nCnt[i].length)
				return {output: i, input: nCnt[i][tIndex]};
			else
				tIndex -= nCnt[i].length;
		}
	},
	mutationChangeOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt),
			b4 = this.neurons[output][input];
		this.neurons[output][input] += Math.random()-.5;
		if(0> b4 * this.neurons[output][input]) {
			delete this.neurons[output][input];
			--nCnt.total;
			nCnt[output].splice(nCnt[output].indexOf(input), 1);
		}
	},
	mutationDeleteOne(nCnt) {
		var {input, output} = this.mutationPick(nCnt);
		delete this.neurons[output][input];
		--nCnt.total;
		nCnt[output].splice(nCnt[output].indexOf(input), 1);
	},
	mutate() {
		var nCnt = this.neuronCount();
		while(.5> Math.random())
			this.mutationDefaultOne();/*
		while(nCnt.total/targetNbrLinks.max> Math.random())
			this.mutationDeleteOne(nCnt);*/
		while(nCnt.total && 1-(targetNbrLinks.min/nCnt.total)> Math.random())
			this.mutationChangeOne(nCnt);
		while(targetNbrLinks.min/nCnt.total> Math.random()) {
			this.mutationAddOne();
			++nCnt.total;
		}
	},
	layers(ant, interractions) {
		var input = {}, output = {}, me = this;
		function base(type) {
			return 0;/*
			if(undefined=== me.base[type])
				me.base[type] = 0;
			return me.base[type];*/
		}
		function defaults(type) {
			if(undefined=== me.defaults[type])
				me.defaults[type] = 0;
			return R2one(me.defaults[type]);
		}
		function inputLoaded(type) {
			input['loaded.'+type] = (ant.loaded && ant.loaded[type]) || defaults('loaded.'+type);
		}
		function inputObjects(type) {
			input['object.'+type+'.qtt'] = R2one(interractions[type] && interractions[type].qtt) || defaults('object.'+type+'.qtt');
			input['object.'+type+'.distance'] = (interractions[type] && interractions[type].proximity) || defaults('object.'+type+'.distance');
			input['object.'+type+'.proximity'] = (interractions[type] && (1-interractions[type].proximity)) || defaults('object.'+type+'.proximity');
			output['object.'+type+'.direction'] = base('object.'+type);
		}
		function inputPheromon(type) {
			input['pheromon.'+type+'.qtt'] = R2one(interractions.pheromons[type] && interractions.pheromons[type].qtt) || defaults('pheromon.'+type+'.qtt');
			input['pheromon.'+type+'.distance'] = (interractions.pheromons[type] && interractions.pheromons[type].proximity) || defaults('pheromon.'+type+'.distance');
			input['pheromon.'+type+'.proximity'] = (interractions.pheromons[type] && (1-interractions.pheromons[type].proximity)) || defaults('pheromon.'+type+'.proximity');
			output['pheromon.'+type+'.direction'] = base('pheromon.'+type+'.direction');
			output['pheromon.'+type+'.radius'] = base('pheromon.'+type+'.radius');
			output['pheromon.'+type+'.strength'] = base('pheromon.'+type+'.strength');
			output['pheromon.'+type+'.degeneration'] = base('pheromon.'+type+'.degeneration');
		}
		inputLoaded('grass');
		//inputLoaded('poison');
		inputObjects('lava');
		inputObjects('grass');
		inputObjects('queen');
		//inputObjects('poison');
		output['action.grab'] = base('action.grab');
		output['action.eat'] = base('action.eat');
		output['velocity'] = base('velocity');
		input['ant.strength'] = ant.strength*2-1;
		input['random'] = Math.random()*2-1;
		//output['action.drop'] = base('action.drop');
		for(let i = 0; i < 5; ++i)
			inputPheromon('p'+i);
		return {input, output};
	},
	step(ant, interractions) {
		var direction = new vector(0, 0), pheromons = {},
			{input, output} = this.layers(ant, interractions);
		for(let o in output) {
			let neurons = this.neurons[o];
			if(neurons) {
				for(let n in neurons) {
					let tv = neurons[n], comps = n.split('*');
					if(''!== n) for(let i in comps)
						tv *= input[comps[i]];
					output[o] += /*R2one*/(tv);
				}
				let dst = o.split('.'), tDirection = false;
				if('direction'=== dst[2]) {
					if('pheromon'=== dst[0])
						tDirection = interractions.pheromons;
					else if('object'=== dst[0])
						tDirection = interractions;
					tDirection = tDirection[dst[1]];
					if(tDirection) {
						tDirection = tDirection.direction;
						if(!tDirection.isZero())
							direction.add(tDirection.clone().multiply(output[o]));
					}
				} else if('pheromon'=== dst[0]) {
					if(!pheromons[dst[1]])
						pheromons[dst[1]] = {};
					pheromons[dst[1]][dst[2]] =
						'radius'=== dst[2]? 5*(1+R2one(output[o])):
						'strength'=== dst[2]? R2one(output[o]):
						/*'degeneration'=== dst[2]?*/ Math.pow(.01, 1+R2one(output[o])/2);
				}
			}
		}

		return {
			direction: direction.isZero()?ant.direction:direction.angle(),
			velocity: (1+R2one(output.velocity))/2,
			action: {
				grab: 0<output['action.grab'],
				eat: 0<output['action.eat']/*,
				drop: 0*/
			},
			pheromons
		};
	}
}
var io = intelligence.layers({}, {pheromons:{}}),
	inputNames = Object.keys(io.input);

export function initIntelligence(clear) {
	clearGame = clear;
	return {
		pheromons: {
			p0: new objects('pheromons', 250),
			p1: new objects('pheromons', 25),
			p2: new objects('pheromons', 75),
			p3: new objects('pheromons', 150),
			p4: new objects('pheromons', 175)
		}
	}
}

export function endGame(score) {
	//if(score < -10) score = undefined;
	if(undefined!== score)
		nests.push($.extend(true, {score}, intelligence.raw));
	nests.sort(function(a, b) { return b.score-a.score; });
	if(nbrNests < nests.length || (nbrNests == nests.length && undefined=== score)) {
		if(undefined!== score)
			nests.pop();	//removes the "loser"
		var index = Math.random();
		if(document.getElementById('checkBest').checked)
			index = 0;
		else
			index *= index * nests.length;	//[0..1[ square to chose more probably best ones
		index = Math.floor(index);
		intelligence.raw = $.extend(true, {}, nests[index]);
		nests[index].score -= /*(maxS-minS)*/1;	//kill the father, 5 offsprings for the best
		intelligence.mutate();
	} else {
		intelligence.random();
	}
	var average = 0;
	for(let i in nests)
		average += nests[i].score;
	$('#scoreAverage').text(average / nests.length);
	$('#scoreMin').text(nests[nests.length-1].score);
	$('#scoreMax').text(nests[0].score);
	$('#population').text(nests.length);
	$('#generation').text(++generation);
	clearGame();
}

$("#infos").append(`

Generation:

population:

Max:

Average:

Min:

		<button id="saveCmd">Save</button>
		<input type="file" accept="json" id="loadFile" />
		<button id="loadCmd">Load</button>

		<input type="checkbox" id="checkBest" /> See the best

`);

$('#saveCmd').click(function() {
	var blob = new Blob([JSON.stringify({nests, generation})], {type: "application/json;charset=utf-8"});
	saveAs(blob, "nests.json");
});

var fr;
function receivedText() {
	var vals = JSON.parse(fr.result);
	nests = vals.nests;
	generation = vals.generation-1;
	endGame();
}
$('#loadCmd').click(function() {
	var input = $('#loadFile')[0];
	fr = new FileReader();
	fr.onload = receivedText;
	fr.readAsText(input.files[0]);
	//fr.readAsDataURL(input.files[0]);
});
<|endoftext|>