<commit_before>/*
* Copyright 2014 Your name <your e-mail>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

(function(Nuvola)
{
"use strict";

  // Create media player component
  var player = Nuvola.$object(Nuvola.MediaPlayer);

  // Handy aliases
  var PlaybackState = Nuvola.PlaybackState;
  var PlayerAction = Nuvola.PlayerAction;

  // Create new WebApp prototype
  var WebApp = Nuvola.$WebApp();

  // Initialization routines
  WebApp._onInitWebWorker = function(emitter)
  {
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    var state = document.readyState;
    if (state === "interactive" || state === "complete")
    this._onPageReady();
    else
    document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
  };

  // Page is ready for magic
  WebApp._onPageReady = function()
  {
    // Connect handler for signal ActionActivated
    Nuvola.actions.connect("ActionActivated", this);

    // Start update routine
    this.update();
  };

  // Extract data from the web page
  WebApp.update = function()
  {
    var hasClass = function (el, cls) {
      return el && el.className && new RegExp("(\\s|^)" + cls + "(\\s|$)").test(el.className);
    };

    var playerElement = document.querySelector(".player.music");

    // Playback state
    var state = PlaybackState.UNKNOWN;
    if (playerElement) {
      var playElement = playerElement.querySelector(".play-btn");
      var pauseElement = playerElement.querySelector(".pause-btn");
      if (hasClass(playElement, "hidden")) {
        state = PlaybackState.PLAYING;
      } else if (hasClass(pauseElement, "hidden")) {
        state = PlaybackState.PAUSED;
      }
    }
    player.setPlaybackState(state);
    // Track informations
    var track = {
      title: null,
      artist: null,
      album: null,
      artLocation: null
    };
    if (playerElement) {
      var posterElement = playerElement.querySelector(".media-poster");
      track.title = posterElement.attributes['data-title'].value;
      track.album = posterElement.attributes['data-parent-title'].value;
      track.artist = posterElement.attributes['data-grandparent-title'].value;
      track.artLocation = posterElement.attributes['data-image-url'].value;
    }
    player.setTrack(track);

    // Schedule the next update
    setTimeout(this.update.bind(this), 500);
  };

  // Handler of playback actions
  WebApp._onActionActivated = function(emitter, name, param)
  {
  };

  WebApp.start();

})(this);  // function(Nuvola)
<commit_msg>Set player actions status<commit_after>/*
* Copyright 2014 Your name <your e-mail>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

(function(Nuvola)
{
"use strict";

  // Create media player component
  var player = Nuvola.$object(Nuvola.MediaPlayer);

  // Handy aliases
  var PlaybackState = Nuvola.PlaybackState;
  var PlayerAction = Nuvola.PlayerAction;

  // Create new WebApp prototype
  var WebApp = Nuvola.$WebApp();

  // Initialization routines
  WebApp._onInitWebWorker = function(emitter)
  {
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    var state = document.readyState;
    if (state === "interactive" || state === "complete")
    this._onPageReady();
    else
    document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
  };

  // Page is ready for magic
  WebApp._onPageReady = function()
  {
    // Connect handler for signal ActionActivated
    Nuvola.actions.connect("ActionActivated", this);

    // Start update routine
    this.update();
  };

  WebApp._isHiddenOrDisabled = function (el) {
    var regex = new RegExp("(\\s|^)(disabled|hidden)(\\s|$)");
    return el && el.className && regex.test(el.className);
  };

  // Extract data from the web page
  WebApp.update = function()
  {
    var playerElement = document.querySelector(".player.music");
    var playElement, pauseElement, previousElement, nextElement;
    if (playerElement) {
      playElement = playerElement.querySelector(".play-btn");
      pauseElement = playerElement.querySelector(".pause-btn");
      previousElement = playerElement.querySelector(".previous-btn");
      nextElement = playerElement.querySelector(".next-btn");
    }
    // Playback state
    var state = PlaybackState.UNKNOWN;
    if (playerElement) {
      if (this._isHiddenOrDisabled(playElement)) {
        state = PlaybackState.PLAYING;
      } else if (this._isHiddenOrDisabled(pauseElement)) {
        state = PlaybackState.PAUSED;
      }
    }
    player.setPlaybackState(state);

    // Track informations
    var track = {
      title: null,
      artist: null,
      album: null,
      artLocation: null
    };
    if (playerElement) {
      var posterElement = playerElement.querySelector(".media-poster");
      track.title = posterElement.attributes['data-title'].value;
      track.album = posterElement.attributes['data-parent-title'].value;
      track.artist = posterElement.attributes['data-grandparent-title'].value;
      track.artLocation = posterElement.attributes['data-image-url'].value;
    }
    player.setTrack(track);

    // Player actions
    player.setCanPlay(playerElement && !this._isHiddenOrDisabled(playElement));
    player.setCanPause(playerElement && !this._isHiddenOrDisabled(pauseElement));
    player.setCanGoPrev(playerElement && !this._isHiddenOrDisabled(previousElement));
    player.setCanGoNext(playerElement && !this._isHiddenOrDisabled(nextElement));

    // Schedule the next update
    setTimeout(this.update.bind(this), 500);
  };

  // Handler of playback actions
  WebApp._onActionActivated = function(emitter, name, param)
  {
  };

  WebApp.start();

})(this);  // function(Nuvola)
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { StepsContainer, StepContent, StepForm, StepButton } from '~client/components/steps'
import { ControlLabel, FormControl, FormGroup } from '~client/components/forms'
import { Button } from '~client/ux/components'

class Page extends Component {

  constructor (props) {
    super(props)
    this.state = { isConnected: false }
  }

  handleConnectionTest () {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        this.setState({ isConnected: true })
        resolve()
      }, 1000)
    })
  }

  render () {
    const { fields: { domain }, ...formProps } = this.props

    return (

        <StepsContainer title='Domínio da comunidade'>
          <StepContent title='Insira o domínio desejado'>
            <StepForm
              {...formProps}
              onSubmit={values => new Promise((resolve, reject) => {
                console.log(values)
                return resolve()
              })}
            >
              <FormGroup {...domain}>
                <ControlLabel>Domínio da sua comunidade</ControlLabel>
                <FormControl type='text' placeholder='Ex. minhacomunidade.org' />
              </FormGroup>
              <Button type='submit'>Adicionar</Button>
            </StepForm>
          </StepContent>
          <StepContent title='Altere os servidores no seu provedor DNS'>

1. Faça login no seu provedor de DNS (onde seu domínio está registrado, por exemplo GoDaddy, Locaweb, RegistroBR)

2. Encontre a página de gerenciador de DNS, e altere os nomes de servidor para os servidores do Bonde:

ns1.1098.19872.0871.98

ns2.1098.19872.0871.98

ns3.1098.19872.0871.98

            <StepButton>Continuar</StepButton>
          </StepContent>
          <StepContent title='Teste a conexão'>

Clique no botão abaixo para verificar se tudo está certo.

Atenção: a mudança de DNS pode demorar até 48 horas para ser propagada pela internet.

            <StepButton onClick={() => this.handleConnectionTest()}>
              {!this.state.isConnected ? 'Testar' : 'Pronto'}
            </StepButton>
          </StepContent>
        </StepsContainer>

    )
  }
}

export default Page
<commit_msg>chore(graphql): change playground to test query #622<commit_after>import React, { Component } from 'react'
import { gql, graphql } from 'react-apollo'

const ActivistsList = gql`
  query ActivistsList {
    allActivists {
      edges {
        node {
          name
        }
      }
    }
  }
`

const Styles = {
  width: '500px',
  heigth: '150px',
  backgroundColor: '#fff',
  padding: '10px'
}

class Page extends Component {

  render () {
    const { data: { loading, error, allActivists } } = this.props

    return (

        {loading &&
Carregando ativistas
}
        {error &&
{error.message}
}
        {allActivists && (

            {allActivists.edges.map(a =>
{a.node.name}
)}

        )}

    )
  }
}

const PageWithData = graphql(ActivistsList)(Page)

export default PageWithData
<|endoftext|>


<commit_before>import classNames from 'classnames';
import {Link} from 'react-router';
/* eslint-disable no-unused-vars */
import React from 'react';
/* eslint-enable no-unused-vars */

import TabsUtil from '../utils/TabsUtil';
import NotificationStore from '../stores/NotificationStore';

/**
 * Adds tabs-specific methods onto a class.
 *
 * Note that routes may be cascaded where multiple tab hierarchies are in place
 * by prefixing one route with another, eg the route 'universe-packages-detail'
 * will result in the tab 'universe-packages' being highlighted as active.
 *
 * @mixin
 * @see {@link TabsUtil}
 * @example
 * class PageWithRoutableTabs extends mixin(TabsMixin) {
 *   constructor() {
 *     super(...args);
 *     // The default selected tab may be defined so:
 *     this.state = {
 *       currentTab: 'defined-route-1'
 *     }
 *   }
 *   componentWillMount() {
 *     // The keys to this object must be defined routes
 *     this.tabs_tabs = {
 *      'defined-route-1': 'Tab Title 1',
 *      'defined-route-2': 'Tab Title 2'
 *     }
 *     this.updateCurrentTab();
 *   }
 *   getNavigation() {
 *     return (
 *

 *         {this.tabs_getRoutedTabs()}
 *

 *     );
 *   }
 *   render() {
 *     return (
 *       <Page
 *         navigation={this.getNavigation()}>
 *         <RouteHandler />
 *       </Page>
 *     );
 *   }
 * }
 */
