<commit_before>'use strict';

/**
 * Module for all communication with LB
 */
define((require) => {
	const $ = require('jquery');
	const Util = require('util');
	const BaseScrobbler = require('scrobbler/base');
	const ServiceCallResult = require('object/service-call-result');

	const listenBrainzTokenPage = 'https://listenbrainz.org/profile/';

	class ListenBrainz extends BaseScrobbler {
		/** @override */
		async getAuthUrl() {
			let data = await this.storage.get();

			data.isAuthStarted = true;
			delete data.sessionID;
			delete data.sessionName;
			await this.storage.set(data);

			this.debugLog(`Auth url: ${this.authUrl}`);

			return this.authUrl;
		}

		/** @override */
		async getSession() {
			let data = await this.storage.get();
			if (data.isAuthStarted) {
				let session = {};

				try {
					session = await this.requestSession();
				} catch (err) {
					this.debugLog('Failed to get session', 'warn');

					await this.signOut();
					throw new ServiceCallResult(ServiceCallResult.ERROR_AUTH);
				}

				data.sessionID = session.sessionID;
				data.sessionName = session.sessionName;
				delete data.isAuthStarted;
				await this.storage.set(data);

				return session;
			} else if (!data.sessionID) {
				throw new ServiceCallResult(ServiceCallResult.ERROR_AUTH);
			}

			return {
				sessionID: data.sessionID,
				sessionName: data.sessionName
			};
		}

		/** @override */
		async isReadyForGrantAccess() {
			let data = await this.storage.get();
			return data.isAuthStarted;
		}

		/** @override */
		async sendNowPlaying(song) {
			let { sessionID } = await this.getSession();
			let track_meta = {
				'artist_name': song.getArtist(),
				'track_name': song.getTrack(),
			};

			if (song.getAlbum()) {
				track_meta['release_name'] = song.getAlbum();
			}

			if (song.getOriginUrl()) {
				track_meta['additional_info'] = {
					'origin_url': song.getOriginUrl()
				};
			}

			let params = {
				'listen_type': 'playing_now',
				'payload': [
					{
						'track_metadata': track_meta
					}
				]
			};

			return this.sendRequest(params, sessionID);
		}

		/** @override */
		async scrobble(song) {
			let { sessionID } = await this.getSession();

			let track_meta = {
				'artist_name': song.getArtist(),
				'track_name': song.getTrack(),
			};
			if (song.getAlbum()) {
				track_meta['release_name'] = song.getAlbum();
			}
			let params = {
				'listen_type': 'single',
				'payload': [
					{
						'listened_at': song.metadata.startTimestamp,
						'track_metadata': track_meta
					}
				]
			};
			return this.sendRequest(params, sessionID);
		}

		sendRequest(params, sessionID) {
			let requestInfo = {
				method: 'POST',
				headers: {
					'Authorization': `Token ${sessionID}`,
					'Content-Type': 'application/json; charset=UTF-8'
				},
				body: JSON.stringify(params)
			};

			let promise = fetch(this.apiUrl, requestInfo).then((response) => {
				switch (response.status) {
					case 400:
						this.debugLog('Invalid JSON sent to ListenBrainz', 'error');
						throw new ServiceCallResult(ServiceCallResult.IGNORED);
					case 401:
						this.debugLog('Invalid Authorization sent to ListenBrainz', 'error');
						throw new ServiceCallResult(ServiceCallResult.IGNORED);
				}

				return response.text();
			}).then((text) => {
				this.debugLog(text, 'log');
				return new ServiceCallResult(ServiceCallResult.OK);
			}).catch((error) => {
				this.debugLog(error.text(), 'warn');
				throw new ServiceCallResult(ServiceCallResult.ERROR_OTHER);
			});

			let timeout = BaseScrobbler.REQUEST_TIMEOUT;
			return Util.timeoutPromise(timeout, promise).catch(() => {
				this.debugLog('TIMED OUT', 'warn');
				throw new ServiceCallResult(ServiceCallResult.ERROR_OTHER);
			});
		}

		async requestSession() {
			let authUrls = [
				listenBrainzTokenPage,
				this.authUrl,
			];

			let session = null;

			for (let url of authUrls) {
				try {
					session = await this.fetchSession(url);
				} catch (e) {
					this.debugLog('request session timeout', 'warn');
					continue;
				}

				if (session) {
					break;
				}
			}

			if (session) {
				let safeId = Util.hideString(session.sessionID);
				this.debugLog(`Session ID: ${safeId}`, 'log');

				return session;
			}

			throw new ServiceCallResult(ServiceCallResult.ERROR_AUTH);
		}

		async fetchSession(url) {
			this.debugLog(`Use ${url}`);
			let promise = fetch(url, { method: 'GET' });
			let timeout = BaseScrobbler.REQUEST_TIMEOUT;

			let response = await Util.timeoutPromise(timeout, promise);
			let $doc = $(await response.text());

			let sessionName = $doc.find('.page-title').text();
			let sessionID = $doc.find('#auth-token').val();

			if (sessionID && sessionName) {
				return { sessionID, sessionName };
			}

			return null;
		}
	}

	return new ListenBrainz({
		label: 'ListenBrainz',
		storage: 'ListenBrainz',
		apiUrl: 'https://api.listenbrainz.org/1/submit-listens',
		authUrl: 'https://listenbrainz.org/login/musicbrainz?next=%2Fprofile%2F',
		statusUrl: 'https://listenbrainz.org/current-status',
		profileUrl: 'https://listenbrainz.org/user/',
	});
});
<commit_msg>Fix login with ListenBrainz<commit_after>'use strict';

/**
 * Module for all communication with LB
 */
define((require) => {
	const $ = require('jquery');
	const Util = require('util');
	const BaseScrobbler = require('scrobbler/base');
	const ServiceCallResult = require('object/service-call-result');

	const listenBrainzTokenPage = 'https://listenbrainz.org/profile/';

	class ListenBrainz extends BaseScrobbler {
		/** @override */
		async getAuthUrl() {
			let data = await this.storage.get();

			data.isAuthStarted = true;
			delete data.sessionID;
			delete data.sessionName;
			await this.storage.set(data);

			this.debugLog(`Auth url: ${this.authUrl}`);

			return this.authUrl;
		}

		/** @override */
		async getSession() {
			let data = await this.storage.get();
			if (data.isAuthStarted) {
				let session = {};

				try {
					session = await this.requestSession();
				} catch (err) {
					this.debugLog('Failed to get session', 'warn');

					await this.signOut();
					throw new ServiceCallResult(ServiceCallResult.ERROR_AUTH);
				}

				data.sessionID = session.sessionID;
				data.sessionName = session.sessionName;
				delete data.isAuthStarted;
				await this.storage.set(data);

				return session;
			} else if (!data.sessionID) {
				throw new ServiceCallResult(ServiceCallResult.ERROR_AUTH);
			}

			return {
				sessionID: data.sessionID,
				sessionName: data.sessionName
			};
		}

		/** @override */
		async isReadyForGrantAccess() {
			let data = await this.storage.get();
			return data.isAuthStarted;
		}

		/** @override */
		async sendNowPlaying(song) {
			let { sessionID } = await this.getSession();
			let track_meta = {
				'artist_name': song.getArtist(),
				'track_name': song.getTrack(),
			};

			if (song.getAlbum()) {
				track_meta['release_name'] = song.getAlbum();
			}

			if (song.getOriginUrl()) {
				track_meta['additional_info'] = {
					'origin_url': song.getOriginUrl()
				};
			}

			let params = {
				'listen_type': 'playing_now',
				'payload': [
					{
						'track_metadata': track_meta
					}
				]
			};

			return this.sendRequest(params, sessionID);
		}

		/** @override */
		async scrobble(song) {
			let { sessionID } = await this.getSession();

			let track_meta = {
				'artist_name': song.getArtist(),
				'track_name': song.getTrack(),
			};
			if (song.getAlbum()) {
				track_meta['release_name'] = song.getAlbum();
			}
			let params = {
				'listen_type': 'single',
				'payload': [
					{
						'listened_at': song.metadata.startTimestamp,
						'track_metadata': track_meta
					}
				]
			};
			return this.sendRequest(params, sessionID);
		}

		sendRequest(params, sessionID) {
			let requestInfo = {
				method: 'POST',
				headers: {
					'Authorization': `Token ${sessionID}`,
					'Content-Type': 'application/json; charset=UTF-8'
				},
				body: JSON.stringify(params)
			};

			let promise = fetch(this.apiUrl, requestInfo).then((response) => {
				switch (response.status) {
					case 400:
						this.debugLog('Invalid JSON sent to ListenBrainz', 'error');
						throw new ServiceCallResult(ServiceCallResult.IGNORED);
					case 401:
						this.debugLog('Invalid Authorization sent to ListenBrainz', 'error');
						throw new ServiceCallResult(ServiceCallResult.IGNORED);
				}

				return response.text();
			}).then((text) => {
				this.debugLog(text, 'log');
				return new ServiceCallResult(ServiceCallResult.OK);
			}).catch((error) => {
				this.debugLog(error.text(), 'warn');
				throw new ServiceCallResult(ServiceCallResult.ERROR_OTHER);
			});

			let timeout = BaseScrobbler.REQUEST_TIMEOUT;
			return Util.timeoutPromise(timeout, promise).catch(() => {
				this.debugLog('TIMED OUT', 'warn');
				throw new ServiceCallResult(ServiceCallResult.ERROR_OTHER);
			});
		}

		async requestSession() {
			let authUrls = [
				listenBrainzTokenPage,
				this.authUrl,
			];

			let session = null;

			for (let url of authUrls) {
				try {
					session = await this.fetchSession(url);
				} catch (e) {
					this.debugLog('request session timeout', 'warn');
					continue;
				}

				if (session) {
					break;
				}
			}

			if (session) {
				let safeId = Util.hideString(session.sessionID);
				this.debugLog(`Session ID: ${safeId}`, 'log');

				return session;
			}

			throw new ServiceCallResult(ServiceCallResult.ERROR_AUTH);
		}

		async fetchSession(url) {
			this.debugLog(`Use ${url}`);
			let promise = fetch(url, { method: 'GET', credentials: 'same-origin' });
			let timeout = BaseScrobbler.REQUEST_TIMEOUT;

			let response = await Util.timeoutPromise(timeout, promise);
			let $doc = $(await response.text());

			let sessionName = $doc.find('.page-title').text();
			let sessionID = $doc.find('#auth-token').val();

			if (sessionID && sessionName) {
				return { sessionID, sessionName };
			}

			return null;
		}
	}

	return new ListenBrainz({
		label: 'ListenBrainz',
		storage: 'ListenBrainz',
		apiUrl: 'https://api.listenbrainz.org/1/submit-listens',
		authUrl: 'https://listenbrainz.org/login/musicbrainz?next=%2Fprofile%2F',
		statusUrl: 'https://listenbrainz.org/current-status',
		profileUrl: 'https://listenbrainz.org/user/',
	});
});
<|endoftext|>


<commit_before>// @flow
import React from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router'
import { BubbleIcon, HeartIcon, RepostIcon, ShareIcon } from '../assets/Icons'
import { after, css, media, hover, select } from '../../styles/jss'
import * as s from '../../styles/jso'

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

const buttonStyle = css(
  s.colorWhite,
  s.transitionColor,
  select('&.isActive .HeartIcon > g', { fill: 'currentColor' }),
  select('& .BubbleIcon > g:nth-child(2)', s.displayNone),
  hover(
    s.colorA,
    select('& .HeartIcon > g', { fill: 'currentColor' }),
    select('& .BubbleIcon > g', { fill: 'currentColor' }),
  ),
)

type ToolButtonProps = {
  children?: React.Element<*> | null,
  className?: string | null,
  onClick?: () => {} | null,
  to?: string | null,
}

const ToolButton = (props: ToolButtonProps) => (
  props.to ?
    <Link className={`${buttonStyle} ${props.className || ''}`} to={props.to}>
      {props.children}
    </Link>
    :
    <button className={`${buttonStyle} ${props.className || ''}`} onClick={props.onClick}>
      {props.children}
    </button>
)

ToolButton.defaultProps = {
  children: null,
  className: null,
  onClick: null,
  to: null,
}

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

const toolsStyle = css(
  s.flex,
  s.pt10,
)

const alignEnd = css(s.mlAuto)
const leftSpacer = css(s.ml20)

type ToolProps = {
  postPath: string,
  isPostLoved: boolean,
}

type ToolContext = {
  onClickLovePost?: () => {},
  onClickOpenSignupModal?: () => {},
  onClickSharePost: () => {},
}

export const EditorialTools = (props: ToolProps, context: ToolContext) => (

    <ToolButton
      className={props.isPostLoved ? 'isActive' : null}
      onClick={context.onClickLovePost}
    >
      <HeartIcon />
    </ToolButton>
    <ToolButton
      className={leftSpacer}
      onClick={context.onClickOpenSignupModal}
      to={context.onClickOpenSignupModal ? null : props.postPath}
    >
      <BubbleIcon />
    </ToolButton>
    <ToolButton
      className={leftSpacer}
      onClick={context.onClickOpenSignupModal}
      to={context.onClickOpenSignupModal ? null : props.postPath}
    >
      <RepostIcon />
    </ToolButton>
    <ToolButton
      className={alignEnd}
      onClick={context.onClickSharePost}
    >
      <ShareIcon />
    </ToolButton>

)
EditorialTools.contextTypes = {
  onClickLovePost: PropTypes.func,
  onClickOpenSignupModal: PropTypes.func,
  onClickSharePost: PropTypes.func.isRequired,
}

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

const titleStyle = css(
  s.colorWhite,
  s.fontSize32,
  s.sansBold,
  { lineHeight: 38 },
  media(s.minBreak2, { fontSize: 38, lineHeight: 42 }),
)

export const EditorialTitle = ({ label }: { label: string }) => (

{label}

)

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

const subtitleStyle = css(
  s.colorWhite,
  s.fontSize18,
  { lineHeight: 24 },
  media(s.minBreak2, s.fontSize24, { lineHeight: 30 }),
)

export const EditorialSubtitle = ({ label }: { label: string }) => (

    {label}

)

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

const overlayStyle = css(
  s.absolute,
  s.flood,
  s.zIndex1,
  s.transitionBgColorSlow,
  { backgroundColor: 'rgba(0, 0, 0, 0.15)' },
  after(
    s.absolute,
    s.flood,
    s.zIndex1,
    { top: '50%', content: '""' },
    { background: 'linear-gradient(to top, rgba(0, 0, 0, 0.666) 0%, rgba(0, 0, 0, 0) 80%)' },
  ),
  select('.no-touch *:hover ~ &', { backgroundColor: 'rgba(0, 0, 0, 0.65)' }),
)

export const EditorialOverlay = () => (

)

<commit_msg>Update editorial h2s to use Atlas Grotesk Black<commit_after>// @flow
import React from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router'
import { BubbleIcon, HeartIcon, RepostIcon, ShareIcon } from '../assets/Icons'
import { after, css, media, hover, select } from '../../styles/jss'
import * as s from '../../styles/jso'

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

const buttonStyle = css(
  s.colorWhite,
  s.transitionColor,
  select('&.isActive .HeartIcon > g', { fill: 'currentColor' }),
  select('& .BubbleIcon > g:nth-child(2)', s.displayNone),
  hover(
    s.colorA,
    select('& .HeartIcon > g', { fill: 'currentColor' }),
    select('& .BubbleIcon > g', { fill: 'currentColor' }),
  ),
)

type ToolButtonProps = {
  children?: React.Element<*> | null,
  className?: string | null,
  onClick?: () => {} | null,
  to?: string | null,
}

const ToolButton = (props: ToolButtonProps) => (
  props.to ?
    <Link className={`${buttonStyle} ${props.className || ''}`} to={props.to}>
      {props.children}
    </Link>
    :
    <button className={`${buttonStyle} ${props.className || ''}`} onClick={props.onClick}>
      {props.children}
    </button>
)

ToolButton.defaultProps = {
  children: null,
  className: null,
  onClick: null,
  to: null,
}

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

const toolsStyle = css(
  s.flex,
  s.pt10,
)

const alignEnd = css(s.mlAuto)
const leftSpacer = css(s.ml20)

type ToolProps = {
  postPath: string,
  isPostLoved: boolean,
}

type ToolContext = {
  onClickLovePost?: () => {},
  onClickOpenSignupModal?: () => {},
  onClickSharePost: () => {},
}

export const EditorialTools = (props: ToolProps, context: ToolContext) => (

    <ToolButton
      className={props.isPostLoved ? 'isActive' : null}
      onClick={context.onClickLovePost}
    >
      <HeartIcon />
    </ToolButton>
    <ToolButton
      className={leftSpacer}
      onClick={context.onClickOpenSignupModal}
      to={context.onClickOpenSignupModal ? null : props.postPath}
    >
      <BubbleIcon />
    </ToolButton>
    <ToolButton
      className={leftSpacer}
      onClick={context.onClickOpenSignupModal}
      to={context.onClickOpenSignupModal ? null : props.postPath}
    >
      <RepostIcon />
    </ToolButton>
    <ToolButton
      className={alignEnd}
      onClick={context.onClickSharePost}
    >
      <ShareIcon />
    </ToolButton>

)
EditorialTools.contextTypes = {
  onClickLovePost: PropTypes.func,
  onClickOpenSignupModal: PropTypes.func,
  onClickSharePost: PropTypes.func.isRequired,
}

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

const titleStyle = css(
  s.colorWhite,
  s.fontSize32,
  s.sansBlack,
  { lineHeight: 38 },
  media(s.minBreak2, { fontSize: 38, lineHeight: 42 }),
)

export const EditorialTitle = ({ label }: { label: string }) => (

{label}

)

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

const subtitleStyle = css(
  s.colorWhite,
  s.fontSize18,
  { lineHeight: 24 },
  media(s.minBreak2, s.fontSize24, { lineHeight: 30 }),
)

export const EditorialSubtitle = ({ label }: { label: string }) => (

    {label}

)

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

const overlayStyle = css(
  s.absolute,
  s.flood,
  s.zIndex1,
  s.transitionBgColorSlow,
  { backgroundColor: 'rgba(0, 0, 0, 0.15)' },
  after(
    s.absolute,
    s.flood,
    s.zIndex1,
    { top: '50%', content: '""' },
    { background: 'linear-gradient(to top, rgba(0, 0, 0, 0.666) 0%, rgba(0, 0, 0, 0) 80%)' },
  ),
  select('.no-touch *:hover ~ &', { backgroundColor: 'rgba(0, 0, 0, 0.65)' }),
)

export const EditorialOverlay = () => (

)

<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var http = require('http')
  , req = http.IncomingMessage.prototype;

/**
 * Intiate a login session for `user`.
 *
 * Options:
 *   - `session`  Save login state in session, defaults to _true_
 *
 * Examples:
 *
 *     req.logIn(user, { session: false });
 *
 *     req.logIn(user, function(err) {
 *       if (err) { throw err; }
 *       // session saved
 *     });
 *
 * @param {User} user
 * @param {Object} options
 * @param {Function} done
 * @api public
 */
req.login =
req.logIn = function(user, options, done) {
  if (typeof options == 'function') {
    done = options;
    options = {};
  }
  options = options || {};

  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }
  var session = (options.session === undefined) ? true : options.session;

  this[property] = user;
  if (session) {
    if (!this._passport) throw new Error('passport.initialize() middleware not in use');

    var self = this;
    this._passport.instance.serializeUser(user, this, function(err, obj) {
      if (err) { self[property] = null; return done(err); }
      self._passport.session.user = obj;
      done();
    });
  } else {
    done && done();
  }
}

/**
 * Terminate an existing login session.
 *
 * @api public
 */
req.logout =
req.logOut = function() {
  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }

  this[property] = null;
  if (this._passport && this._passport.session) {
    delete this._passport.session.user;
  }
};

/**
 * Test if request is authenticated.
 *
 * @return {Boolean}
 * @api public
 */
req.isAuthenticated = function() {
  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }

  return (this[property]) ? true : false;
};

/**
 * Test if request is unauthenticated.
 *
 * @return {Boolean}
 * @api public
 */
req.isUnauthenticated = function() {
  return !this.isAuthenticated();
};
<commit_msg>Fix merge conflicts.<commit_after>/**
 * Module dependencies.
 */
var http = require('http')
  , req = http.IncomingMessage.prototype;

/**
 * Intiate a login session for `user`.
 *
 * Options:
 *   - `session`  Save login state in session, defaults to _true_
 *
 * Examples:
 *
 *     req.logIn(user, { session: false });
 *
 *     req.logIn(user, function(err) {
 *       if (err) { throw err; }
 *       // session saved
 *     });
 *
 * @param {User} user
 * @param {Object} options
 * @param {Function} done
 * @api public
 */
req.login =
req.logIn = function(user, options, done) {
  if (typeof options == 'function') {
    done = options;
    options = {};
  }
  options = options || {};

  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }
  var session = (options.session === undefined) ? true : options.session;

  this[property] = user;
  if (session) {
    if (!this._passport) { throw new Error('passport.initialize() middleware not in use'); }
    if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }

    var self = this;
    this._passport.instance.serializeUser(user, this, function(err, obj) {
      if (err) { self[property] = null; return done(err); }
      self._passport.session.user = obj;
      done();
    });
  } else {
    done && done();
  }
}

/**
 * Terminate an existing login session.
 *
 * @api public
 */
req.logout =
req.logOut = function() {
  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }

  this[property] = null;
  if (this._passport && this._passport.session) {
    delete this._passport.session.user;
  }
};

/**
 * Test if request is authenticated.
 *
 * @return {Boolean}
 * @api public
 */
req.isAuthenticated = function() {
  var property = 'user';
  if (this._passport && this._passport.instance) {
    property = this._passport.instance._userProperty || 'user';
  }

  return (this[property]) ? true : false;
};

/**
 * Test if request is unauthenticated.
 *
 * @return {Boolean}
 * @api public
 */
req.isUnauthenticated = function() {
  return !this.isAuthenticated();
};
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'

export default class Prefs extends React.Component {
  static propTypes = {
    prefs: PropTypes.object.isRequired,
    setPrefs: PropTypes.func.isRequired,
    providerRefresh: PropTypes.func.isRequired,
  }