const TabsMixin = {
  /**
   * Returns a tab that has a callback when clicked.
   * @see #tabs_handleTabClick
   *
   * @param  {String} customClasses to be added to the Link item
   * @param  {String} tab key of tab to render
   * @return {Component} React component to render
   */
  tabs_getUnroutedItem(customClasses, tab) {
    let tabLabelClass = classNames(customClasses, {'tab-item-label': true});

    return (

          {this.tabs_tabs[tab]}

    );
  },

  /**
   * Will return an array of tabs to be rendered.
   * Will only have onClick handlers, as these tabs are not routable.
   *
   * @param  {String} customClasses to be added to the active component
   * @return {Array} of tabs to render
   */
  tabs_getUnroutedTabs(customClasses) {
    return TabsUtil.getTabs(
      this.tabs_tabs,
      this.state.currentTab,
      this.tabs_getUnroutedItem.bind(this, customClasses)
    );
  },

  /**
   * Returns a Link for a given tab. This tab is expected to be routable.
   *
   * @param  {String} customClasses to be added to the Link item
   * @param  {String} tab key of tab to render
   * @return {Component} React component to render
   */
  tabs_getRoutedItem(customClasses, tab) {
    let notificationCount = NotificationStore.getNotificationCount(tab);
    let tabLabelClass = classNames(customClasses, {'tab-item-label': true});

    if (notificationCount > 0) {
      return (
        <Link
          to={tab}
          className={tabLabelClass}
          onClick={this.tabs_handleTabClick.bind(this, tab)}>

            {this.tabs_tabs[tab]}

            {notificationCount}

        </Link>
      );
    }

    return (
      <Link
        to={tab}
        className={tabLabelClass}
        onClick={this.tabs_handleTabClick.bind(this, tab)}>

          {this.tabs_tabs[tab]}

      </Link>
    );
  },

  /**
   * Will return an array of routed tabs to be rendered.
   * Will have onClick handlers and active Link components with routes
   *
   * @param  {String} customClasses to be added to the active component
   * @return {Array} of tabs to render
   */
  tabs_getRoutedTabs(customClasses) {
    return TabsUtil.getTabs(
      this.tabs_tabs,
      this.state.currentTab,
      this.tabs_getRoutedItem.bind(this, customClasses)
    );
  },

  /**
   * Calls the function to render the active tab
   *
   * @return {Component} the result of the appropriate render function
   */
  tabs_getTabView() {
    // Replace spaces in the currentTab string because we are calling the string
    // as a function on the component, and functions cannot have spaces.
    let currentTab = this.tabs_tabs[this.state.currentTab].replace(' ', '');
    let renderFunction = this[`render${currentTab}TabView`];

    if (renderFunction == null) {
      return null;
    }

    return renderFunction.apply(this, arguments);
  },

  tabs_handleTabClick(nextTab) {
    this.setState({currentTab: nextTab});
  }
};

module.exports = TabsMixin;
<commit_msg>Making TabsMixin take more properties than just classes<commit_after>import classNames from 'classnames/dedupe';
import {Link} from 'react-router';
/* eslint-disable no-unused-vars */
import React from 'react';
/* eslint-enable no-unused-vars */

import TabsUtil from '../utils/TabsUtil';
import NotificationStore from '../stores/NotificationStore';

/**
 * Adds tabs-specific methods onto a class.
 *
 * Note that routes may be cascaded where multiple tab hierarchies are in place
 * by prefixing one route with another, eg the route 'universe-packages-detail'
 * will result in the tab 'universe-packages' being highlighted as active.
 *
 * @mixin
 * @see {@link TabsUtil}
 * @example
 * class PageWithRoutableTabs extends mixin(TabsMixin) {
 *   constructor() {
 *     super(...args);
 *     // The default selected tab may be defined so:
 *     this.state = {
 *       currentTab: 'defined-route-1'
 *     }
 *   }
 *   componentWillMount() {
 *     // The keys to this object must be defined routes
 *     this.tabs_tabs = {
 *      'defined-route-1': 'Tab Title 1',
 *      'defined-route-2': 'Tab Title 2'
 *     }
 *     this.updateCurrentTab();
 *   }
 *   getNavigation() {
 *     return (
 *

 *         {this.tabs_getRoutedTabs()}
 *

 *     );
 *   }
 *   render() {
 *     return (
 *       <Page
 *         navigation={this.getNavigation()}>
 *         <RouteHandler />
 *       </Page>
 *     );
 *   }
 * }
 */
const TabsMixin = {
  /**
   * Returns a tab that has a callback when clicked.
   * @see #tabs_handleTabClick
   *
   * @param  {Object} props to be added to the Link item
   * @param  {String} tab key of tab to render
   * @return {Component} React component to render
   */
  tabs_getUnroutedItem(props = {}, tab) {
    let attributes = Object.assign({}, props);
    delete attributes.classNames;
    let tabLabelClass = classNames({'tab-item-label': true}, props.classNames);

    return (

          {this.tabs_tabs[tab]}

    );
  },

  /**
   * Will return an array of tabs to be rendered.
   * Will only have onClick handlers, as these tabs are not routable.
   *
   * @param  {Object} props to be added to the active component
   * @return {Array} of tabs to render
   */
  tabs_getUnroutedTabs(props) {
    return TabsUtil.getTabs(
      this.tabs_tabs,
      this.state.currentTab,
      this.tabs_getUnroutedItem.bind(this, props)
    );
  },

  /**
   * Returns a Link for a given tab. This tab is expected to be routable.
   *
   * @param  {Object} props to be added to the Link item
   * @param  {String} tab key of tab to render
   * @return {Component} React component to render
   */
  tabs_getRoutedItem(props = {}, tab) {
    let attributes = Object.assign({}, props);
    delete attributes.classNames;
    let notificationCount = NotificationStore.getNotificationCount(tab);
    let tabLabelClass = classNames({'tab-item-label': true}, props.classNames);

    if (notificationCount > 0) {
      return (
        <Link
          to={tab}
          className={tabLabelClass}
          onClick={this.tabs_handleTabClick.bind(this, tab)}
          {...attributes}>

            {this.tabs_tabs[tab]}

            {notificationCount}

        </Link>
      );
    }

    return (
      <Link
        to={tab}
        className={tabLabelClass}
        onClick={this.tabs_handleTabClick.bind(this, tab)}
        {...attributes}>

          {this.tabs_tabs[tab]}

      </Link>
    );
  },

  /**
   * Will return an array of routed tabs to be rendered.
   * Will have onClick handlers and active Link components with routes
   *
   * @param  {Object} props to be added to the active component
   * @return {Array} of tabs to render
   */
  tabs_getRoutedTabs(props) {
    return TabsUtil.getTabs(
      this.tabs_tabs,
      this.state.currentTab,
      this.tabs_getRoutedItem.bind(this, props)
    );
  },

  /**
   * Calls the function to render the active tab
   *
   * @return {Component} the result of the appropriate render function
   */
  tabs_getTabView() {
    // Replace spaces in the currentTab string because we are calling the string
    // as a function on the component, and functions cannot have spaces.
    let currentTab = this.tabs_tabs[this.state.currentTab].replace(' ', '');
    let renderFunction = this[`render${currentTab}TabView`];

    if (renderFunction == null) {
      return null;
    }

    return renderFunction.apply(this, arguments);
  },

  tabs_handleTabClick(nextTab) {
    this.setState({currentTab: nextTab});
  }
};

module.exports = TabsMixin;
<|endoftext|>


<commit_before>/*
 * Copyright 2011-2015 Jiří Janoušek <janousek.jiri@gmail.com>
 * Copyright 2014 Martin Pöhlmann <martin.deimos@gmx.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(Nuvola)
{

var C_ = Nuvola.Translate.pgettext;
var ngettext = Nuvola.Translate.ngettext;

var State = Nuvola.PlaybackState;
var PlayerAction = Nuvola.PlayerAction;
var player = Nuvola.$object(Nuvola.MediaPlayer);

var ACTION_THUMBS_UP = "thumbs-up";
var ACTION_THUMBS_DOWN = "thumbs-down";
var THUMBS_ACTIONS = [ACTION_THUMBS_UP, ACTION_THUMBS_DOWN];

if (!String.prototype.endsWith)
{
    String.prototype.endsWith = function(searchString, position)
    {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length)
            position = subjectString.length;
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
}

var WebApp = Nuvola.$WebApp();

WebApp._onInitAppRunner = function(emitter)
{
    Nuvola.WebApp._onInitAppRunner.call(this, emitter);
    try
    {
        Nuvola.core.connect("ResourceRequest", this);
    }
    catch (e)
    {
        var msg = "\n\n{1} integration script {2}.{3} requires a newer version of Nuvola Player 3"
         + " to apply a workaround for a Google Play Music bug.";
        throw new Error(Nuvola.format(msg, this.meta.name, this.meta.version_major, this.meta.version_minor));
    }

    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_UP, C_("Action", "Thumbs up"), null, null, null, true);
    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_DOWN,C_("Action", "Thumbs down"), null, null, null, true);
}

WebApp._onInitWebWorker = function(emitter)
{
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    Nuvola.actions.connect("ActionActivated", this);
    this.thumbsUp = undefined;
    this.thumbsDown = undefined;
    this.state = State.UNKNOWN;
    player.addExtraActions(THUMBS_ACTIONS);
    document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
}

WebApp._onResourceRequest = function(emitter, request)
{
    var FIXED_WEBCOMPONENTS = (
            "https://raw.githubusercontent.com/tiliado/nuvola-app-google-play/"
            + "16627e12bf115fcaa97f4abc581382c2251f0e76/webcomponents.js");

    if (request.url.endsWith("webcomponents.js") && request.url != FIXED_WEBCOMPONENTS)
    {
        request.url = FIXED_WEBCOMPONENTS;
        Nuvola.log("Fixed webcomponents: {1}", request.url);
    }
}

/**
 * Signal handler for @link{Core::UriChanged}
 */
WebApp._onUriChanged = function(emitter, uri)
{
    /*
     * Users that use the queue page a lot might end up with it as a start-up page. However, this page is always empty
     * and not useful at all, so load Listen now page instead. https://bugs.launchpad.net/nuvola-player/+bug/1306678
     */
    if (uri === "https://play.google.com/music/listen#/ap/queue")
        uri = this.meta.home_url;

    Nuvola.WebApp._onUriChanged.call(this, emitter, uri);
}

WebApp._onPageReady = function()
{
    this.update();
}

WebApp.update = function()
{
    var elm;
    /* Fix for Google Play Music shows an incomplete queue. https://github.com/tiliado/nuvolaplayer/issues/106 */
    if (!this._queueOverlayFixed && (elm = document.getElementById("queue-overlay")) && elm.hasAttribute("layout"))
    {
        elm.removeAttribute("layout");
        this._queueOverlayFixed = true;
    }

    this.state = State.UNKNOWN;
    var prevSong, nextSong, canPlay, canPause;
    try
    {
        var pp = this._getPlayPauseButton();
        if (pp.disabled === true)
            this.state = State.UNKNOWN;
        else if (pp.className == "playing")
            this.state = State.PLAYING;
        else
            this.state = State.PAUSED;

        if (this.state !== State.UNKNOWN)
        {
            prevSong = this._getGoPrevButton().disabled === false;
            nextSong = this._getGoNextButton().disabled === false;
        }
        else
        {
            prevSong = nextSong = false;
        }
    }
    catch (e)
    {
        this.state = State.UNKNOWN;
        this.scheduleUpdate();
        return;
    }

    player.setPlaybackState(this.state);
    player.setCanPause(this.state === State.PLAYING);
    player.setCanPlay(this.state === State.PAUSED || this.state === State.UNKNOWN && this._luckyMix());
    player.setCanGoPrev(prevSong);
    player.setCanGoNext(nextSong);

    var track = {};
    try
    {
        track.artLocation = document.getElementById('playingAlbumArt').src.replace("=s90-", "=s500-");
    }
    catch(e)
    {
        track.artLocation =  null;
    }

    try
    {
        elm = document.getElementById('player-song-title').firstChild;
        track.title = elm.innerText || elm.textContent;
    }
    catch(e)
    {
        track.title = null;
    }

    try
    {
        elm = document.getElementById('player-artist').firstChild;
        track.artist = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.artist = null;
    }

    try
    {
        elm = document.querySelector("#playerSongInfo .player-album");
        track.album = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.album = null;
    }

    player.setTrack(track);

    // Extract enabled flag and state from a web page
    var actionsEnabled = {};
    var actionsStates = {};
    var thumbsUp = this._getThumbsUpButton();
    var thumbsDown = this._getThumbsDownButton();
    actionsStates[ACTION_THUMBS_UP] = this._isThumbSelected(thumbsUp);
    actionsStates[ACTION_THUMBS_DOWN] = this._isThumbSelected(thumbsDown);
    actionsEnabled[ACTION_THUMBS_UP] = !!thumbsUp;
    actionsEnabled[ACTION_THUMBS_DOWN] = !!thumbsDown;

    // Compare with previous values and update if necessary
    Nuvola.actions.updateEnabledFlags(actionsEnabled);
    Nuvola.actions.updateStates(actionsStates);

    this.scheduleUpdate();
}

WebApp.scheduleUpdate = function()
{
    setTimeout(this.update.bind(this), 500);
}

WebApp._getButton = function(id)
{
    return document.querySelector("sj-icon-button[data-id=" + id + "]");
}

WebApp._getPlayPauseButton = function()
{
    return this._getButton("play-pause");
}

WebApp._getGoPrevButton = function()
{
    return this._getButton("rewind");
}

WebApp._getGoNextButton = function()
{
    return this._getButton("forward");
}

WebApp._getShuffleButton = function()
{
    return this._getButton("shuffle");
}

WebApp._getThumbsUpButton = function()
{
    return document.querySelector(".player-rating-container sj-icon-button[data-rating='5']");
}

WebApp._getThumbsDownButton = function()
{
    return document.querySelector(".player-rating-container sj-icon-button[data-rating='1']");
}

WebApp._isThumbSelected = function(elm)
{
    return elm ? elm.$.icon.getAttribute('aria-label').indexOf('-outline') == -1: false;
}

WebApp._onActionActivated = function(emitter, name, param)
{
    var prevSong = this._getGoPrevButton();
    var nextSong = this._getGoNextButton();
    var playPause = this._getPlayPauseButton();
    var luckyMix = this._luckyMix();

    switch (name)
    {
    /* Base media player actions */
    case PlayerAction.TOGGLE_PLAY:
        if (this.state === State.UNKNOWN && luckyMix)
            luckyMix.click();
        else
            playPause.click();
        break;
    case PlayerAction.PLAY:
        if (this.state === State.UNKNOWN && luckyMix)
            luckyMix.click();
        else if (this.state != State.PLAYING)
            playPause.click();
        break;
    case PlayerAction.PAUSE:
    case PlayerAction.STOP:
        if (this.state == State.PLAYING)
            playPause.click();
        break;
    case PlayerAction.PREV_SONG:
        if (prevSong)
           prevSong.click();
        break;
    case PlayerAction.NEXT_SONG:
        if (nextSong)
            nextSong.click();
        break;

    /* Custom actions */
    case ACTION_THUMBS_UP:
        this._getThumbsUpButton().click();
        break;
    case ACTION_THUMBS_DOWN:
        this._getThumbsDownButton().click();
        break;
    }
}

WebApp._luckyMix = function()
{
    return location.hash === "#/now" ? document.querySelector("div[data-type=imfl]") || false : false;
}

WebApp.start();

})(this);  // function(Nuvola)
<commit_msg>Substitute broken webcomponents.min.js<commit_after>/*
 * Copyright 2011-2015 Jiří Janoušek <janousek.jiri@gmail.com>
 * Copyright 2014 Martin Pöhlmann <martin.deimos@gmx.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(Nuvola)
{

var C_ = Nuvola.Translate.pgettext;
var ngettext = Nuvola.Translate.ngettext;

var State = Nuvola.PlaybackState;
var PlayerAction = Nuvola.PlayerAction;
var player = Nuvola.$object(Nuvola.MediaPlayer);

var ACTION_THUMBS_UP = "thumbs-up";
var ACTION_THUMBS_DOWN = "thumbs-down";
var THUMBS_ACTIONS = [ACTION_THUMBS_UP, ACTION_THUMBS_DOWN];

if (!String.prototype.endsWith)
{
    String.prototype.endsWith = function(searchString, position)
    {
        var subjectString = this.toString();
        if (position === undefined || position > subjectString.length)
            position = subjectString.length;
        position -= searchString.length;
        var lastIndex = subjectString.indexOf(searchString, position);
        return lastIndex !== -1 && lastIndex === position;
    };
}

var WebApp = Nuvola.$WebApp();

WebApp._onInitAppRunner = function(emitter)
{
    Nuvola.WebApp._onInitAppRunner.call(this, emitter);
    try
    {
        Nuvola.core.connect("ResourceRequest", this);
    }
    catch (e)
    {
        var msg = "\n\n{1} integration script {2}.{3} requires a newer version of Nuvola Player 3"
         + " to apply a workaround for a Google Play Music bug.";
        throw new Error(Nuvola.format(msg, this.meta.name, this.meta.version_major, this.meta.version_minor));
    }

    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_UP, C_("Action", "Thumbs up"), null, null, null, true);
    Nuvola.actions.addAction("playback", "win", ACTION_THUMBS_DOWN,C_("Action", "Thumbs down"), null, null, null, true);
}

WebApp._onInitWebWorker = function(emitter)
{
    Nuvola.WebApp._onInitWebWorker.call(this, emitter);

    Nuvola.actions.connect("ActionActivated", this);
    this.thumbsUp = undefined;
    this.thumbsDown = undefined;
    this.state = State.UNKNOWN;
    player.addExtraActions(THUMBS_ACTIONS);
    document.addEventListener("DOMContentLoaded", this._onPageReady.bind(this));
}

WebApp._onResourceRequest = function(emitter, request)
{
    var FIXED_WEBCOMPONENTS = "nuvola://webcomponents.js";
    if (request.url.endsWith("webcomponents.min.js") || request.url.endsWith("webcomponents.js"))
    {
        request.url = FIXED_WEBCOMPONENTS;
        Nuvola.log("Fixed webcomponents: {1}", request.url);
    }
}

/**
 * Signal handler for @link{Core::UriChanged}
 */
WebApp._onUriChanged = function(emitter, uri)
{
    /*
     * Users that use the queue page a lot might end up with it as a start-up page. However, this page is always empty
     * and not useful at all, so load Listen now page instead. https://bugs.launchpad.net/nuvola-player/+bug/1306678
     */
    if (uri === "https://play.google.com/music/listen#/ap/queue")
        uri = this.meta.home_url;

    Nuvola.WebApp._onUriChanged.call(this, emitter, uri);
}

WebApp._onPageReady = function()
{
    this.update();
}

WebApp.update = function()
{
    var elm;
    /* Fix for Google Play Music shows an incomplete queue. https://github.com/tiliado/nuvolaplayer/issues/106 */
    if (!this._queueOverlayFixed && (elm = document.getElementById("queue-overlay")) && elm.hasAttribute("layout"))
    {
        elm.removeAttribute("layout");
        this._queueOverlayFixed = true;
    }

    this.state = State.UNKNOWN;
    var prevSong, nextSong, canPlay, canPause;
    try
    {
        var pp = this._getPlayPauseButton();
        if (pp.disabled === true)
            this.state = State.UNKNOWN;
        else if (pp.className == "playing")
            this.state = State.PLAYING;
        else
            this.state = State.PAUSED;

        if (this.state !== State.UNKNOWN)
        {
            prevSong = this._getGoPrevButton().disabled === false;
            nextSong = this._getGoNextButton().disabled === false;
        }
        else
        {
            prevSong = nextSong = false;
        }
    }
    catch (e)
    {
        this.state = State.UNKNOWN;
        this.scheduleUpdate();
        return;
    }

    player.setPlaybackState(this.state);
    player.setCanPause(this.state === State.PLAYING);
    player.setCanPlay(this.state === State.PAUSED || this.state === State.UNKNOWN && this._luckyMix());
    player.setCanGoPrev(prevSong);
    player.setCanGoNext(nextSong);

    var track = {};
    try
    {
        track.artLocation = document.getElementById('playingAlbumArt').src.replace("=s90-", "=s500-");
    }
    catch(e)
    {
        track.artLocation =  null;
    }

    try
    {
        elm = document.getElementById('player-song-title').firstChild;
        track.title = elm.innerText || elm.textContent;
    }
    catch(e)
    {
        track.title = null;
    }

    try
    {
        elm = document.getElementById('player-artist').firstChild;
        track.artist = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.artist = null;
    }

    try
    {
        elm = document.querySelector("#playerSongInfo .player-album");
        track.album = elm.innerText || elm.textContent;
    }
    catch (e)
    {
        track.album = null;
    }

    player.setTrack(track);

    // Extract enabled flag and state from a web page
    var actionsEnabled = {};
    var actionsStates = {};
    var thumbsUp = this._getThumbsUpButton();
    var thumbsDown = this._getThumbsDownButton();
    actionsStates[ACTION_THUMBS_UP] = this._isThumbSelected(thumbsUp);
    actionsStates[ACTION_THUMBS_DOWN] = this._isThumbSelected(thumbsDown);
    actionsEnabled[ACTION_THUMBS_UP] = !!thumbsUp;
    actionsEnabled[ACTION_THUMBS_DOWN] = !!thumbsDown;

    // Compare with previous values and update if necessary
    Nuvola.actions.updateEnabledFlags(actionsEnabled);
    Nuvola.actions.updateStates(actionsStates);

    this.scheduleUpdate();
}

WebApp.scheduleUpdate = function()
{
    setTimeout(this.update.bind(this), 500);
}

WebApp._getButton = function(id)
{
    return document.querySelector("sj-icon-button[data-id=" + id + "]");
}

WebApp._getPlayPauseButton = function()
{
    return this._getButton("play-pause");
}

WebApp._getGoPrevButton = function()
{
    return this._getButton("rewind");
}

WebApp._getGoNextButton = function()
{
    return this._getButton("forward");
}

WebApp._getShuffleButton = function()
{
    return this._getButton("shuffle");
}