  setEnabled = this.setEnabled.bind(this)
  handleRefresh = this.handleRefresh.bind(this)

  setEnabled(e) {
    let prefs = Object.assign({}, this.props.prefs)
    prefs.enabled = e.target.checked
    this.props.setPrefs('provider.cdg', prefs)
  }

  handleRefresh() {
    this.props.providerRefresh('cdg')
  }

  render() {
    const { prefs } = this.props
    if (!prefs) return null

    const enabled = prefs.enabled === true
    let paths = prefs.paths || []

    paths = paths.map(path => (

{path}

    ))

    return (

          <input type='checkbox' checked={enabled} onChange={this.setEnabled}/>
           CD+Graphics

        <button onClick={this.handleRefresh}>Refresh</button>
        {paths}

    )
  }
}
<commit_msg>Tweak provider title<commit_after>import React, { PropTypes } from 'react'

export default class Prefs extends React.Component {
  static propTypes = {
    prefs: PropTypes.object.isRequired,
    setPrefs: PropTypes.func.isRequired,
    providerRefresh: PropTypes.func.isRequired,
  }

  setEnabled = this.setEnabled.bind(this)
  handleRefresh = this.handleRefresh.bind(this)

  setEnabled(e) {
    let prefs = Object.assign({}, this.props.prefs)
    prefs.enabled = e.target.checked
    this.props.setPrefs('provider.cdg', prefs)
  }

  handleRefresh() {
    this.props.providerRefresh('cdg')
  }

  render() {
    const { prefs } = this.props
    if (!prefs) return null

    const enabled = prefs.enabled === true
    let paths = prefs.paths || []

    paths = paths.map(path => (

{path}

    ))

    return (

          <input type='checkbox' checked={enabled} onChange={this.setEnabled}/>
           CD+Graphics (.cdg + audio)

        <button onClick={this.handleRefresh}>Refresh</button>
        {paths}

    )
  }
}
<|endoftext|>