WebApp._getThumbsUpButton = function()
{
    return document.querySelector(".player-rating-container sj-icon-button[data-rating='5']");
}

WebApp._getThumbsDownButton = function()
{
    return document.querySelector(".player-rating-container sj-icon-button[data-rating='1']");
}

WebApp._isThumbSelected = function(elm)
{
    return elm ? elm.$.icon.getAttribute('aria-label').indexOf('-outline') == -1: false;
}

WebApp._onActionActivated = function(emitter, name, param)
{
    var prevSong = this._getGoPrevButton();
    var nextSong = this._getGoNextButton();
    var playPause = this._getPlayPauseButton();
    var luckyMix = this._luckyMix();

    switch (name)
    {
    /* Base media player actions */
    case PlayerAction.TOGGLE_PLAY:
        if (this.state === State.UNKNOWN && luckyMix)
            luckyMix.click();
        else
            playPause.click();
        break;
    case PlayerAction.PLAY:
        if (this.state === State.UNKNOWN && luckyMix)
            luckyMix.click();
        else if (this.state != State.PLAYING)
            playPause.click();
        break;
    case PlayerAction.PAUSE:
    case PlayerAction.STOP:
        if (this.state == State.PLAYING)
            playPause.click();
        break;
    case PlayerAction.PREV_SONG:
        if (prevSong)
           prevSong.click();
        break;
    case PlayerAction.NEXT_SONG:
        if (nextSong)
            nextSong.click();
        break;

    /* Custom actions */
    case ACTION_THUMBS_UP:
        this._getThumbsUpButton().click();
        break;
    case ACTION_THUMBS_DOWN:
        this._getThumbsDownButton().click();
        break;
    }
}

WebApp._luckyMix = function()
{
    return location.hash === "#/now" ? document.querySelector("div[data-type=imfl]") || false : false;
}

WebApp.start();

})(this);  // function(Nuvola)
<|endoftext|>


<commit_before>interface NavigationInstructionInit {
  fragment: string,
  queryString: string,
  params : Object,
  queryParams: Object,
  config: RouteConfig,
  parentInstruction: NavigationInstruction,
  previousInstruction: NavigationInstruction,
  router: Router,
  options: Object
}

export class CommitChangesStep {
  run(navigationInstruction: NavigationInstruction, next: Function) {
    return navigationInstruction._commitChanges(true).then(() => {
      navigationInstruction._updateTitle();
      return next();
    });
  }
}

/**
* Class used to represent an instruction during a navigation.
*/
export class NavigationInstruction {
  /**
  * The URL fragment.
  */
  fragment: string;

  /**
  * The query string.
  */
  queryString: string;

  /**
  * Parameters extracted from the route pattern.
  */
  params: any;

  /**
  * Parameters extracted from the query string.
  */
  queryParams: any;

  /**
  * The route config for the route matching this instruction.
  */
  config: RouteConfig;

  /**
  * The parent instruction, if this instruction was created by a child router.
  */
  parentInstruction: NavigationInstruction;

  /**
  * The instruction being replaced by this instruction in the current router.
  */
  previousInstruction: NavigationInstruction;

  /**
  * viewPort instructions to used activation.
  */
  viewPortInstructions: any;

  plan: Object = null;

  options: Object = {};

  constructor(init: NavigationInstructionInit) {
    Object.assign(this, init);

    this.params = this.params || {};
    this.viewPortInstructions = {};

    let ancestorParams = [];
    let current = this;
    do {
      let currentParams = Object.assign({}, current.params);
      if (current.config && current.config.hasChildRouter) {
        // remove the param for the injected child route segment
        delete currentParams[current.getWildCardName()];
      }

      ancestorParams.unshift(currentParams);
      current = current.parentInstruction;
    } while (current);

    let allParams = Object.assign({}, this.queryParams, ...ancestorParams);
    this.lifecycleArgs = [allParams, this.config, this];
  }

  /**
  * Gets an array containing this instruction and all child instructions for the current navigation.
  */
  getAllInstructions(): Array<NavigationInstruction> {
    let instructions = [this];
    for (let key in this.viewPortInstructions) {
      let childInstruction = this.viewPortInstructions[key].childNavigationInstruction;
      if (childInstruction) {
        instructions.push(...childInstruction.getAllInstructions());
      }
    }

    return instructions;
  }

  /**
  * Gets an array containing the instruction and all child instructions for the previous navigation.
  * Previous instructions are no longer available after navigation completes.
  */
  getAllPreviousInstructions(): Array<NavigationInstruction> {
    return this.getAllInstructions().map(c => c.previousInstruction).filter(c => c);
  }

  /**
  * Adds a viewPort instruction.
  */
  addViewPortInstruction(viewPortName: string, strategy: string, moduleId: string, component: any): any {
    let viewportInstruction = this.viewPortInstructions[viewPortName] = {
      name: viewPortName,
      strategy: strategy,
      moduleId: moduleId,
      component: component,
      childRouter: component.childRouter,
      lifecycleArgs: this.lifecycleArgs.slice()
    };

    return viewportInstruction;
  }

  /**
  * Gets the name of the route pattern's wildcard parameter, if applicable.
  */
  getWildCardName(): string {
    let wildcardIndex = this.config.route.lastIndexOf('*');
    return this.config.route.substr(wildcardIndex + 1);
  }

  /**
  * Gets the path and query string created by filling the route
  * pattern's wildcard parameter with the matching param.
  */
  getWildcardPath(): string {
    let wildcardName = this.getWildCardName();
    let path = this.params[wildcardName] || '';

    if (this.queryString) {
      path += '?' + this.queryString;
    }

    return path;
  }

  /**
  * Gets the instruction's base URL, accounting for wildcard route parameters.
  */
  getBaseUrl(): string {
    if (!this.params) {
      return this.fragment;
    }

    let wildcardName = this.getWildCardName();
    let path = this.params[wildcardName] || '';

    if (!path) {
      return this.fragment;
    }

    path = encodeURI(path);
    return this.fragment.substr(0, this.fragment.lastIndexOf(path));
  }

  _commitChanges(waitToSwap: boolean) {
    let router = this.router;
    router.currentInstruction = this;

    if (this.previousInstruction) {
      this.previousInstruction.config.navModel.isActive = false;
    }

    this.config.navModel.isActive = true;

    router._refreshBaseUrl();
    router.refreshNavigation();

    let loads = [];
    let delaySwaps = [];

    for (let viewPortName in this.viewPortInstructions) {
      let viewPortInstruction = this.viewPortInstructions[viewPortName];
      let viewPort = router.viewPorts[viewPortName];

      if (!viewPort) {
        throw new Error(`There was no router-view found in the view for ${viewPortInstruction.moduleId}.`);
      }

      if (viewPortInstruction.strategy === activationStrategy.replace) {
        if (waitToSwap) {
          delaySwaps.push({viewPort, viewPortInstruction});
        }

        loads.push(viewPort.process(viewPortInstruction, waitToSwap).then((x) => {
          if (viewPortInstruction.childNavigationInstruction) {
            return viewPortInstruction.childNavigationInstruction._commitChanges();
          }

          return undefined;
        }));
      } else {
        if (viewPortInstruction.childNavigationInstruction) {
          loads.push(viewPortInstruction.childNavigationInstruction._commitChanges(waitToSwap));
        }
      }
    }

    return Promise.all(loads).then(() => {
      delaySwaps.forEach(x => x.viewPort.swap(x.viewPortInstruction));
      return null;
    }).then(() => prune(this));
  }

  _updateTitle(): void {
    let title = this._buildTitle();
    if (title) {
      this.router.history.setTitle(title);
    }
  }

  _buildTitle(separator: string = ' | '): string {
    let title = this.config.navModel.title || '';
    let childTitles = [];

    for (let viewPortName in this.viewPortInstructions) {
      let viewPortInstruction = this.viewPortInstructions[viewPortName];

      if (viewPortInstruction.childNavigationInstruction) {
        let childTitle = viewPortInstruction.childNavigationInstruction._buildTitle(separator);
        if (childTitle) {
          childTitles.push(childTitle);
        }
      }
    }

    if (childTitles.length) {
      title = childTitles.join(separator) + (title ? separator : '') + title;
    }

    if (this.router.title) {
      title += (title ? separator : '') + this.router.title;
    }

    return title;
  }
}

function prune(instruction) {
  instruction.previousInstruction = null;
  instruction.plan = null;
}
<commit_msg>fix(tsd): define router property in NavigationInstruction<commit_after>interface NavigationInstructionInit {
  fragment: string,
  queryString: string,
  params : Object,
  queryParams: Object,
  config: RouteConfig,
  parentInstruction: NavigationInstruction,
  previousInstruction: NavigationInstruction,
  router: Router,
  options: Object
}

export class CommitChangesStep {
  run(navigationInstruction: NavigationInstruction, next: Function) {
    return navigationInstruction._commitChanges(true).then(() => {
      navigationInstruction._updateTitle();
      return next();
    });
  }
}

/**
* Class used to represent an instruction during a navigation.
*/
export class NavigationInstruction {
  /**
  * The URL fragment.
  */
  fragment: string;

  /**
  * The query string.
  */
  queryString: string;

  /**
  * Parameters extracted from the route pattern.
  */
  params: any;

  /**
  * Parameters extracted from the query string.
  */
  queryParams: any;

  /**
  * The route config for the route matching this instruction.
  */
  config: RouteConfig;

  /**
  * The parent instruction, if this instruction was created by a child router.
  */
  parentInstruction: NavigationInstruction;

  /**
  * The instruction being replaced by this instruction in the current router.
  */
  previousInstruction: NavigationInstruction;

  /**
  * viewPort instructions to used activation.
  */
  viewPortInstructions: any;

  /**
    * The router instance.
  */
  router: Router;

  plan: Object = null;

  options: Object = {};

  constructor(init: NavigationInstructionInit) {
    Object.assign(this, init);

    this.params = this.params || {};
    this.viewPortInstructions = {};

    let ancestorParams = [];
    let current = this;
    do {
      let currentParams = Object.assign({}, current.params);
      if (current.config && current.config.hasChildRouter) {
        // remove the param for the injected child route segment
        delete currentParams[current.getWildCardName()];
      }

      ancestorParams.unshift(currentParams);
      current = current.parentInstruction;
    } while (current);

    let allParams = Object.assign({}, this.queryParams, ...ancestorParams);
    this.lifecycleArgs = [allParams, this.config, this];
  }

  /**
  * Gets an array containing this instruction and all child instructions for the current navigation.
  */
  getAllInstructions(): Array<NavigationInstruction> {
    let instructions = [this];
    for (let key in this.viewPortInstructions) {
      let childInstruction = this.viewPortInstructions[key].childNavigationInstruction;
      if (childInstruction) {
        instructions.push(...childInstruction.getAllInstructions());
      }
    }

    return instructions;
  }

  /**
  * Gets an array containing the instruction and all child instructions for the previous navigation.
  * Previous instructions are no longer available after navigation completes.
  */
  getAllPreviousInstructions(): Array<NavigationInstruction> {
    return this.getAllInstructions().map(c => c.previousInstruction).filter(c => c);
  }

  /**
  * Adds a viewPort instruction.
  */
  addViewPortInstruction(viewPortName: string, strategy: string, moduleId: string, component: any): any {
    let viewportInstruction = this.viewPortInstructions[viewPortName] = {
      name: viewPortName,
      strategy: strategy,
      moduleId: moduleId,
      component: component,
      childRouter: component.childRouter,
      lifecycleArgs: this.lifecycleArgs.slice()
    };

    return viewportInstruction;
  }

  /**
  * Gets the name of the route pattern's wildcard parameter, if applicable.
  */
  getWildCardName(): string {
    let wildcardIndex = this.config.route.lastIndexOf('*');
    return this.config.route.substr(wildcardIndex + 1);
  }

  /**
  * Gets the path and query string created by filling the route
  * pattern's wildcard parameter with the matching param.
  */
  getWildcardPath(): string {
    let wildcardName = this.getWildCardName();
    let path = this.params[wildcardName] || '';

    if (this.queryString) {
      path += '?' + this.queryString;
    }

    return path;
  }

  /**
  * Gets the instruction's base URL, accounting for wildcard route parameters.
  */
  getBaseUrl(): string {
    if (!this.params) {
      return this.fragment;
    }

    let wildcardName = this.getWildCardName();
    let path = this.params[wildcardName] || '';

    if (!path) {
      return this.fragment;
    }

    path = encodeURI(path);
    return this.fragment.substr(0, this.fragment.lastIndexOf(path));
  }

  _commitChanges(waitToSwap: boolean) {
    let router = this.router;
    router.currentInstruction = this;

    if (this.previousInstruction) {
      this.previousInstruction.config.navModel.isActive = false;
    }

    this.config.navModel.isActive = true;

    router._refreshBaseUrl();
    router.refreshNavigation();

    let loads = [];
    let delaySwaps = [];

    for (let viewPortName in this.viewPortInstructions) {
      let viewPortInstruction = this.viewPortInstructions[viewPortName];
      let viewPort = router.viewPorts[viewPortName];

      if (!viewPort) {
        throw new Error(`There was no router-view found in the view for ${viewPortInstruction.moduleId}.`);
      }

      if (viewPortInstruction.strategy === activationStrategy.replace) {
        if (waitToSwap) {
          delaySwaps.push({viewPort, viewPortInstruction});
        }

        loads.push(viewPort.process(viewPortInstruction, waitToSwap).then((x) => {
          if (viewPortInstruction.childNavigationInstruction) {
            return viewPortInstruction.childNavigationInstruction._commitChanges();
          }

          return undefined;
        }));
      } else {
        if (viewPortInstruction.childNavigationInstruction) {
          loads.push(viewPortInstruction.childNavigationInstruction._commitChanges(waitToSwap));
        }
      }
    }

    return Promise.all(loads).then(() => {
      delaySwaps.forEach(x => x.viewPort.swap(x.viewPortInstruction));
      return null;
    }).then(() => prune(this));
  }

  _updateTitle(): void {
    let title = this._buildTitle();
    if (title) {
      this.router.history.setTitle(title);
    }
  }

  _buildTitle(separator: string = ' | '): string {
    let title = this.config.navModel.title || '';
    let childTitles = [];

    for (let viewPortName in this.viewPortInstructions) {
      let viewPortInstruction = this.viewPortInstructions[viewPortName];

      if (viewPortInstruction.childNavigationInstruction) {
        let childTitle = viewPortInstruction.childNavigationInstruction._buildTitle(separator);
        if (childTitle) {
          childTitles.push(childTitle);
        }
      }
    }

    if (childTitles.length) {
      title = childTitles.join(separator) + (title ? separator : '') + title;
    }

    if (this.router.title) {
      title += (title ? separator : '') + this.router.title;
    }

    return title;
  }
}

function prune(instruction) {
  instruction.previousInstruction = null;
  instruction.plan = null;
}
<|endoftext|>


<commit_before>function getXY(obj) {
  return {
    x: obj.pageX,
    y: obj.pageY
  };
}

function touchDistance(touch1, touch2) {
  const dx = Math.abs(touch2.x - touch1.x);
  const dy = Math.abs(touch2.y - touch1.y);
  return Math.sqrt(dx*dx + dy*dy);
}

function getMidpoint(point1, point2) {
  return {
    x: (point1.x + point2.x) / 2,
    y: (point1.y + point2.y) / 2
  };
}

function getPoints(event) {
  if (event.touches) {
    return Array.from(event.touches).map(t => getXY(t));
  }
  else {
    return [getXY(event)];
  }
}

export default class PanZoom {
  constructor(target, {
    eventArea = target,
    shouldCaptureFunc = () => true
  }={}) {
    this._target = target;
    this._shouldCaptureFunc = shouldCaptureFunc;
    this._dx = 0;
    this._dy = 0;
    this._scale = 1;
    this._active = 0;
    this._lastPoints = [];

    // bind
    [
      '_onPointerDown',
      '_onPointerMove',
      '_onPointerUp'
    ].forEach(funcName => {
      this[funcName] = this[funcName].bind(this);
    });

    // bound events
    eventArea.addEventListener('mousedown', this._onPointerDown);
    eventArea.addEventListener('touchstart', this._onPointerDown);

    // unbonud
    eventArea.addEventListener('wheel', e => this._onWheel(e));
  }

  reset() {
    this._dx = 0;
    this._dy = 0;
    this._scale = 1;
    this._update();
  }

  _onWheel(event) {
    if (!this._shouldCaptureFunc(event.target)) return;
    event.preventDefault();

    const boundingRect = this._target.getBoundingClientRect();
    let delta = event.deltaY;

    if (event.deltaMode === 1) { // 1 is "lines", 0 is "pixels"
      // Firefox uses "lines" when mouse is connected
      delta *= 15;
    }

    // stop mouse wheel producing huge values
    delta = Math.max(Math.min(delta, 60), -60);

    const scaleDiff = (delta / 300) + 1;

    // avoid to-small values
    if (this._scale * scaleDiff < 0.05) return;

    this._scale *= scaleDiff;
    this._dx -= (event.pageX - boundingRect.left) * (scaleDiff - 1);
    this._dy -= (event.pageY - boundingRect.top) * (scaleDiff - 1);
    this._update();
  }

  _onFirstPointerDown() {
    document.addEventListener('mousemove', this._onPointerMove);
    document.addEventListener('mouseup', this._onPointerUp);
    document.addEventListener('touchmove', this._onPointerMove);
    document.addEventListener('touchend', this._onPointerUp);
  }

  _onPointerDown(event) {
    if (event.type == 'mousedown' && event.which != 1) return;
    if (!this._shouldCaptureFunc(event.target)) return;
    event.preventDefault();

    this._lastPoints = getPoints(event);
    this._active++;

    if (this._active === 1) {
      this._onFirstPointerDown();
    }
  }

  _onPointerMove(event) {
    event.preventDefault();
    const points = getPoints(event);
    const averagePoint = points.reduce(getMidpoint);
    const averageLastPoint = this._lastPoints.reduce(getMidpoint);
    const boundingRect = this._target.getBoundingClientRect();

    this._dx += averagePoint.x - averageLastPoint.x;
    this._dy += averagePoint.y - averageLastPoint.y;

    if (points[1]) {
      const scaleDiff = touchDistance(points[0], points[1]) / touchDistance(this._lastPoints[0], this._lastPoints[1]);
      this._scale *= scaleDiff;
      this._dx -= (averagePoint.x - boundingRect.left) * (scaleDiff - 1);
      this._dy -= (averagePoint.y - boundingRect.top) * (scaleDiff - 1);
    }

    this._update();
    this._lastPoints = points;
  }

  _update() {
    this._target.style.transform = `translate3d(${this._dx}px, ${this._dy}px, 0) scale(${this._scale})`;
  }

  _onPointerUp(event) {
    event.preventDefault();
    this._active--;
    this._lastPoints.pop();

    if (this._active) {
      this._lastPoints = getPoints(event);
      return;
    }

    document.removeEventListener('mousemove', this._onPointerMove);
    document.removeEventListener('mouseup', this._onPointerUp);
    document.removeEventListener('touchmove', this._onPointerMove);
    document.removeEventListener('touchend', this._onPointerUp);
  }
}
<commit_msg>pan-zoom: use `MouseEvent.button` instead of `event.which` (#270)<commit_after>function getXY(obj) {
  return {
    x: obj.pageX,
    y: obj.pageY
  };
}

function touchDistance(touch1, touch2) {
  const dx = Math.abs(touch2.x - touch1.x);
  const dy = Math.abs(touch2.y - touch1.y);
  return Math.sqrt(dx*dx + dy*dy);
}

function getMidpoint(point1, point2) {
  return {
    x: (point1.x + point2.x) / 2,
    y: (point1.y + point2.y) / 2
  };
}

function getPoints(event) {
  if (event.touches) {
    return Array.from(event.touches).map(t => getXY(t));
  }
  else {
    return [getXY(event)];
  }
}

export default class PanZoom {
  constructor(target, {
    eventArea = target,
    shouldCaptureFunc = () => true
  }={}) {
    this._target = target;
    this._shouldCaptureFunc = shouldCaptureFunc;
    this._dx = 0;
    this._dy = 0;
    this._scale = 1;
    this._active = 0;
    this._lastPoints = [];

    // bind
    [
      '_onPointerDown',
      '_onPointerMove',
      '_onPointerUp'
    ].forEach(funcName => {
      this[funcName] = this[funcName].bind(this);
    });

    // bound events
    eventArea.addEventListener('mousedown', this._onPointerDown);
    eventArea.addEventListener('touchstart', this._onPointerDown);

    // unbonud
    eventArea.addEventListener('wheel', e => this._onWheel(e));
  }

  reset() {
    this._dx = 0;
    this._dy = 0;
    this._scale = 1;
    this._update();
  }