<commit_before>$(function() {

    var preDomName = null;
    function showTweet(tweets) {
        if(!(tweets instanceof Array)) {
            return;
        }
        var i = Math.floor(Math.random() * tweets.length);
        //console.log(i);
        //console.log(tweets[i].tweet);

        var sides = ["left", "right"];
        var numbers =  [1,2,3,4,5];

        var whichSide = sides[Math.floor(Math.random() * sides.length)];
        var whatNumber = Math.floor(Math.random() * numbers.length);

        var domName = "#tweet-" + whichSide + whatNumber;
        if (preDomName != null) {
            //console.log(preDomName);
            $(preDomName).animate({
                visibility: "hidden"
            }, 900);
            $(preDomName).css({opecity: 1.0, visibility: "visible"}).animate({opacity: 0.0}, 500);
        }
        preDomName = domName;

        $(domName).css({opacity: 0.0, visibility: "visible"}).animate({opacity: 1.0}, 500);
        $(domName).text(tweets[i].tweet);
    }

    $("#indicator").activity({color: "#000"});

    var myid;

    //遅延情報の更新
    function updateInfos(infos) {
        for(var i=0;i<infos.length;i++) {
            var station_name = infos[i].station_name;
            $("#"+station_name+"-modal").text(infos[i].text);
        }

    }

    var ws = new WebSocket(location.origin.replace(/^http/, 'ws'));
    msgflag = false;

    //current trains sprite objects
    currentTrains = {};
    currentWets = {};

    var tweets;
    var counter = 0;
    ws.onmessage = function(msg) {
        var data = JSON.parse(msg.data);
        //console.log(data);
        if(!data.trains){return;}
        if(msgflag) {console.log(data)}
        //$(".trains").append("
" + msg.data + "
");

        updateInfos(data.infos);

        var trains = data.trains;

        if (data.tweets.length != 0) {
            $("#indicator").activity(false);
            tweets = data.tweets;
        }

        if (counter % 5 == 0) {
            showTweet(tweets);
        }
        counter++;

        //処理フラグ
        for(var x in currentTrains) {
            currentTrains[x].proc = false;
        }
        for(var x in currentWets) {
            currentWets[x].proc = false;
        }

        for(i = 0; i < trains.length; ++i){
            var train;
            var wet;
            var exists = currentTrains[trains[i].train_number]!=undefined;
            var exists_wet = currentWets[trains[i].train_number]!=undefined;
            if(exists) {
                train = currentTrains[trains[i].train_number];
            }else{
                train = new Train();
                currentTrains[trains[i].train_number] = train;
            }
            if(trains[i].delay > 0){
                if(exists_wet){
                    wet = currentTrains[trains[i].train_number];
                } else {
                    wet = new Wet();
                    currentWets[trains[i].train_number] = wet;
                }
                wet.proc = true;
            } else {
                wet = {};
                wet.proc = false;
            }

            if (trains[i].is_stop) {
                console.log(currentTrains[trains[i].train_number]);
            }

            train.proc = true;

            var x,y;
            if("inside_line" === trains[i].line_name){
                x = (trains[i].x + 1) * 281 + 41;
                y = (trains[i].y + 1) * 281 + 37;
            } else {
                x = (trains[i].x + 1) * 319 + 3;
                y = (trains[i].y + 1) * 319 + 0;
            }

            if(exists){
                train.x = x;
                train.y = y;
            }else{
                train.moveTo(x, y, 40);
                core.rootScene.addChild(train);
            }
            if(wet.proc){
                if(exists_wet){
                    wet.x = x;
                    wet.y = y;
                }else{
                    if(typeof(wet.moveTo) !== undefined){
                        wet.moveTo(x + 20, y, 40);
                        core.rootScene.addChild(wet);
                    }
                }
            }
        }

        //処理flag==falseの要素を削除
        for(var x in currentTrains) {
            if(!currentTrains[x].proc) {
                core.rootScene.removeChild(currentTrains[x]);
                delete currentTrains[x];
            }
        }
        for(var x in currentWets) {
            if(!currentWets[x].proc) {
                core.rootScene.removeChild(currentWets[x]);
                delete currentWets[x];
            }
        }
    }

    enchant(); // initialize
    var core = new Core(680, 680); // core stage
    core.preload('./images/yamate.png'); // preload image
    core.preload('./images/wet.png'); // preload image
    core.fps = 10;

    core.onload = function(){

       /*
        bear.tl.moveBy(288, 0, 90)   // move right
            .scaleTo(-1, 1, 10)      // turn left
            .moveBy(-288, 0, 90)     // move left
            .scaleTo(1, 1, 10)       // turn right
            .loop();                 // loop it
        */
    };

    // Train Object Class
    var defineFrame = [0, 1, 0, 2];
    var defineFrame_wet = [0, 1, 2, 2];
    var Train = Class.create(Sprite, {
        // 初期化
        initialize: function() {
            Sprite.call(this, 36, 36);
            this.image = core.assets['./images/yamate.png'];

            var rand = Math.floor( Math.random() * 100 ) % 4;
            var newFrame = [];
            for(var i=0;i<4;i++){
                newFrame.push(defineFrame[(i+rand)%4]);
            }
            //console.log(newFrame);
            this.frame = newFrame;   // select sprite frame
        }
    });
    var Wet = Class.create(Sprite, {
        // 初期化
        initialize: function() {
            Sprite.call(this, 20, 20);
            this.image = core.assets['./images/wet.png'];

            var rand = Math.floor( Math.random() * 100 ) % 4;
            var newFrame = [];
            for(var i=0;i<4;i++){
                newFrame.push(defineFrame_wet[(i+rand)%4]);
            }
            //console.log(newFrame);
            this.frame = newFrame;   // select sprite frame
        }
    });

    core.start(); // start your core!`
    $(".subway-map").subwayMap({ debug: true });

    //駅名のクリックイベント処理
    //透明なDOMを前面に作成し、click eventを取得する
    stations = [];
    $("div.subway-map span").each(function(){
        var copy = $(this).clone();
        var stationName = copy.text();
        var modalId = stationName+"-modal";
        stations.push(stationName);

        var modal =  $('
遅延情報はありません
');
        copy.leanModal({ top : 400, overlay : 0.4, closeButton: ".modal_close" });

        copy.css({"color":"transparent", "z-index":6000});
        copy.attr({"href":"#"+modalId, "id":stationName});
        copy.text(copy.text());
        $(this).after(copy);
        $("body").append(modal);
        $(this).click(function() {

        });
    })

});

<commit_msg>modify latent_info<commit_after>$(function() {

    var preDomName = null;
    function showTweet(tweets) {
        if(!(tweets instanceof Array)) {
            return;
        }
        var i = Math.floor(Math.random() * tweets.length);
        //console.log(i);
        //console.log(tweets[i].tweet);

        var sides = ["left", "right"];
        var numbers =  [1,2,3,4,5];

        var whichSide = sides[Math.floor(Math.random() * sides.length)];
        var whatNumber = Math.floor(Math.random() * numbers.length);

        var domName = "#tweet-" + whichSide + whatNumber;
        if (preDomName != null) {
            //console.log(preDomName);
            $(preDomName).animate({
                visibility: "hidden"
            }, 900);
            $(preDomName).css({opecity: 1.0, visibility: "visible"}).animate({opacity: 0.0}, 500);
        }
        preDomName = domName;

        $(domName).css({opacity: 0.0, visibility: "visible"}).animate({opacity: 1.0}, 500);
        $(domName).text(tweets[i].tweet);
    }

    $("#indicator").activity({color: "#000"});

    var myid;

    //遅延情報の更新
    function updateInfos(infos) {

        station_hash = {};
        for(var i=0;i<infos.length;i++) {
            station_hash[infos[i].station_name] = infos[i].text;
        }

        for(var i=0;i<stations.length;i++) {
            var station_name = stations[i];
            if(station_hash[station_name]!=undefined) {
                //遅延情報が存在
                console.log("#"+station_name+"-modal");
                $("#"+station_name).html(station_name+'');
                $("#"+station_name+"-modal").text(station_hash[station_name]);
            }else{
                //遅延情報がない
                $("#"+station_name).text(station_name);
                $("#"+station_name+"-modal").append('遅延情報がありません');
            }
        }

    }

    var ws = new WebSocket(location.origin.replace(/^http/, 'ws'));
    msgflag = false;

    //current trains sprite objects
    currentTrains = {};
    currentWets = {};

    var tweets;
    var counter = 0;
    ws.onmessage = function(msg) {
        var data = JSON.parse(msg.data);
        //console.log(data);
        if(!data.trains){return;}
        if(msgflag) {console.log(data)}
        //$(".trains").append("
" + msg.data + "
");

        updateInfos(data.infos);

        var trains = data.trains;

        if (data.tweets.length != 0) {
            $("#indicator").activity(false);
            tweets = data.tweets;
        }

        if (counter % 5 == 0) {
            showTweet(tweets);
        }
        counter++;

        //処理フラグ
        for(var x in currentTrains) {
            currentTrains[x].proc = false;
        }
        for(var x in currentWets) {
            currentWets[x].proc = false;
        }

        for(i = 0; i < trains.length; ++i){
            var train;
            var wet;
            var exists = currentTrains[trains[i].train_number]!=undefined;
            var exists_wet = currentWets[trains[i].train_number]!=undefined;
            if(exists) {
                train = currentTrains[trains[i].train_number];
            }else{
                train = new Train();
                currentTrains[trains[i].train_number] = train;
            }
            if(trains[i].delay > 0){
                if(exists_wet){
                    wet = currentTrains[trains[i].train_number];
                } else {
                    wet = new Wet();
                    currentWets[trains[i].train_number] = wet;
                }
                wet.proc = true;
            } else {
                wet = {};
                wet.proc = false;
            }

            if (trains[i].is_stop) {
                console.log(currentTrains[trains[i].train_number]);
            }

            train.proc = true;

            var x,y;
            if("inside_line" === trains[i].line_name){
                x = (trains[i].x + 1) * 281 + 41;
                y = (trains[i].y + 1) * 281 + 37;
            } else {
                x = (trains[i].x + 1) * 319 + 3;
                y = (trains[i].y + 1) * 319 + 0;
            }

            if(exists){
                train.x = x;
                train.y = y;
            }else{
                train.moveTo(x, y, 40);
                core.rootScene.addChild(train);
            }
            if(wet.proc){
                if(exists_wet){
                    wet.x = x;
                    wet.y = y;
                }else{
                    if(typeof(wet.moveTo) !== undefined){
                        wet.moveTo(x + 20, y, 40);
                        core.rootScene.addChild(wet);
                    }
                }
            }
        }

        //処理flag==falseの要素を削除
        for(var x in currentTrains) {
            if(!currentTrains[x].proc) {
                core.rootScene.removeChild(currentTrains[x]);
                delete currentTrains[x];
            }
        }
        for(var x in currentWets) {
            if(!currentWets[x].proc) {
                core.rootScene.removeChild(currentWets[x]);
                delete currentWets[x];
            }
        }
    }

    enchant(); // initialize
    var core = new Core(680, 680); // core stage
    core.preload('./images/yamate.png'); // preload image
    core.preload('./images/wet.png'); // preload image
    core.fps = 10;

    core.onload = function(){

       /*
        bear.tl.moveBy(288, 0, 90)   // move right
            .scaleTo(-1, 1, 10)      // turn left
            .moveBy(-288, 0, 90)     // move left
            .scaleTo(1, 1, 10)       // turn right
            .loop();                 // loop it
        */
    };

    // Train Object Class
    var defineFrame = [0, 1, 0, 2];
    var defineFrame_wet = [0, 1, 2, 2];
    var Train = Class.create(Sprite, {
        // 初期化
        initialize: function() {
            Sprite.call(this, 36, 36);
            this.image = core.assets['./images/yamate.png'];

            var rand = Math.floor( Math.random() * 100 ) % 4;
            var newFrame = [];
            for(var i=0;i<4;i++){
                newFrame.push(defineFrame[(i+rand)%4]);
            }
            //console.log(newFrame);
            this.frame = newFrame;   // select sprite frame
        }
    });
    var Wet = Class.create(Sprite, {
        // 初期化
        initialize: function() {
            Sprite.call(this, 20, 20);
            this.image = core.assets['./images/wet.png'];

            var rand = Math.floor( Math.random() * 100 ) % 4;
            var newFrame = [];
            for(var i=0;i<4;i++){
                newFrame.push(defineFrame_wet[(i+rand)%4]);
            }
            //console.log(newFrame);
            this.frame = newFrame;   // select sprite frame
        }
    });

    core.start(); // start your core!`
    $(".subway-map").subwayMap({ debug: true });

    //駅名のクリックイベント処理
    //透明なDOMを前面に作成し、click eventを取得する
    stations = [];
    $("div.subway-map span").each(function(){
        var copy = $(this).clone();
        var stationName = copy.text();
        var modalId = stationName+"-modal";
        stations.push(stationName);

        var modal =  $('
遅延情報はありません
');
        copy.leanModal({ top : 400, overlay : 0.4, closeButton: ".modal_close" });

        copy.css({"color":"transparent", "z-index":6000});
        copy.attr({"href":"#"+modalId, "id":stationName});
        copy.text(copy.text());
        $(this).after(copy);
        $("body").append(modal);
        $(this).click(function() {

        });
    })

});

<|endoftext|>


<commit_before>'use strict';

define([
  'backbone',
  'handlebars',
  'moment',
  'application/abstract/conexion',
  'application/abstract/utils',
  'text!application/templates/sidebar/project/projectReach.handlebars'
  ], function(Backbone, handlebars, moment, conexion, utils, tpl) {

  var ProjectReach = Backbone.View.extend({

    el: '#project-reach',

    template: Handlebars.compile(tpl),

    initialize: function() {
      if (!this.$el.length) {
        return
      }
      this.project = project;
      if (!!this.project.actual_project_reach && !!this.project.target_project_reach && this.project.project_reach_unit) {
        this.render();
      }
    },

    parseData: function(){
      this.project.reach = (this.project.actual_project_reach/this.project.target_project_reach) + '%';
      this.project.actual_project_reach_string = utils.formatCurrency(this.project.actual_project_reach);
      this.project.target_project_reach_string = utils.formatCurrency(this.project.target_project_reach);
      return this.project;
    },

    render: function(){
      this.$el.html(this.template(this.parseData()));
    },

  });

  return ProjectReach;

});
<commit_msg>project reach fixes<commit_after>'use strict';

define([
  'backbone',
  'handlebars',
  'moment',
  'application/abstract/conexion',
  'application/abstract/utils',
  'text!application/templates/sidebar/project/projectReach.handlebars'
  ], function(Backbone, handlebars, moment, conexion, utils, tpl) {

  var ProjectReach = Backbone.View.extend({

    el: '#project-reach',

    template: Handlebars.compile(tpl),

    initialize: function() {
      if (!this.$el.length) {
        return
      }
      this.project = project;
      if (!!this.project.actual_project_reach && !!this.project.target_project_reach && this.project.project_reach_unit) {
        this.render();
      }
    },

    parseData: function(){
      this.project.reach = (this.project.actual_project_reach/this.project.target_project_reach*100) + '%';
      this.project.actual_project_reach_string = utils.formatCurrency(this.project.actual_project_reach);
      this.project.target_project_reach_string = utils.formatCurrency(this.project.target_project_reach);
      return this.project;
    },

    render: function(){
      this.$el.html(this.template(this.parseData()));
    },

  });

  return ProjectReach;

});
<|endoftext|>


<commit_before>/* global patternfly */
angular.module('patternfly.charts').component('pfDonutPctChart', {
  bindings: {
    config: '<',
    data: '<',
    chartHeight: '<?',
    centerLabel: '<?',
    onThresholdChange: '&',
  },
  templateUrl: '/static/pf_charts/donut-pct-chart.html.haml',
  controller: donutPctChartController,
});
donutPctChartController.$inject = ['pfUtils'];

function donutPctChartController(pfUtils) {
  'use strict';
  var vm = this;
  var prevData;

  vm.$onInit = function() {
    vm.donutChartId = 'donutPctChart';
    if (vm.config.chartId) {
      vm.donutChartId = vm.config.chartId + vm.donutChartId;
    }

    vm.updateAll();
  };

  vm.updateAvailable = function() {
    vm.data.available = vm.data.total - vm.data.used;
  };

  vm.getStatusColor = function(used, thresholds) {
    var threshold = "none";
    var color = pfUtils.colorPalette.blue;

    if (thresholds) {
      threshold = "ok";
      color = pfUtils.colorPalette.green;
      if (used >= thresholds.error) {
        threshold = "error";
        color = pfUtils.colorPalette.red;
      } else if (used >= thresholds.warning) {
        threshold = "warning";
        color = pfUtils.colorPalette.orange;
      }
    }

    if (! vm.threshold || vm.threshold !== threshold) {
      vm.threshold = threshold;
      vm.onThresholdChange({ threshold: vm.threshold });
    }

    return color;
  };

  vm.statusDonutColor = function() {
    var color;
    var percentUsed;

    color = { pattern: [] };
    percentUsed = vm.data.used / vm.data.total * 100.0;
    color.pattern[0] = vm.getStatusColor(percentUsed, vm.config.thresholds);
    color.pattern[1] = pfUtils.colorPalette.black300;
    return color;
  };

  vm.donutTooltip = function() {
    return {
      contents: function(d) {
        var tooltipHtml;

        if (vm.config.tooltipFn) {
          tooltipHtml = '' +
            vm.config.tooltipFn(d) +
            '';
        } else {
          tooltipHtml = '' +
            Math.round(d[0].ratio * 100) + '%' + ' ' + vm.config.units + ' ' + d[0].name +
            '';
        }

        return tooltipHtml;
      },
    };
  };

  vm.getDonutData = function() {
    return {
      columns: [
        ['Used', vm.data.used],
        ['Available', vm.data.available],
      ],
      type: 'donut',
      donut: {
        label: {
          show: false,
        },
      },
      groups: [
        ['used', 'available'],
      ],
      order: null,
    };
  };

  vm.getCenterLabelText = function() {
    var centerLabelText;

    // default to 'used' info.
    centerLabelText = { bigText: vm.data.used,
      smText: vm.config.units + ' Used' };

    if (vm.config.centerLabelFn) {
      centerLabelText.bigText = vm.config.centerLabelFn();
      centerLabelText.smText = '';
    } else if (vm.centerLabel === 'none') {
      centerLabelText.bigText = '';
      centerLabelText.smText = '';
    } else if (vm.centerLabel === 'available') {
      centerLabelText.bigText = vm.data.available;
      centerLabelText.smText = vm.config.units + ' Available';
    } else if (vm.centerLabel === 'percent') {
      centerLabelText.bigText = Math.round(vm.data.used / vm.data.total * 100.0) + '%';
      centerLabelText.smText = 'of ' + vm.data.total + ' ' + vm.config.units;
    }

    return centerLabelText;
  };

  vm.updateAll = function() {
    // Need to deep watch changes in chart data
    prevData = angular.copy(vm.data);

    vm.config = pfUtils.merge(patternfly.c3ChartDefaults().getDefaultDonutConfig(), vm.config);
    vm.updateAvailable();
    vm.config.data = pfUtils.merge(vm.config.data, vm.getDonutData());
    vm.config.color = vm.statusDonutColor(vm);
    vm.config.tooltip = vm.donutTooltip();
    vm.config.data.onclick = vm.config.onClickFn;
  };

  vm.setupDonutChartTitle = function() {
    var donutChartTitle;
    var centerLabelText;

    if (angular.isUndefined(vm.chart)) {
      return;
    }

    donutChartTitle = d3.select(vm.chart.element).select('text.c3-chart-arcs-title');
    if (! donutChartTitle) {
      return;
    }

    centerLabelText = vm.getCenterLabelText();

    // Remove any existing title.
    donutChartTitle.selectAll('*').remove();
    if (centerLabelText.bigText && ! centerLabelText.smText) {
      donutChartTitle.text(centerLabelText.bigText);
    } else {
      donutChartTitle.insert('tspan').text(centerLabelText.bigText).classed('donut-title-big-pf', true).attr('dy', 0).attr('x', 0);
      donutChartTitle.insert('tspan').text(centerLabelText.smText).classed('donut-title-small-pf', true).attr('dy', 20).attr('x', 0);
    }
  };

  vm.setChart = function(chart) {
    vm.chart = chart;
    vm.setupDonutChartTitle();
  };

  vm.$onChanges = function(changesObj) {
    if (changesObj.config || changesObj.data) {
      vm.updateAll();
    }
    if (changesObj.chartHeight) {
      vm.config.size.height = changesObj.chartHeight.currentValue;
    }
    if (changesObj.centerLabel) {
      vm.setupDonutChartTitle();
    }
  };

  vm.$doCheck = function() {
    // do a deep compare on data
    if (! angular.equals(vm.data, prevData)) {
      vm.updateAll();
    }
  };
}
<commit_msg>Add missing gettext into pfDonutPctChart<commit_after>/* global patternfly */
angular.module('patternfly.charts').component('pfDonutPctChart', {
  bindings: {
    config: '<',
    data: '<',
    chartHeight: '<?',
    centerLabel: '<?',
    onThresholdChange: '&',
  },
  templateUrl: '/static/pf_charts/donut-pct-chart.html.haml',
  controller: donutPctChartController,
});
donutPctChartController.$inject = ['pfUtils'];

function donutPctChartController(pfUtils) {
  'use strict';
  var vm = this;
  var prevData;

  vm.$onInit = function() {
    vm.donutChartId = 'donutPctChart';
    if (vm.config.chartId) {
      vm.donutChartId = vm.config.chartId + vm.donutChartId;
    }

    vm.updateAll();
  };

  vm.updateAvailable = function() {
    vm.data.available = vm.data.total - vm.data.used;
  };

  vm.getStatusColor = function(used, thresholds) {
    var threshold = "none";
    var color = pfUtils.colorPalette.blue;

    if (thresholds) {
      threshold = "ok";
      color = pfUtils.colorPalette.green;
      if (used >= thresholds.error) {
        threshold = "error";
        color = pfUtils.colorPalette.red;
      } else if (used >= thresholds.warning) {
        threshold = "warning";
        color = pfUtils.colorPalette.orange;
      }
    }

    if (! vm.threshold || vm.threshold !== threshold) {
      vm.threshold = threshold;
      vm.onThresholdChange({ threshold: vm.threshold });
    }

    return color;
  };

  vm.statusDonutColor = function() {
    var color;
    var percentUsed;

    color = { pattern: [] };
    percentUsed = vm.data.used / vm.data.total * 100.0;
    color.pattern[0] = vm.getStatusColor(percentUsed, vm.config.thresholds);
    color.pattern[1] = pfUtils.colorPalette.black300;
    return color;
  };

  vm.donutTooltip = function() {
    return {
      contents: function(d) {
        var tooltipHtml;

        if (vm.config.tooltipFn) {
          tooltipHtml = '' +
            vm.config.tooltipFn(d) +
            '';
        } else {
          tooltipHtml = '' +
            Math.round(d[0].ratio * 100) + '%' + ' ' + vm.config.units + ' ' + d[0].name +
            '';
        }

        return tooltipHtml;
      },
    };
  };

  vm.getDonutData = function() {
    return {
      columns: [
        [__('Used'), vm.data.used],
        [__('Available'), vm.data.available],
      ],
      type: 'donut',
      donut: {
        label: {
          show: false,
        },
      },
      groups: [
        ['used', 'available'],
      ],
      order: null,
    };
  };

  vm.getCenterLabelText = function() {
    var centerLabelText;

    // default to 'used' info.
    centerLabelText = { bigText: vm.data.used,
      smText: vm.config.units + __(' Used') };

    if (vm.config.centerLabelFn) {
      centerLabelText.bigText = vm.config.centerLabelFn();
      centerLabelText.smText = '';
    } else if (vm.centerLabel === 'none') {
      centerLabelText.bigText = '';
      centerLabelText.smText = '';
    } else if (vm.centerLabel === 'available') {
      centerLabelText.bigText = vm.data.available;
      centerLabelText.smText = vm.config.units + __(' Available');
    } else if (vm.centerLabel === 'percent') {
      centerLabelText.bigText = Math.round(vm.data.used / vm.data.total * 100.0) + '%';
      centerLabelText.smText = __('of ') + vm.data.total + ' ' + vm.config.units;
    }

    return centerLabelText;
  };

  vm.updateAll = function() {
    // Need to deep watch changes in chart data
    prevData = angular.copy(vm.data);

    vm.config = pfUtils.merge(patternfly.c3ChartDefaults().getDefaultDonutConfig(), vm.config);
    vm.updateAvailable();
    vm.config.data = pfUtils.merge(vm.config.data, vm.getDonutData());
    vm.config.color = vm.statusDonutColor(vm);
    vm.config.tooltip = vm.donutTooltip();
    vm.config.data.onclick = vm.config.onClickFn;
  };

  vm.setupDonutChartTitle = function() {
    var donutChartTitle;
    var centerLabelText;

    if (angular.isUndefined(vm.chart)) {
      return;
    }

    donutChartTitle = d3.select(vm.chart.element).select('text.c3-chart-arcs-title');
    if (! donutChartTitle) {
      return;
    }

    centerLabelText = vm.getCenterLabelText();

    // Remove any existing title.
    donutChartTitle.selectAll('*').remove();
    if (centerLabelText.bigText && ! centerLabelText.smText) {
      donutChartTitle.text(centerLabelText.bigText);
    } else {
      donutChartTitle.insert('tspan').text(centerLabelText.bigText).classed('donut-title-big-pf', true).attr('dy', 0).attr('x', 0);
      donutChartTitle.insert('tspan').text(centerLabelText.smText).classed('donut-title-small-pf', true).attr('dy', 20).attr('x', 0);
    }
  };

  vm.setChart = function(chart) {
    vm.chart = chart;
    vm.setupDonutChartTitle();
  };

  vm.$onChanges = function(changesObj) {
    if (changesObj.config || changesObj.data) {
      vm.updateAll();
    }
    if (changesObj.chartHeight) {
      vm.config.size.height = changesObj.chartHeight.currentValue;
    }
    if (changesObj.centerLabel) {
      vm.setupDonutChartTitle();
    }
  };

  vm.$doCheck = function() {
    // do a deep compare on data
    if (! angular.equals(vm.data, prevData)) {
      vm.updateAll();
    }
  };
}
<|endoftext|>


<commit_before>const fs = require('fs')
// const { isVisible } = require('is-visible')
const h = require('../h')
const human = require('human-time')

const {
  Struct, Value, Dict,
  dictToCollection, map: mutantMap, when, computed
} = require('@mmckegg/mutant')

exports.needs = {
  avatar_image_link: 'first',
  avatar_name_link: 'first',
  sbot_gossip_peers: 'first',
  sbot_gossip_connect: 'first'
}

exports.gives = {
  menu_items: true,
  builtin_tabs: true,
  screen_view: true,
  mcss: true
}

//sbot_gossip_connect
//sbot_gossip_add

function legacyToMultiServer(addr) {
  return 'net:'+addr.host + ':'+addr.port + '~shs:'+addr.key.substring(1).replace('.ed25519','')
}

//on the same wifi network
function isLocal (peer) {
  // don't rely on private ip address, because
  // cjdns creates fake private ip addresses.
  return ip.isPrivate(peer.host) && peer.type === 'local'
}

function getType (peer) {
  return (
      isLongterm(peer)    ? 'modern'
    : isLegacy(peer)      ? 'legacy'
    : isInactive(peer)    ? 'inactive'
    : isUnattempted(peer) ? 'unattempted'
    :                       'other' //should never happen
  )

  //pub is running scuttlebot >=8
  //have connected successfully.
  function isLongterm (peer) {
    return peer.ping && peer.ping.rtt && peer.ping.rtt.mean > 0
  }

  //pub is running scuttlebot < 8
  //have connected sucessfully
  function isLegacy (peer) {
    return /connect/.test(peer.state) || (peer.duration && peer.duration.mean) > 0 && !isLongterm(peer)
  }

  //tried to connect, but failed.
  function isInactive (peer) {
    return peer.stateChange && (peer.duration && peer.duration.mean == 0)
  }

  //havn't tried to connect peer yet.
  function isUnattempted (peer) {
    return !peer.stateChange
  }
}

function origin (peer) {
  return peer.source === 'local' ? 0 : 1
}

function round(n) {
  return Math.round(n*100)/100
}

function duration (s) {
  if(!s) return s
  if (Math.abs(s) > 30000)
    return round(s/60000)+'m'
  else if (Math.abs(s) > 500)
    return round(s/1000)+'s'
  else
    return round(s)+'ms'
}

function peerListSort (a, b) {
  var states = {
    connected: 3,
    connecting: 2
  }

  //types of peers
  var types = {
    modern: 4,
    legacy: 3,
    inactive: 2,
    unattempted: 1,
    other: 0
  }

  return (
    (states[b.state] || 0) - (states[a.state] || 0)
    || origin(b) - origin(a)
    || types[getType(b)] - types[getType(a)]
    || b.stateChange - a.stateChange
  )
}

function formatDate (time) {
  return new Date(time).toString()
}

function humanDate (time) {
  return human(new Date(time)).replace(/minute/, 'min').replace(/second/, 'sec')
}

exports.create = function (api) {

  return {
    menu_items: () => h('a', {href: '#/network'}, '/network'),
    builtin_tabs: () => ['/network'],
    screen_view,
    mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
  }

  function screen_view (path) {
    if (path !== '/network') return

    var peers = obs_gossip_peers(api)

    return h('div', { style: {'overflow':'auto'}, className: 'column scroller' }, [
      h('Network', [
        mutantMap(peers, peer => {
          var { key, ping, source, state, stateChange } = peer

          return h('NetworkConnection', [
            h('section.avatar', [
              api.avatar_image_link(key()),
            ]),
            h('section.name', [
              api.avatar_name_link(key()),
            ]),
            h('section.type', [
              computed(peer, getType),
            ]),
            h('section.source', [
              h('label', 'source:'),
              h('code', source)
            ]),
            h('section.state', [
              h('label', 'state:'),
              h('i', {
                className: computed(state, (state) => '-'+state)
              }),
              h('code', when(state, state, 'not connected'))
            ]),
            h('section.actions', [
              h('button', {
                'ev-click': () => {
                  api.sbot_gossip_connect(peer(), (err) => {
                    if(err) console.error(err)
                    else console.log('connected to', peer())
                  })
                }},
                'connect'
              )
            ]),
            h('section.time-ago', [
              h('div',
                { title: computed(stateChange, formatDate) },
                [ computed(stateChange, humanDate) ]
              )
            ]),
            h('section.ping', [
              h('div.rtt', [
                h('label', 'rtt:'),
                h('code', computed(ping.rtt.mean, duration))
              ]),
              h('div.skew', [
                h('label', 'skew:'),
                h('code', computed(ping.skew.mean, duration))
              ]),
            ]),
            h('section.address', [
              h('code', computed(peer, legacyToMultiServer))
            ])
          ])
        })
      ])
    ])
  }
}

function obs_gossip_peers (api) {
  var timer = null
  var state = Dict({}, {
    onListen: () => {
      timer = setInterval(refresh, 5e3)
    },
    onUnlisten: () => {
      clearInterval(timer)
    }
  })

  refresh()

  var sortedIds = computed([state], (state) => {
    Object.keys(state).sort((a, b) => {
      return peerListSort(state[a], state[b])
    })
  })

  return mutantMap(sortedIds, state.get)

  function refresh () {
    api.sbot_gossip_peers((err, peers) => {
      peers.forEach(data => {
        var id = legacyToMultiServer(data)
        var current = state.get(id)
        if (!current) {
          current = Peer()
          current.set(data)
          state.put(id, current)
        } else {
          current.set(data)
        }
      })
    })
  }
}

function Peer () {
  var peer = Struct({
    key: Value(),
    ping: Struct({
      rtt: Struct({
        mean: Value()
      }),
      skew: Struct({
        mean: Value()
      })
    }),
    source: Value(),
    state: Value(),
    stateChange: Value()
  })

  return peer
}

<commit_msg>return<commit_after>const fs = require('fs')
// const { isVisible } = require('is-visible')
const h = require('../h')
const human = require('human-time')

const {
  Struct, Value, Dict,
  dictToCollection, map: mutantMap, when, computed
} = require('@mmckegg/mutant')

exports.needs = {
  avatar_image_link: 'first',
  avatar_name_link: 'first',
  sbot_gossip_peers: 'first',
  sbot_gossip_connect: 'first'
}

exports.gives = {
  menu_items: true,
  builtin_tabs: true,
  screen_view: true,
  mcss: true
}

//sbot_gossip_connect
//sbot_gossip_add

function legacyToMultiServer(addr) {
  return 'net:'+addr.host + ':'+addr.port + '~shs:'+addr.key.substring(1).replace('.ed25519','')
}

//on the same wifi network
function isLocal (peer) {
  // don't rely on private ip address, because
  // cjdns creates fake private ip addresses.
  return ip.isPrivate(peer.host) && peer.type === 'local'
}

function getType (peer) {
  return (
      isLongterm(peer)    ? 'modern'
    : isLegacy(peer)      ? 'legacy'
    : isInactive(peer)    ? 'inactive'
    : isUnattempted(peer) ? 'unattempted'
    :                       'other' //should never happen
  )

  //pub is running scuttlebot >=8
  //have connected successfully.
  function isLongterm (peer) {
    return peer.ping && peer.ping.rtt && peer.ping.rtt.mean > 0
  }

  //pub is running scuttlebot < 8
  //have connected sucessfully
  function isLegacy (peer) {
    return /connect/.test(peer.state) || (peer.duration && peer.duration.mean) > 0 && !isLongterm(peer)
  }

  //tried to connect, but failed.
  function isInactive (peer) {
    return peer.stateChange && (peer.duration && peer.duration.mean == 0)
  }

  //havn't tried to connect peer yet.
  function isUnattempted (peer) {
    return !peer.stateChange
  }
}

function origin (peer) {
  return peer.source === 'local' ? 0 : 1
}

function round(n) {
  return Math.round(n*100)/100
}

function duration (s) {
  if(!s) return s
  if (Math.abs(s) > 30000)
    return round(s/60000)+'m'
  else if (Math.abs(s) > 500)
    return round(s/1000)+'s'
  else
    return round(s)+'ms'
}

function peerListSort (a, b) {
  var states = {
    connected: 3,
    connecting: 2
  }

  //types of peers
  var types = {
    modern: 4,
    legacy: 3,
    inactive: 2,
    unattempted: 1,
    other: 0
  }

  return (
    (states[b.state] || 0) - (states[a.state] || 0)
    || origin(b) - origin(a)
    || types[getType(b)] - types[getType(a)]
    || b.stateChange - a.stateChange
  )
}

function formatDate (time) {
  return new Date(time).toString()
}

function humanDate (time) {
  return human(new Date(time)).replace(/minute/, 'min').replace(/second/, 'sec')
}

exports.create = function (api) {

  return {
    menu_items: () => h('a', {href: '#/network'}, '/network'),
    builtin_tabs: () => ['/network'],
    screen_view,
    mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8')
  }

  function screen_view (path) {
    if (path !== '/network') return

    var peers = obs_gossip_peers(api)

    return h('div', { style: {'overflow':'auto'}, className: 'column scroller' }, [
      h('Network', [
        mutantMap(peers, peer => {
          var { key, ping, source, state, stateChange } = peer

          return h('NetworkConnection', [
            h('section.avatar', [
              api.avatar_image_link(key()),
            ]),
            h('section.name', [
              api.avatar_name_link(key()),
            ]),
            h('section.type', [
              computed(peer, getType),
            ]),
            h('section.source', [
              h('label', 'source:'),
              h('code', source)
            ]),
            h('section.state', [
              h('label', 'state:'),
              h('i', {
                className: computed(state, (state) => '-'+state)
              }),
              h('code', when(state, state, 'not connected'))
            ]),
            h('section.actions', [
              h('button', {
                'ev-click': () => {
                  api.sbot_gossip_connect(peer(), (err) => {
                    if(err) console.error(err)
                    else console.log('connected to', peer())
                  })
                }},
                'connect'
              )
            ]),
            h('section.time-ago', [
              h('div',
                { title: computed(stateChange, formatDate) },
                [ computed(stateChange, humanDate) ]
              )
            ]),
            h('section.ping', [
              h('div.rtt', [
                h('label', 'rtt:'),
                h('code', computed(ping.rtt.mean, duration))
              ]),
              h('div.skew', [
                h('label', 'skew:'),
                h('code', computed(ping.skew.mean, duration))
              ]),
            ]),
            h('section.address', [
              h('code', computed(peer, legacyToMultiServer))
            ])
          ])
        })
      ])
    ])
  }
}

function obs_gossip_peers (api) {
  var timer = null
  var state = Dict({}, {
    onListen: () => {
      timer = setInterval(refresh, 5e3)
    },
    onUnlisten: () => {
      clearInterval(timer)
    }
  })

  refresh()

  var sortedIds = computed([state], (state) => {
    return Object.keys(state).sort((a, b) => {
      return peerListSort(state[a], state[b])
    })
  })

  return mutantMap(sortedIds, state.get)

  function refresh () {
    api.sbot_gossip_peers((err, peers) => {
      peers.forEach(data => {
        var id = legacyToMultiServer(data)
        var current = state.get(id)
        if (!current) {
          current = Peer()
          current.set(data)
          state.put(id, current)
        } else {
          current.set(data)
        }
      })
    })
  }
}

function Peer () {
  var peer = Struct({
    key: Value(),
    ping: Struct({
      rtt: Struct({
        mean: Value()
      }),
      skew: Struct({
        mean: Value()
      })
    }),
    source: Value(),
    state: Value(),
    stateChange: Value()
  })

  return peer
}

<|endoftext|>


<commit_before>define([
    'View',
    'announcements/OnSelectionChanged',
    'helpers/converters/ChaptersByYearConverter',
    'views/PieChart',
    'views/LegendChart'
], function(
    View,
    OnSelectionChanged,
    ChaptersByYearConverter,
    PieChart,
    LegendChart
){

    function IcdYearsVisualisations() {
        var _this = new View('

');
        var converter = new ChaptersByYearConverter();
        // 0 identifies regular PieChart visualisation
        // 1 identifies ChaptersByYear Visualisation
        const CHARTIDENTIFIER = 1;

        var man;
        var woman;
        var legend;
        var model;

        /*--------- V I S U A L I S A T I O N S ---------*/
        _this.update = function (selection) {
            var data_man = [];
            var data_woman = [];
            var normalizer = selection.years.length*selection.ages.length;

            converter.convert(selection, function(result) {

                var minEventsWoman = 0;
                var minEventsMan = 0;

                _.each(result.woman, function(value, key) {

                    value = value/normalizer;
                    if(value > 5) {
                        value = Math.round(value*100)/100;
                        data_woman.push({interval: key, amount: value});
                    } else {
                        minEventsWoman += value;
                    }
                });
                data_woman = _.sortBy(data_woman, 'amount').reverse();
                minEventsWoman = Math.round(minEventsWoman*100)/100;
                data_woman.push({interval: "Rest", amount: minEventsWoman});

                _.each(result.man, function(value, key) {

                    value = value/normalizer;
                    if(value > 5) {
                        value = Math.round(value*100)/100;
                        data_man.push({interval: key, amount: value});
                    } else {
                        minEventsMan += value;
                    }
                });
                data_man = _.sortBy(data_man, 'amount').reverse();
                minEventsMan = Math.round(minEventsMan*100)/100;
                data_man.push({interval: "Rest", amount: minEventsMan});

                if(normalizer > 0) {
                    _this.womanChart().openOn(data_woman, CHARTIDENTIFIER);
                    _this.manChart().openOn(data_man, CHARTIDENTIFIER);
                    legend = _this.newLegendChart();
                    var right = _this.newLegend();
                    right.add(legend);
                    _this.add(right);

                    _this.legendChart();
                }
            });
        };

        /**
         * Returns new chart, a subclass of ResponsiveSvg subclass, that is used to visualise women
         * @returns {ResponsiveSvg|View}
         */
        _this.newWomanChart = function () {
            var pieChart = new PieChart(800, 500);
            pieChart.key('interval').value('amount');
            return pieChart;
        };

        /**
         * Returns new chart, a subclass of ResponsiveSvg subclass, that is used to visualise men
         * @returns {ResponsiveSvg|View}
         */
        _this.newManChart = function () {
            var pieChart = new PieChart(800, 500);
            pieChart.key('interval').value('amount');
            return pieChart;
        };

        _this.newLegendChart = function() {
            var legendChart = new LegendChart(800, 700);
            return legendChart;
        };

        /*------------------------------------------------*/

        _this.model = function(_model) {
            if (_.isUndefined(_model)) return model;
            model = _model;
            model.announcer().onSendTo(OnSelectionChanged, _this.onChanged, _this);
            _this.render();
            return _this;
        };

        _this.render = function () {
            woman = _this.newWomanChart();
            man = _this.newManChart();
            //legend = _this.newLegendChart();
            var left = _this.newColumn();
            var middle = _this.newColumn();
            //var right = _this.newLegend();
            left.add(woman);
            middle.add(man);
            //right.add(legend);
            _this.add(left);
            _this.add(middle);
            //_this.add(right);
        };

        _this.manChart = function () {
            return man;
        };

        _this.womanChart = function () {
            return woman;
        };

        _this.legendChart = function () {
            return legend;
        };

        _this.newColumn = function () {
            return new View('

');
        };

        _this.newLegend = function() {
            return new View('

');
        };

        // calls the selection method of IcdYearsModel which returns a JSON
        // of two arrays selectedYears and selectedAges
        _this.onChanged = function() {
            _this.invalidate();
        };

        _this.invalidate = function () {
            _this.update(_this.model().selection());
        };

        return _this;
    }

    return IcdYearsVisualisations;

});<commit_msg>fixed duplication of legend in icd by year<commit_after>define([
    'View',
    'announcements/OnSelectionChanged',
    'helpers/converters/ChaptersByYearConverter',
    'views/PieChart',
    'views/LegendChart'
], function(
    View,
    OnSelectionChanged,
    ChaptersByYearConverter,
    PieChart,
    LegendChart
){

    function IcdYearsVisualisations() {
        var _this = new View('

');
        var converter = new ChaptersByYearConverter();
        // 0 identifies regular PieChart visualisation
        // 1 identifies ChaptersByYear Visualisation
        const CHARTIDENTIFIER = 1;

        var man;
        var woman;
        var legend;
        var right;
        var model;

        /*--------- V I S U A L I S A T I O N S ---------*/
        _this.update = function (selection) {
            var data_man = [];
            var data_woman = [];
            var normalizer = selection.years.length*selection.ages.length;

            converter.convert(selection, function(result) {

                var minEventsWoman = 0;
                var minEventsMan = 0;

                _.each(result.woman, function(value, key) {

                    value = value/normalizer;
                    if(value > 5) {
                        value = Math.round(value*100)/100;
                        data_woman.push({interval: key, amount: value});
                    } else {
                        minEventsWoman += value;
                    }
                });
                data_woman = _.sortBy(data_woman, 'amount').reverse();
                minEventsWoman = Math.round(minEventsWoman*100)/100;
                data_woman.push({interval: "Rest", amount: minEventsWoman});

                _.each(result.man, function(value, key) {

                    value = value/normalizer;
                    if(value > 5) {
                        value = Math.round(value*100)/100;
                        data_man.push({interval: key, amount: value});
                    } else {
                        minEventsMan += value;
                    }
                });
                data_man = _.sortBy(data_man, 'amount').reverse();
                minEventsMan = Math.round(minEventsMan*100)/100;
                data_man.push({interval: "Rest", amount: minEventsMan});

                if(normalizer > 0) {
                    _this.womanChart().openOn(data_woman, CHARTIDENTIFIER);
                    _this.manChart().openOn(data_man, CHARTIDENTIFIER);

                    if (!_.isUndefined(right)) right.remove();
                    legend = _this.newLegendChart();
                    right = _this.newLegend();
                    right.add(legend);
                    _this.add(right);

                    _this.legendChart();
                }
            });
        };

        /**
         * Returns new chart, a subclass of ResponsiveSvg subclass, that is used to visualise women
         * @returns {ResponsiveSvg|View}
         */
        _this.newWomanChart = function () {
            var pieChart = new PieChart(800, 500);
            pieChart.key('interval').value('amount');
            return pieChart;
        };

        /**
         * Returns new chart, a subclass of ResponsiveSvg subclass, that is used to visualise men
         * @returns {ResponsiveSvg|View}
         */
        _this.newManChart = function () {
            var pieChart = new PieChart(800, 500);
            pieChart.key('interval').value('amount');
            return pieChart;
        };

        _this.newLegendChart = function() {
            var legendChart = new LegendChart(800, 700);
            return legendChart;
        };

        /*------------------------------------------------*/

        _this.model = function(_model) {
            if (_.isUndefined(_model)) return model;
            model = _model;
            model.announcer().onSendTo(OnSelectionChanged, _this.onChanged, _this);
            _this.render();
            return _this;
        };

        _this.render = function () {
            woman = _this.newWomanChart();
            man = _this.newManChart();
            //legend = _this.newLegendChart();
            var left = _this.newColumn();
            var middle = _this.newColumn();
            //var right = _this.newLegend();
            left.add(woman);
            middle.add(man);
            //right.add(legend);
            _this.add(left);
            _this.add(middle);
            //_this.add(right);
        };

        _this.manChart = function () {
            return man;
        };

        _this.womanChart = function () {
            return woman;
        };

        _this.legendChart = function () {
            return legend;
        };

        _this.newColumn = function () {
            return new View('

');
        };

        _this.newLegend = function() {
            return new View('

');
        };

        // calls the selection method of IcdYearsModel which returns a JSON
        // of two arrays selectedYears and selectedAges
        _this.onChanged = function() {
            _this.invalidate();
        };

        _this.invalidate = function () {
            _this.update(_this.model().selection());
        };

        return _this;
    }

    return IcdYearsVisualisations;

});<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import Warning from '../components/warning';
import { createSelector } from 'reselect';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';

const getMentionedUsernames = createSelector(state => state.getIn(['compose', 'text']), text => text.match(/(?:^|[^\/\w])@([a-z0-9_]+@[a-z0-9\.\-]+)/ig));

const getMentionedDomains = createSelector(getMentionedUsernames, mentionedUsernamesWithDomains => {
  return mentionedUsernamesWithDomains !== null ? [...new Set(mentionedUsernamesWithDomains.map(item => item.split('@')[2]))] : [];
});

const mapStateToProps = state => {
  const mentionedUsernames = getMentionedUsernames(state);
  const mentionedUsernamesWithDomains = getMentionedDomains(state);

  return {
    needsLeakWarning: (state.getIn(['compose', 'privacy']) === 'private' || state.getIn(['compose', 'privacy']) === 'direct') && mentionedUsernames !== null,
    mentionedDomains: mentionedUsernamesWithDomains,
    needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', state.getIn(['meta', 'me']), 'locked'])
  };
};

const WarningWrapper = ({ needsLeakWarning, needsLockWarning, mentionedDomains }) => {
  if (needsLockWarning) {
    return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /> }} />} />;
  } else if (needsLeakWarning) {
    return (
      <Warning
        message={<FormattedMessage
          id='compose_form.privacy_disclaimer'
          defaultMessage='Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.'
          values={{ domains: {mentionedDomains.join(', ')}, domainsCount: mentionedDomains.length }}
        />}
      />
    );
  }

  return null;
};

WarningWrapper.propTypes = {
  needsLeakWarning: PropTypes.bool,
  needsLockWarning: PropTypes.bool,
  mentionedDomains: PropTypes.array.isRequired,
};

export default connect(mapStateToProps)(WarningWrapper);
<commit_msg>Fix #2725 (#2774)<commit_after>import React from 'react';
import { connect } from 'react-redux';
import Warning from '../components/warning';
import { createSelector } from 'reselect';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { OrderedSet } from 'immutable';

const getMentionedUsernames = createSelector(state => state.getIn(['compose', 'text']), text => text.match(/(?:^|[^\/\w])@([a-z0-9_]+@[a-z0-9\.\-]+)/ig));

const getMentionedDomains = createSelector(getMentionedUsernames, mentionedUsernamesWithDomains => {
  return OrderedSet(mentionedUsernamesWithDomains !== null ? mentionedUsernamesWithDomains.map(item => item.split('@')[2]) : []);
});

const mapStateToProps = state => {
  const mentionedUsernames = getMentionedUsernames(state);
  const mentionedUsernamesWithDomains = getMentionedDomains(state);

  return {
    needsLeakWarning: (state.getIn(['compose', 'privacy']) === 'private' || state.getIn(['compose', 'privacy']) === 'direct') && mentionedUsernames !== null,
    mentionedDomains: mentionedUsernamesWithDomains,
    needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', state.getIn(['meta', 'me']), 'locked'])
  };
};

const WarningWrapper = ({ needsLeakWarning, needsLockWarning, mentionedDomains }) => {
  if (needsLockWarning) {
    return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /> }} />} />;
  } else if (needsLeakWarning) {
    return (
      <Warning
        message={<FormattedMessage
          id='compose_form.privacy_disclaimer'
          defaultMessage='Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.'
          values={{ domains: {mentionedDomains.join(', ')}, domainsCount: mentionedDomains.size }}
        />}
      />
    );
  }

  return null;
};

WarningWrapper.propTypes = {
  needsLeakWarning: PropTypes.bool,
  needsLockWarning: PropTypes.bool,
  mentionedDomains: PropTypes.array.isRequired,
};

export default connect(mapStateToProps)(WarningWrapper);
<|endoftext|>


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

    angular
        .module('smn-ui')
        .directive('uiMaskCnpj', uiMaskCnpj);

    function uiMaskCnpj(uiCnpjFilter, $timeout) {
        var directive = {
            restrict: 'A',
            link: link,
            require: 'ngModel'
        };
        return directive;

        function link(scope, element, attrs, ctrl) {
            var beforeSelIndex, afterSelIndex, futureSelIndex;

            element.on('keydown', function () {
                beforeSelIndex = doGetCaretPosition(element[0]);
            });

            ctrl.$parsers.push(function(value){
                afterSelIndex = doGetCaretPosition(element[0]);

                var viewValue = uiCnpjFilter(value);
                ctrl.$setViewValue(viewValue);
                ctrl.$render();

                if (element[0].selectionStart || element[0].selectionStart == '0') {
                    switch (true) {
                        case beforeSelIndex == 2 && afterSelIndex == 3:
                            futureSelIndex = 4;
                            break;
                        case beforeSelIndex == 6 && afterSelIndex == 7:
                            futureSelIndex = 8;
                            break;
                        case beforeSelIndex == 10 && afterSelIndex == 11:
                            futureSelIndex = 12;
                            break;
                        case beforeSelIndex == 15 && afterSelIndex == 16:
                            futureSelIndex = 17;
                            break;
                        default:
                            futureSelIndex = afterSelIndex;
                    }
                    setCaretPosition(element[0], futureSelIndex);
                    $timeout(function () {
                        setCaretPosition(element[0], futureSelIndex);
                    });
                }

                if (viewValue.length === 18)
                    return viewValue.replace(/[^0-9]+/g, '');
                if (!viewValue)
                    return '';
            });

            ctrl.$formatters.push(function(value){
                if (value) value = ("00000000000000" + value).substring((14 + value.length) - 14);
                return uiCnpjFilter(value);
            });

            function doGetCaretPosition(elem) {
                var caretPos = 0;
                // IE Support
                if (document.selection) {
                    elem.focus();
                    var sel = document.selection.createRange();
                    sel.moveStart('character', -elem.value.length);
                    caretPos = sel.text.length;
                }
                // Firefox support
                else if (elem.selectionStart || elem.selectionStart == '0') {
                    caretPos = elem.selectionStart;
                }

                return caretPos;

            }

            function setCaretPosition(elem, caretPos) {
                if (elem != null) {
                    if (elem.createTextRange) {
                        var range = elem.createTextRange();
                        range.move('character', caretPos);
                        range.select();
                    }
                    else {
                        if (elem.selectionStart) {
                            elem.focus();
                            elem.setSelectionRange(caretPos, caretPos);
                        }
                        else {
                            elem.focus();
                        }
                    }
                }
            }
        }
    }

})();<commit_msg>Atualizações<commit_after>(function () {
    'use strict';

    angular
        .module('smn-ui')
        .directive('uiMaskCnpj', uiMaskCnpj);

    function uiMaskCnpj(uiCnpjFilter, $timeout) {
        var directive = {
            restrict: 'A',
            link: link,
            require: 'ngModel'
        };
        return directive;

        function link(scope, element, attrs, ctrl) {
            var beforeSelIndex, afterSelIndex, futureSelIndex;

            element.on('keydown', function () {
                beforeSelIndex = doGetCaretPosition(element[0]);
            });

            ctrl.$parsers.push(function(value){
                afterSelIndex = doGetCaretPosition(element[0]);

                var viewValue = uiCnpjFilter(value);
                ctrl.$setViewValue(viewValue);
                ctrl.$render();

                if (element[0].selectionStart || element[0].selectionStart == '0') {
                    switch (true) {
                        case beforeSelIndex == 2 && afterSelIndex == 3:
                            futureSelIndex = 4;
                            break;
                        case beforeSelIndex == 6 && afterSelIndex == 7:
                            futureSelIndex = 8;
                            break;
                        case beforeSelIndex == 10 && afterSelIndex == 11:
                            futureSelIndex = 12;
                            break;
                        case beforeSelIndex == 15 && afterSelIndex == 16:
                            futureSelIndex = 17;
                            break;
                        default:
                            futureSelIndex = afterSelIndex;
                    }
                    setCaretPosition(element[0], futureSelIndex);
                    $timeout(function () {
                        setCaretPosition(element[0], futureSelIndex);
                    });
                }

                if (viewValue.length === 18)
                    return viewValue.replace(/[^0-9]+/g, '');
                if (!viewValue)
                    return '';
            });

            ctrl.$formatters.push(function(value){
                if (value) value = ("00000000000000" + value).substring((14 + value.length) - 14);
                return uiCnpjFilter(value);
            });

            function doGetCaretPosition(elem) {
                var caretPos = 0;
                // IE Support
                if (document.selection) {
                    elem.focus();
                    var sel = document.selection.createRange();
                    sel.moveStart('character', -elem.value.length);
                    caretPos = sel.text.length;
                }
                // Firefox support
                else if (elem.selectionStart || elem.selectionStart == '0') {
                    caretPos = elem.selectionStart;
                }

                return caretPos;
            }

            function setCaretPosition(elem, caretPos) {
                if (elem != null) {
                    if (elem.createTextRange) {
                        var range = elem.createTextRange();
                        range.move('character', caretPos);
                        range.select();
                    }
                    else {
                        if (elem.selectionStart) {
                            elem.focus();
                            elem.setSelectionRange(caretPos, caretPos);
                        }
                        else {
                            elem.focus();
                        }
                    }
                }
            }
        }
    }

})();<|endoftext|>


<commit_before>ngapp.directive('settingsModal', function () {
    return {
        restrict: 'E',
        templateUrl: 'directives/settingsModal.html',
        controller: 'settingsModalController',
        scope: false
    }
});

ngapp.controller('settingsModalController', function($scope, formUtils, settingsService) {
    // inherited functions
    $scope.unfocusSettingsModal = formUtils.unfocusModal($scope.saveSettings);

    // initialize scope variables
    $scope.settings = settingsService.settings;
    $scope.profileName = settingsService.currentProfile;
    $scope.tabs = settingsService.getTabs();
    $scope.currentTab = $scope.tabs[0];
    $scope.currentTab.selected = true;

    // scope functions
    $scope.onTabClick = function(e, tab) {
        e.stopPropagation();
        if (tab === $scope.currentTab) return;
        $scope.currentTab.selected = false;
        $scope.currentTab = tab;
        $scope.currentTab.selected = true;
    };

    $scope.saveSettings = function() {
        settingsService.saveSettings($scope.settings);
        $scope.toggleSettingsModal();
    };
});
<commit_msg>improved tab selection logic on settings modal<commit_after>ngapp.directive('settingsModal', function () {
    return {
        restrict: 'E',
        templateUrl: 'directives/settingsModal.html',
        controller: 'settingsModalController',
        scope: false
    }
});