  _onWheel(event) {
    if (!this._shouldCaptureFunc(event.target)) return;
    event.preventDefault();

    const boundingRect = this._target.getBoundingClientRect();
    let delta = event.deltaY;

    if (event.deltaMode === 1) { // 1 is "lines", 0 is "pixels"
      // Firefox uses "lines" when mouse is connected
      delta *= 15;
    }

    // stop mouse wheel producing huge values
    delta = Math.max(Math.min(delta, 60), -60);

    const scaleDiff = (delta / 300) + 1;

    // avoid to-small values
    if (this._scale * scaleDiff < 0.05) return;

    this._scale *= scaleDiff;
    this._dx -= (event.pageX - boundingRect.left) * (scaleDiff - 1);
    this._dy -= (event.pageY - boundingRect.top) * (scaleDiff - 1);
    this._update();
  }

  _onFirstPointerDown() {
    document.addEventListener('mousemove', this._onPointerMove);
    document.addEventListener('mouseup', this._onPointerUp);
    document.addEventListener('touchmove', this._onPointerMove);
    document.addEventListener('touchend', this._onPointerUp);
  }

  _onPointerDown(event) {
    if (event.type == 'mousedown' && event.button !== 0) return;
    if (!this._shouldCaptureFunc(event.target)) return;
    event.preventDefault();

    this._lastPoints = getPoints(event);
    this._active++;

    if (this._active === 1) {
      this._onFirstPointerDown();
    }
  }

  _onPointerMove(event) {
    event.preventDefault();
    const points = getPoints(event);
    const averagePoint = points.reduce(getMidpoint);
    const averageLastPoint = this._lastPoints.reduce(getMidpoint);
    const boundingRect = this._target.getBoundingClientRect();

    this._dx += averagePoint.x - averageLastPoint.x;
    this._dy += averagePoint.y - averageLastPoint.y;

    if (points[1]) {
      const scaleDiff = touchDistance(points[0], points[1]) / touchDistance(this._lastPoints[0], this._lastPoints[1]);
      this._scale *= scaleDiff;
      this._dx -= (averagePoint.x - boundingRect.left) * (scaleDiff - 1);
      this._dy -= (averagePoint.y - boundingRect.top) * (scaleDiff - 1);
    }

    this._update();
    this._lastPoints = points;
  }

  _update() {
    this._target.style.transform = `translate3d(${this._dx}px, ${this._dy}px, 0) scale(${this._scale})`;
  }