ngapp.controller('settingsModalController', function($scope, formUtils, settingsService) {
    // inherited functions
    $scope.unfocusSettingsModal = formUtils.unfocusModal($scope.saveSettings);

    // helper function
    let selectTab = function(tab) {
        $scope.tabs.forEach((tab) => tab.selected = false);
        $scope.currentTab = tab;
        $scope.currentTab.selected = true;
    };

    // initialize scope variables
    $scope.settings = settingsService.settings;
    $scope.profileName = settingsService.currentProfile;
    $scope.tabs = settingsService.getTabs();
    selectTab($scope.tabs[0]);

    // scope functions
    $scope.onTabClick = function(e, tab) {
        e.stopPropagation();
        if (tab === $scope.currentTab) return;
        selectTab(tab);
    };

    $scope.saveSettings = function() {
        settingsService.saveSettings();
        $scope.toggleSettingsModal();
    };
});
<|endoftext|>


<commit_before>/**
 * Created by danielhollcraft on 4/11/17.
 */

import React, {
  PropTypes,
  Component,
} from 'react';

import Helmet from 'react-helmet'

import {
  Col,
  Row,
  Grid,
  Form,
  FormControl,
  FormGroup,
  ControlLabel,
  Button
} from 'react-bootstrap'
import { config } from 'config'

import './index.scss'

class Contact extends Component {

  constructor(props) {
    super(props);
    this.state = {
      submitPress: false,
      email: '',
      name: '',
      message: ''
    };
  }

  submit (evt) {
    evt.preventDefault();
    this.setState({
      submitPressed: true
    });

    if(this.isFormValid()) {
      console.log("can submit form")
    }
  }

  handleEmailChange(evt) {
    this.setState({email: evt.target.value});
  }

  handleNameChange(evt) {
    this.setState({name: evt.target.value});
  }

  handleMessageChange(evt) {
    this.setState({message: evt.target.value});
  }

  isValidEmail() {
     return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(this.state.email);
  }

  getEmailValidationState() {
    return (!this.isValidEmail() || this.state.email === '') && this.state.submitPressed ? 'error' : null
  }

  getTextFieldValidationState(fieldValue) { return fieldValue === '' && this.state.submitPressed ? 'error' : null }

  isFormValid() {
    return this.state.message !== "" && this.state.name !== "" && this.state.email !== "" && this.isValidEmail()
  }

  render() {
    return (

        <Helmet
          title={config.siteTitle}
          meta={[
            {"name": "description", "content": "Blog"},
            {"name": "keywords", "content": "sample, something"},
          ]}
        />
        <Grid>
          <Row>
            <Col xs={12} sm={12} md={12} lg={12} >

                <Form horizontal>
                  <FormGroup controlId="formHorizontalEmail" validationState={this.getEmailValidationState()}>
                    <Col componentClass={ControlLabel} sm={2}>
                      Email
                    </Col>
                    <Col sm={10}>
                      <FormControl
                        type="email"
                        placeholder="Email"
                        value={this.state.email}
                        onChange={this.handleEmailChange.bind(this)}
                      />
                      <FormControl.Feedback />
                    </Col>
                  </FormGroup>
                  <FormGroup controlId="formHorizontalName"
                             validationState={this.getTextFieldValidationState(this.state.name)}
                  >
                    <Col componentClass={ControlLabel} sm={2}>
                      Name
                    </Col>
                    <Col sm={10}>
                      <FormControl type="text" placeholder="Name"
                                   value={this.state.name}
                                   onChange={this.handleNameChange.bind(this)}
                      />
                      <FormControl.Feedback />
                    </Col>
                  </FormGroup>
                  <FormGroup controlId="formHorizontalMessage"
                             validationState={this.getTextFieldValidationState(this.state.message)}
                  >
                    <Col componentClass={ControlLabel} sm={2}>
                      Message
                    </Col>
                    <Col sm={10}>
                      <FormControl componentClass="textarea" placeholder="Your message..."
                                   value={this.state.message}
                                   onChange={this.handleMessageChange.bind(this)} />
                      <FormControl.Feedback />
                    </Col>
                  </FormGroup>
                  <FormGroup>
                    <Col smOffset={2} sm={10}>
                      <Button bsStyle="success" bsSize="large" type="submit" onClick={this.submit.bind(this)}>
                        Send
                      </Button>
                    </Col>
                  </FormGroup>
                </Form>

            </Col>
          </Row>
        </Grid>

    );
  }
}