  _onPointerUp(event) {
    event.preventDefault();
    this._active--;
    this._lastPoints.pop();

    if (this._active) {
      this._lastPoints = getPoints(event);
      return;
    }

    document.removeEventListener('mousemove', this._onPointerMove);
    document.removeEventListener('mouseup', this._onPointerUp);
    document.removeEventListener('touchmove', this._onPointerMove);
    document.removeEventListener('touchend', this._onPointerUp);
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name SwellRTService.service:swellRT
 * @description
 * Interface service with SwellRT API
 */
angular.module('SwellRTService',[])
  .factory('swellRT', ['$rootScope', '$q', function($rootScope, $q){

    function diff(a, b) {
      return a.filter(function(i) {return b.indexOf(i) < 0;});
    }

    var def = $q.defer();
    var session = def.promise;
    var currentWaveId = null;
    var currentModel = {model: {}};

    var ret = {
      open: openModel,
      close: closeModel,
      create: create,
      model: currentModel,
      m2: currentModel.model,
      copy: {}
    };

    var apply = function (fun) {
      var p = $rootScope.$$phase;
      if (p !== '$digest' && p !== '$apply') {
        $rootScope.$apply(fun);
      }
    };
    function init(){
      window.SwellRT.startSession(
        window.swellrtConfig.server,
        window.swellrtConfig.user,
        window.swellrtConfig.pass,
        function () {
          apply(function() {
            def.resolve(window.SwellRT);
          });
        },
        function () {
           def.reject('Error conecting to wavejs server: Try again later');
         });
    }
    if (window.SwellRT) {
      init();
    }
    window.onSwellRTReady = function () {
     init();
    };

    function openModel(waveId){
      var deferred = $q.defer();
      deferred.notify('Opening ' + waveId + ' model.');
      session.then(function(api) {
        api
          .openModel(waveId,
                     function (model) {
                       apply(function() {
                         currentWaveId = waveId;
                         currentModel.model = model;
                         ret.model = model.root;
                         ret.mod = model;
                         simplify(model.root, ret.copy, []);
                         deferred.resolve(model);
                       });
                     },
                     function(error){
                       console.log(error);
                       apply(function() {
                         deferred.reject(error);
                         currentWaveId = null;
                         currentModel = {};
                       });
                     }
                    );
      });
      return deferred.promise;
    }

    function closeModel(waveId){
      session.then(function(api) {
        api.closeModel(waveId);
        currentWaveId = null;
      });
    }

    function create(){
      session.then(function(api) {
        var deferred = $q.defer();
        api.createModel(
          function(modelId) {
            apply(function() {
              deferred.resolve(modelId);
            });
            currentWaveId = modelId;
          },
          function(error) {
            apply(function() {
              deferred.reject(error);
              });
          });
        return deferred.promise;
      });
    }

    // Creates and attach (if not attached) an object made from maps, arrays and strings
    function createAttachObject(obj, key, value) {

      // Create
      var o;
      try {
        o = obj.get(key);
      } catch (e) {
      }
      var isNew = !o;
      if (typeof value === 'string'){
        if (isNew){
          o = currentModel.model.createString(value);
        } else {
          o.setValue(value);
        }
      } else if (value instanceof Array){
        if (isNew){
          o = currentModel.model.createList();
        }
      } else if (value instanceof Object){
        if (isNew){
          o = currentModel.model.createMap();
        }
      }
      // Attach
      var className = obj._delegate.___clazz$.simpleName;
      if (className === 'ListType'){
        try{
          obj.add(o);
          }
        catch (e){
        }
      } else if (className === 'MapType'){
        try{
          obj.put(key, o);
        }
        catch (e){
        }
      }
      if (typeof value !== 'string'){
        angular.forEach(value, function(val, key){
          try{
            createAttachObject(o, key, val);
            }
          catch (e) {
            console.log(e);
          }
        });
      }
    }

    function setPathValue(obj, path, value){
      return path.reduce(
        function(object,key){
          return function(v){
            if (v) {
              object()[key] = v;
            }
            return object()[key];
          };
        },
        function(){
          return obj;
        })(value);
    }

    function simplify(e, mod, path){
      var className = e._delegate.___clazz$.simpleName;
      switch (className) {

        case 'StringType':

          e.registerEventHandler(SwellRT.events.ITEM_CHANGED,
                                 function(newStr) {
                                   setPathValue(ret.copy,path,newStr);
                                   apply();
                                 },
                                 function(error) {
                                   console.log(error);
                                 }
          );
          $rootScope.$watch(
            function(){
              var r = path.reduce(function(object, key){return object[key];}, mod);
              return r;
            },
            function (newValue){
              if (typeof newValue === 'string'){
                path.reduce(function(object,key){return object.get(key);}, ret.model).setValue(newValue);
              }
            },
            true);
          setPathValue(mod, path, e.getValue());
          break;

        case 'MapType':

          setPathValue(mod, path, {});
          e.registerEventHandler(SwellRT.events.ITEM_ADDED,
                                 function(item) {
                                   var p = (path || []).slice();
                                   p.push(item[0]);
                                   try {
                                     simplify(item[1], mod, p);
                                   }
                                   catch (e) {
                                     console.log(e);
                                   }
                                   apply();
                                 },
                                 function(error) {
                                   console.log(error);
                                 });
          e.registerEventHandler(SwellRT.events.ITEM_REMOVED,
                                 function(item) {
                                   var p = (path || []).slice();
                                   delete p.reduce(function(object, key){return object[key];}, mod)[item[0]];
                                   apply();
                                 },
                                 function(error) {
                                   console.log(error);
                                 });
          var keys = e.keySet();
          angular.forEach(keys,function(value){
              var el = e.get(value);
              var p = (path || []).slice();
              p.push(value);
              simplify(el, mod, p);
          });
          $rootScope.$watchCollection(
            function(){
              var r = path.reduce(function(object,key){return object[key];} , mod);
              return r;
            },
            function(newValue, oldValue){
              // AngularJS introduce $$haskKey property to some objects
              var oldKeys = Object.keys(oldValue);
              oldKeys.push('$$hashKey');
              var newVals = diff(Object.keys(newValue),oldKeys);
              angular.forEach(newVals, function(value){
                var m = path.reduce(function(object,k){return object.get(k);}, ret.model);
                createAttachObject(m, value, newValue[value]);
                apply();
              });
              var deletedVars = diff(Object.keys(oldValue), Object.keys(newValue));
              angular.forEach(deletedVars, function(value){
                e.remove(value);
                apply();
              });
          });
          break;

        case 'ListType':

          setPathValue(mod, path, []);
          e.registerEventHandler(SwellRT.events.ITEM_ADDED,
                                  function(item) {
                                    var par = path.reduce(function(object,key){return object[key];},mod);
                                    var ext = path.reduce(function(object,key){return object.get(key);},ret.model);
                                    //var p = path.concat([par.length]);
                                    var p = (path || []).slice();
                                    p.push('' + (par.length || '0'));
                                    // TODO check for possible failure due to paralel additions
                                    // if it is not a item I added
                                    if (ext.size() > par.length){
                                      try{
                                        simplify(item, mod, p);
                                      } catch (e) {
                                        console.log(e);
                                      }
                                    }
                                    apply();
                                  });
        //TODO: check why is not needed!
        // e.registerEventHandler(SwellRT.events.ITEM_REMOVED,
        //                        function(item) {
                                   // function copy(v1){
                                   //   className = v1._delegate.___clazz$.simpleName;
                                   //   var r;
                                   //   if (className === 'StringType'){
                                   //     r = v1.getValue();
                                   //   }

                                   //   if (className === 'ListType'){
                                   //     r = [];
                                   //     for (var i = 0; i < v1.size(); i++){
                                   //       r.push(copy(v1.get(i)));
                                   //     }
                                   //   }
                                   //   if (className === 'MapType'){
                                   //     r = {};
                                   //     angular.forEach(v1.keySet(), function(value, key){
                                   //       r[value] = copy(v1.get(value));
                                   //     });
                                   //   }
                                   //   return r;
                                   // }
                                   // var cp = copy(foo);
                                   // var par = path.reduce(function(object, key){return object[key]}, mod);
                                   // // TODO if cp in par, delete it
                                   // //
                                   // apply();
                                 // },
                                 // function(error) {
                                 //   console.log(error);
                                 // });

          var keyNum = e.size();
          for(var i = 0; i < keyNum; i++){
            var p = (path || []).slice();
            p.push('' + i);
            simplify(e.get(i), mod, p);
          }

           $rootScope.$watchCollection(
             function(){
               // TODO change ret.copy by mod?
               var r = path.reduce(function(object,key){return object[key];} ,ret.copy);
               return r;
             },
             function(newValue, oldValue){
               var newVals = diff(Object.keys(newValue), Object.keys(oldValue));
               angular.forEach(newVals, function(value){
                 var m = path.reduce(function(object,k){return object.get(k);}, ret.model);
                 createAttachObject(m, ''+value, newValue[value]);
                 apply();
               });
               var deletedVars = diff(Object.keys(oldValue), Object.keys(newValue));
               angular.forEach(deletedVars, function(value){
                 e.remove(value);
                 apply();
               });
           });

          break;
      }
    }
    return ret;
  }]);
<commit_msg>swellRT-angular service: lists working<commit_after>'use strict';

/**
 * @ngdoc function
 * @name SwellRTService.service:swellRT
 * @description
 * Interface service with SwellRT API
 */
angular.module('SwellRTService',[])
  .factory('swellRT', ['$rootScope', '$q', function($rootScope, $q){

    function diff(a, b) {
      return a.filter(function(i) {return b.indexOf(i) < 0;});
    }

    var def = $q.defer();
    var session = def.promise;
    var currentWaveId = null;
    var currentModel = {model: {}};

    var ret = {
      open: openModel,
      close: closeModel,
      create: create,
      model: currentModel,
      m2: currentModel.model,
      copy: {}
    };

    var apply = function (fun) {
      var p = $rootScope.$$phase;
      if (p !== '$digest' && p !== '$apply') {
        $rootScope.$apply(fun);
      }
    };
    function init(){
      window.SwellRT.startSession(
        window.swellrtConfig.server,
        window.swellrtConfig.user,
        window.swellrtConfig.pass,
        function () {
          apply(function() {
            def.resolve(window.SwellRT);
          });
        },
        function () {
           def.reject('Error conecting to wavejs server: Try again later');
         });
    }
    if ( window.SwellRT) {
      init();
    }
    window.onSwellRTReady = function () {
     init();
    };

    function openModel(waveId){
      var deferred = $q.defer();
      deferred.notify('Opening ' + waveId + ' model.');
      session.then(function(api) {
        api
          .openModel(waveId,
                     function (model) {
                       apply(function() {
                         currentWaveId = waveId;
                         currentModel.model = model;
                         ret.model = model.root;
                         ret.mod = model;
                         simplify(model.root, ret.copy, []);
                         deferred.resolve(model);
                       });
                     },
                     function(error){
                       console.log(error);
                       apply(function() {
                         deferred.reject(error);
                         currentWaveId = null;
                         currentModel = {};
                       });
                     }
                    );
      });
      return deferred.promise;
    }

    function closeModel(waveId){
      session.then(function(api) {
        api.closeModel(waveId);
        currentWaveId = null;
      });
    }

    function create(){
      session.then(function(api) {
        var deferred = $q.defer();
        api.createModel(
          function(modelId) {
            apply(function() {
              deferred.resolve(modelId);
            });
            currentWaveId = modelId;
          },
          function(error) {
            apply(function() {
              deferred.reject(error);
              });
          });
        return deferred.promise;
      });
    }

    // Creates and attach (if not attached) an object made from maps, arrays and strings
    function createAttachObject(obj, key, value) {

      // Create
      var o;
      try {
        o = obj.get(key);
      } catch (e) {
      }
      var isNew = !o;
      if (typeof value === 'string'){
        if (isNew){
          o = currentModel.model.createString(value);
        } else {
          o.setValue(value);
        }
      } else if (value instanceof Array){
        if (isNew){
          o = currentModel.model.createList();
        }
      } else if (value instanceof Object){
        if (isNew){
          o = currentModel.model.createMap();
        }
      }
      // Attach
      var className = obj._delegate.___clazz$.simpleName;
      if (className === 'ListType'){
        try{
          obj.add(o);
          }
        catch (e){
        }
      } else if (className === 'MapType'){
        try{
          obj.put(key, o);
        }
        catch (e){
        }
      }
      if (typeof value !== 'string'){
        angular.forEach(value, function(val, key){
          try{
            createAttachObject(o, key, val);
            }
          catch (e) {
            console.log(e);
          }
        });
      }
    }

    function setPathValue(obj, path, value){
      return path.reduce(
        function(object,key){
          return function(v){
            if (v) {
              object()[key] = v;
            }
            return object()[key];
          };
        },
        function(){
          return obj;
        })(value);
    }

    function simplify(e, mod, path){
      var className = e._delegate.___clazz$.simpleName;
      switch (className) {

        case 'StringType':

          e.registerEventHandler(SwellRT.events.ITEM_CHANGED,
                                 function(newStr) {
                                   setPathValue(ret.copy,path,newStr);
                                   apply();
                                 },
                                 function(error) {
                                   console.log(error);
                                 }
          );
          $rootScope.$watch(
            function(){
              var r = path.reduce(function(object, key){return object[key];}, mod);
              return r;
            },
            function (newValue){
              if (typeof newValue === 'string'){
                path.reduce(function(object,key){return object.get(key);}, ret.model).setValue(newValue);
              }
            },
            true);
          setPathValue(mod, path, e.getValue());
          break;

        case 'MapType':

          setPathValue(mod, path, {});
          e.registerEventHandler(SwellRT.events.ITEM_ADDED,
                                 function(item) {
                                   var p = (path || []).slice();
                                   p.push(item[0]);
                                   try {
                                     simplify(item[1], mod, p);
                                   }
                                   catch (e) {
                                     console.log(e);
                                   }
                                   apply();
                                 },
                                 function(error) {
                                   console.log(error);
                                 });
          e.registerEventHandler(SwellRT.events.ITEM_REMOVED,
                                 function(item) {
                                   var p = (path || []).slice();
                                   delete p.reduce(function(object, key){return object[key];}, mod)[item[0]];
                                   apply();
                                 },
                                 function(error) {
                                   console.log(error);
                                 });
          var keys = e.keySet();
          angular.forEach(keys,function(value){
              var el = e.get(value);
              var p = (path || []).slice();
              p.push(value);
              simplify(el, mod, p);
          });
          $rootScope.$watchCollection(
            function(){
              var r = path.reduce(function(object,key){return object[key];} , mod);
              return r;
            },
            function(newValue, oldValue){
              // AngularJS introduce $$haskKey property to some objects
              var oldKeys = Object.keys(oldValue);
              oldKeys.push('$$hashKey');
              var newVals = diff(Object.keys(newValue),oldKeys);
              angular.forEach(newVals, function(value){
                var m = path.reduce(function(object,k){return object.get(k);}, ret.model);
                createAttachObject(m, value, newValue[value]);
                apply();
              });
              var deletedVars = diff(Object.keys(oldValue), Object.keys(newValue));
              angular.forEach(deletedVars, function(value){
                e.remove(value);
                apply();
              });
          });
          break;

        case 'ListType':

          setPathValue(mod, path, []);
          e.registerEventHandler(SwellRT.events.ITEM_ADDED,
                                  function(item) {
                                    var par = path.reduce(function(object,key){return object[key];},mod);
                                    var ext = path.reduce(function(object,key){return object.get(key);},ret.model);
                                    //var p = path.concat([par.length]);
                                    var p = (path || []).slice();
                                    p.push('' + (par.length || '0'));
                                    // TODO check for possible failure due to paralel additions
                                    // if it is not a item I added
                                    if (ext.size() > par.length){
                                      try{
                                        simplify(item, mod, p);
                                      } catch (e) {
                                        console.log(e);
                                      }
                                    }
                                    apply();
                                  });
        //TODO: check why is not needed!
        // e.registerEventHandler(SwellRT.events.ITEM_REMOVED,
        //                        function(item) {
                                   // function copy(v1){
                                   //   className = v1._delegate.___clazz$.simpleName;
                                   //   var r;
                                   //   if (className === 'StringType'){
                                   //     r = v1.getValue();
                                   //   }

                                   //   if (className === 'ListType'){
                                   //     r = [];
                                   //     for (var i = 0; i < v1.size(); i++){
                                   //       r.push(copy(v1.get(i)));
                                   //     }
                                   //   }
                                   //   if (className === 'MapType'){
                                   //     r = {};
                                   //     angular.forEach(v1.keySet(), function(value, key){
                                   //       r[value] = copy(v1.get(value));
                                   //     });
                                   //   }
                                   //   return r;
                                   // }
                                   // var cp = copy(foo);
                                   // var par = path.reduce(function(object, key){return object[key]}, mod);
                                   // // TODO if cp in par, delete it
                                   // //
                                   // apply();
                                 // },
                                 // function(error) {
                                 //   console.log(error);
                                 // });

          var keyNum = e.size();
          for(var i = 0; i < keyNum; i++){
            var p = (path || []).slice();
            p.push('' + i);
            simplify(e.get(i), mod, p);
          }

           $rootScope.$watchCollection(
             function(){
               // TODO change ret.copy by mod?
               var r = path.reduce(function(object,key){return object[key];} ,ret.copy);
               return r;
             },
             function(newValue, oldValue){
               var newVals = diff(Object.keys(newValue), Object.keys(oldValue));
               angular.forEach(newVals, function(value){
                 var m = path.reduce(function(object,k){return object.get(k);}, ret.model);
                 createAttachObject(m, ''+value, newValue[value]);
                 apply();
               });
               var deletedVars = diff(Object.keys(oldValue), Object.keys(newValue));
               angular.forEach(deletedVars, function(value){
                 e.remove(value);
                 apply();
               });
           });

          break;
      }
    }
    return ret;
  }]);
<|endoftext|>


<commit_before>var addCriterium = function ()
{
    var criterium = $("#criterium").val()
    if (criterium !== null)
    {
        criteria.push(criterium)
        updateCriteria()
    }
}

var addTeam = function ()
{
    var team = $("#new-team").val()
    if (team !== "" && teams.indexOf(team) === -1)
    {
        teams.push(team)
        updateTeams()
    }
    $("#new-team").val("")
}

var deleteCriterium = function (event)
{
    var criterium = parseInt($(event.target).attr("data-criterium"))
    criteria.splice(criterium, 1)
    updateCriteria()
}

var deleteTeam = function (event)
{
    var team = parseInt($(event.target).attr("data-team"))
    teams.splice(team, 1)
    updateTeams()
}

var updateCriteria = function ()
{
    $("#criteria").empty()
    table = $("

").appendTo("#criteria")
    for (var i = 0; i < criteria.length; i++)
    {
        var criterium = criteria[i]
        var tr = $("

").appendTo(table)
        $("" + criteriumNames[criterium] + "	").appendTo(tr)
        $("<input class=\"delete-criterium\" data-criterium=\"" + i + "\" type=\"button\" value=\"Löschen\"/>	").appendTo(tr)
    }
    $(".delete-criterium").click(deleteCriterium)
    $("<select id=\"criterium\"></select>").appendTo("#criteria")
    for (var i = 0; i < allCriteria.length; i++)
    {
        var criterium = allCriteria[i]
        if (criteria.indexOf(criterium) === -1)
        {
            $("<option value=\"" + criterium + "\">" + criteriumNames[criterium] + "</option>").appendTo("#criterium")
        }
    }
    $("<input id=\"add-criterium\" type=\"button\" value=\"Kriterium hinzufügen\" />").appendTo("#criteria")
    $("#add-criterium").click(addCriterium)
}

var updateMatches = function ()
{
    $("#matches").empty()
    for (var i = 0; i < matches.length; i++)
    {
        $("
" + (i + 1) + ". Spieltag
").appendTo("#matches")
        var table = $("

").appendTo("#matches")
        for (var j = 0; j < matches[i].length; j++)
        {
            var match = matches[i][j]
            var tr = $("

").appendTo(table)
            $("" + match.homeTeam + "	").appendTo(tr)
            $("-	").appendTo(tr)
            $("" + match.awayTeam + "	").appendTo(tr)
            var homeGoals = $("<input class=\"update-goals\" data-match=\"" + j + "\" data-matchday=\"" + i + "\" data-side=\"homeGoals\" min=\"0\" type=\"number\" />	").appendTo(tr)
            if (match.homeGoals !== undefined)
            {
                $(homeGoals).val(match.homeGoals)
            }
            $(":	").appendTo(tr)
            var awayGoals = $("<input class=\"update-goals\" data-match=\"" + j + "\" data-matchday=\"" + i + "\" data-side=\"awayGoals\" min=\"0\" type=\"number\" />	").appendTo(tr)
            if (match.awayGoals !== undefined)
            {
                $(awayGoals).val(match.awayGoals)
            }
        }
    }
}

var updateRounds = function ()
{
    rounds = parseInt($("#rounds").val())
}

var updateTeams = function ()
{
    $("#teams").empty()
    for (var i = 0; i < teams.length; i++)
    {
        var team = teams[i]
        $("
" + team + "	<input data-team=\"" + i + "\" class=\"delete-team\" type=\"button\" value=\"Löschen\" />
").appendTo("#teams")
    }
    $(".delete-team").click(deleteTeam)
}

$(document).ready
(
    function ()
    {
        updateRounds()
        $("#rounds").change(updateRounds)
        $("#add-team").click(addTeam)
        updateCriteria()
        $("#generate-matches").click
        (
            function ()
            {
                generateMatches()
                updateMatches()
            }
        )
    }
)
<commit_msg>Kriterien verschieben<commit_after>var addCriterium = function ()
{
    var criterium = $("#criterium").val()
    if (criterium !== null)
    {
        criteria.push(criterium)
        updateCriteria()
    }
}

var addTeam = function ()
{
    var team = $("#new-team").val()
    if (team !== "" && teams.indexOf(team) === -1)
    {
        teams.push(team)
        updateTeams()
    }
    $("#new-team").val("")
}

var deleteCriterium = function (event)
{
    var criterium = parseInt($(event.target).attr("data-criterium"))
    criteria.splice(criterium, 1)
    updateCriteria()
}

var deleteTeam = function (event)
{
    var team = parseInt($(event.target).attr("data-team"))
    teams.splice(team, 1)
    updateTeams()
}

var moveCriteriumDown = function (event)
{
    var criterium = parseInt($(event.target).attr("data-criterium"))
    var temp = criteria[criterium]
    criteria[criterium] = criteria[criterium + 1]
    criteria[criterium + 1] = temp
    updateCriteria()
}

var moveCriteriumUp = function (event)
{
    var criterium = parseInt($(event.target).attr("data-criterium"))
    var temp = criteria[criterium]
    criteria[criterium] = criteria[criterium - 1]
    criteria[criterium - 1] = temp
    updateCriteria()
}

var updateCriteria = function ()
{
    $("#criteria").empty()
    table = $("

").appendTo("#criteria")
    for (var i = 0; i < criteria.length; i++)
    {
        var criterium = criteria[i]
        var tr = $("

").appendTo(table)
        $("" + criteriumNames[criterium] + "	").appendTo(tr)
        if (i !== 0)
        {
            $("<input class=\"move-criterium-up\" data-criterium=\"" + i + "\" type=\"button\" value=\"↑\"/>	").appendTo(tr)
        }
        else
        {
            $("	").appendTo(tr)
        }
        if (i !== criteria.length - 1)
        {
            $("<input class=\"move-criterium-down\" data-criterium=\"" + i + "\" type=\"button\" value=\"↓\"/>	").appendTo(tr)
        }
        else
        {
            $("	").appendTo(tr)
        }
        $("<input class=\"delete-criterium\" data-criterium=\"" + i + "\" type=\"button\" value=\"Löschen\"/>	").appendTo(tr)
    }
    $(".move-criterium-up").click(moveCriteriumUp)
    $(".move-criterium-down").click(moveCriteriumDown)
    $(".delete-criterium").click(deleteCriterium)
    $("<select id=\"criterium\"></select>").appendTo("#criteria")
    for (var i = 0; i < allCriteria.length; i++)
    {
        var criterium = allCriteria[i]
        if (criteria.indexOf(criterium) === -1)
        {
            $("<option value=\"" + criterium + "\">" + criteriumNames[criterium] + "</option>").appendTo("#criterium")
        }
    }
    $("<input id=\"add-criterium\" type=\"button\" value=\"Kriterium hinzufügen\" />").appendTo("#criteria")
    $("#add-criterium").click(addCriterium)
}

var updateMatches = function ()
{
    $("#matches").empty()
    for (var i = 0; i < matches.length; i++)
    {
        $("
" + (i + 1) + ". Spieltag
").appendTo("#matches")
        var table = $("

").appendTo("#matches")
        for (var j = 0; j < matches[i].length; j++)
        {
            var match = matches[i][j]
            var tr = $("

").appendTo(table)
            $("" + match.homeTeam + "	").appendTo(tr)
            $("-	").appendTo(tr)
            $("" + match.awayTeam + "	").appendTo(tr)
            var homeGoals = $("<input class=\"update-goals\" data-match=\"" + j + "\" data-matchday=\"" + i + "\" data-side=\"homeGoals\" min=\"0\" type=\"number\" />	").appendTo(tr)
            if (match.homeGoals !== undefined)
            {
                $(homeGoals).val(match.homeGoals)
            }
            $(":	").appendTo(tr)
            var awayGoals = $("<input class=\"update-goals\" data-match=\"" + j + "\" data-matchday=\"" + i + "\" data-side=\"awayGoals\" min=\"0\" type=\"number\" />	").appendTo(tr)
            if (match.awayGoals !== undefined)
            {
                $(awayGoals).val(match.awayGoals)
            }
        }
    }
}

var updateRounds = function ()
{
    rounds = parseInt($("#rounds").val())
}

var updateTeams = function ()
{
    $("#teams").empty()
    for (var i = 0; i < teams.length; i++)
    {
        var team = teams[i]
        $("
" + team + "	<input data-team=\"" + i + "\" class=\"delete-team\" type=\"button\" value=\"Löschen\" />
").appendTo("#teams")
    }
    $(".delete-team").click(deleteTeam)
}

$(document).ready
(
    function ()
    {
        updateRounds()
        $("#rounds").change(updateRounds)
        $("#add-team").click(addTeam)
        updateCriteria()
        $("#generate-matches").click
        (
            function ()
            {
                generateMatches()
                updateMatches()
            }
        )
    }
)
<|endoftext|>


<commit_before>$(document).ready(function(){
  var game = new Game();
  var scoreboard = new Scoreboard();
  $('#frameCount').text(game.frameCount);

  $(function () {
  $('#rackUp').click(function(){
    game.rackUp();
    $('#firstRoll').show();
    $('#secondRoll').show();
    if ($(this.rackedPins).val() == false) {
                $('.roll1').prop('disabled', true);
            } else {
                $('.roll1').prop('disabled', false);
            }
        });
  });

  $('#firstRoll').click(function(){
    $(this).hide();
    $('#pinSweep').show();
  $('#firstScore').text(scoreboard.scoreFirstRoll(game.firstRoll()))
  });

  // $(function () {
  // $('#pinSweep').click(function(){
  //   $(this).hide();
  //   game.pinSweep();
  //   if ($(this.sweep).val() == false) {
  //               $('.roll2').prop('disabled', true);
  //           } else {
  //               $('.roll2').prop('disabled', false);
  //           }
  //       });
  // });

  $('#secondRoll').click(function(){
    // $(this).hide();
  $('#secondScore').text(scoreboard.scoreSecondRoll(game.secondRoll()));
  // updateCurrentScore();
  });

  // $('#restart').click(function(){
  //   game.newGame();
  // });

  function updateCurrentScore() {
    $('#currentTotalScore').text(game.currentRoundScore());
    $('#runningTotal').text(game.runningTotal());
  };

});
<commit_msg>frame count on client side<commit_after>$(document).ready(function(){
  var game = new Game();
  var scoreboard = new Scoreboard();
  $('#frameCount').text(game.frameCount);

  $(function () {
  $('#rackUp').click(function(){
    game.rackUp();
    updateCurrentScore();
    $('#firstRoll').show();
    $('#secondRoll').show();
    if ($(this.rackedPins).val() == false) {
                $('.roll1').prop('disabled', true);
            } else {
                $('.roll1').prop('disabled', false);
            }
        });
  });

  $('#firstRoll').click(function(){
    $(this).hide();
    $('#pinSweep').show();
  $('#firstScore').text(scoreboard.scoreFirstRoll(game.firstRoll()))
  });

  // $(function () {
  // $('#pinSweep').click(function(){
  //   $(this).hide();
  //   game.pinSweep();
  //   if ($(this.sweep).val() == false) {
  //               $('.roll2').prop('disabled', true);
  //           } else {
  //               $('.roll2').prop('disabled', false);
  //           }
  //       });
  // });

  $('#secondRoll').click(function(){
    // $(this).hide();
  $('#secondScore').text(scoreboard.scoreSecondRoll(game.secondRoll()));
  });

  // $('#restart').click(function(){
  //   game.newGame();
  // });

  function updateCurrentScore() {
    $('#frameCount').text(game.frameCount);
    // $('#currentTotalScore').text(game.currentRoundScore());
    // $('#runningTotal').text(game.runningTotal());
  };

});
<|endoftext|>