Contact.propTypes = {};
Contact.defaultProps = {};

export default Contact;<commit_msg>adding form submit<commit_after>/**
 * Created by danielhollcraft on 4/11/17.
 */

import React, {
  PropTypes,
  Component,
} from 'react';

import Helmet from 'react-helmet'

import {
  Col,
  Row,
  Grid,
  Form,
  FormControl,
  FormGroup,
  ControlLabel,
  Button
} from 'react-bootstrap'
import { config } from 'config'

import './index.scss'

class Contact extends Component {

  constructor(props) {
    super(props);
    this.state = {
      submitPress: false,
      email: '',
      name: '',
      message: ''
    };
  }

  submit (evt) {
    evt.preventDefault();
    this.setState({
      submitPressed: true
    });

    if(this.isFormValid()) {

      const body = {
        email: this.state.email,
        name: this.state.name,
        message: this.state.message
      };

      fetch("localhost:8080/", {
        method: "POST",
        body,
        headers: {
          'Content-Type': 'x-www-form-urlggitencoded'
        }
      });
    }
  }

  handleEmailChange(evt) {
    this.setState({email: evt.target.value});
  }

  handleNameChange(evt) {
    this.setState({name: evt.target.value});
  }

  handleMessageChange(evt) {
    this.setState({message: evt.target.value});
  }

  isValidEmail() {
     return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(this.state.email);
  }

  getEmailValidationState() {
    return (!this.isValidEmail() || this.state.email === '') && this.state.submitPressed ? 'error' : null
  }

  getTextFieldValidationState(fieldValue) { return fieldValue === '' && this.state.submitPressed ? 'error' : null }

  isFormValid() {
    return this.state.message !== "" && this.state.name !== "" && this.state.email !== "" && this.isValidEmail()
  }

  render() {
    return (

        <Helmet
          title={config.siteTitle}
          meta={[
            {"name": "description", "content": "Blog"},
            {"name": "keywords", "content": "sample, something"},
          ]}
        />
        <Grid>
          <Row>
            <Col xs={12} sm={12} md={12} lg={12} >

                <Form horizontal>
                  <FormGroup controlId="formHorizontalEmail" validationState={this.getEmailValidationState()}>
                    <Col componentClass={ControlLabel} sm={2}>
                      Email
                    </Col>
                    <Col sm={10}>
                      <FormControl
                        type="email"
                        placeholder="Email"
                        value={this.state.email}
                        onChange={this.handleEmailChange.bind(this)}
                      />
                      <FormControl.Feedback />
                    </Col>
                  </FormGroup>
                  <FormGroup controlId="formHorizontalName"
                             validationState={this.getTextFieldValidationState(this.state.name)}
                  >
                    <Col componentClass={ControlLabel} sm={2}>
                      Name
                    </Col>
                    <Col sm={10}>
                      <FormControl type="text" placeholder="Name"
                                   value={this.state.name}
                                   onChange={this.handleNameChange.bind(this)}
                      />
                      <FormControl.Feedback />
                    </Col>
                  </FormGroup>
                  <FormGroup controlId="formHorizontalMessage"
                             validationState={this.getTextFieldValidationState(this.state.message)}
                  >
                    <Col componentClass={ControlLabel} sm={2}>
                      Message
                    </Col>
                    <Col sm={10}>
                      <FormControl componentClass="textarea" placeholder="Your message..."
                                   value={this.state.message}
                                   onChange={this.handleMessageChange.bind(this)} />
                      <FormControl.Feedback />
                    </Col>
                  </FormGroup>
                  <FormGroup>
                    <Col smOffset={2} sm={10}>
                      <Button bsStyle="success" bsSize="large" type="submit" onClick={this.submit.bind(this)}>
                        Send
                      </Button>
                    </Col>
                  </FormGroup>
                </Form>

            </Col>
          </Row>
        </Grid>

    );
  }
}

Contact.propTypes = {};
Contact.defaultProps = {};

export default Contact;<|endoftext|>