<commit_before>//META{"name":"CompactGuilds"}*//

'use strict';
var CompactGuilds = function () {};
CompactGuilds.prototype.getAuthor = function () {
	return "kosshi";
};
CompactGuilds.prototype.getName = function () {
	return "CompactGuilds";
};
CompactGuilds.prototype.getDescription = function () {
	return "Reduces sidebar's width or hides it completetly by displaying it only when cursor is near left edge. ";
};
CompactGuilds.prototype.getVersion = function () {
	return "0.1.8";
};

CompactGuilds.prototype.windowResizeEvent = function() {
	// Called when window is resized.
	var settings = CompactGuilds.prototype.loadSettings();
	var plugin = BdApi.getPlugin('CompactGuilds');
	if(settings.always) {
		plugin.enable();
		return;
	}
	if(window.innerWidth < settings.activeWidth){
		if(!plugin.enabled) plugin.enable();
	}else{
		if(plugin.enabled) plugin.disable();
	}
};

CompactGuilds.prototype.enabled = false; // if guilds are hidden

CompactGuilds.prototype.start = function () {
	// Called when plugin is started
	window.addEventListener('resize',this.windowResizeEvent,false);
	this.windowResizeEvent();
};

CompactGuilds.prototype.enable = function() {
	// Hides guilds
	if(this.enabled) return;
	this.enabled = true;
	var settings = this.loadSettings();

	var guilds = document.getElementsByClassName('guilds-wrapper')[0];
	var main = document.getElementsByClassName('flex-horizontal flex-spacer')[0];
	var channels = document.getElementsByClassName('flex-vertical channels-wrap')[0];

	if(settings.trim){
		var accountName = document.getElementsByClassName('username')[0];
		accountName.style.maxWidth = "40px";
		channels.style.width = '200px';
	}

	var guildsHide = true;
	var overGuilds = document.createElement('div');
	overGuilds.id = 'hg_hoverOver';
	main.appendChild(overGuilds);
	var outGuilds = document.createElement('div');
	outGuilds.id = 'hg_hoverOut';
	main.appendChild(outGuilds);

	$('#hg_hoverOver').css({
		"position":"absolute",
		"height":"100%",
		"width": settings.show+"px",
		"left":"0"
	});
	$('#hg_hoverOut').css({
		"position": "fixed",
		"height": "100%",
		"left": settings.hide+"px",
		"overflowX": "hidden",
		"overflowY": "hidden",
		"width": "80%",
		"zIndex": "9001",
		"display": "none"
	});
	$('.guilds-wrapper').css({
		"position": "fixed",
		"height": "100%",
		"zIndex": "3",
		"left": "-80px",
		"transition": settings.animstyle +" "+settings.animspeed+"ms"
	});
	if(settings.mobilefy){
		$('.channels-wrap').css({
			"position": "fixed",
			"height": "100%",
			"zIndex": "2",
			"left": "-240px",
			"transition": settings.animstyle +" "+settings.animspeed+"ms"
		});
	}

	overGuilds.onmouseover = function(){
		guildsHide = false;
		outGuilds.style.display = "block";
		guilds.style.left = "0px";
		if(settings.mobilefy){
			// fix for minimal mode
			channels.style.left = ($("body").hasClass("bd-minimal")) ? "40px" : "80px";
		}
	};
	outGuilds.onmouseover = function(){
		guildsHide = true;
		outGuilds.style.display = "none";
		guilds.style.left = "-80px";
		if(settings.mobilefy){
			channels.style.left = "-240px";
		}
	};
};
CompactGuilds.prototype.stop = function () {
	// Called when plugin is disabled
	window.removeEventListener('resize',this.windowResizeEvent,false);
	this.disable();
};

CompactGuilds.prototype.disable = function(){
	// Permashows guilds
	if(!this.enabled) return;
	this.enabled = false;
	var guilds = document.getElementsByClassName('guilds-wrapper')[0];
	var channels = document.getElementsByClassName('flex-vertical channels-wrap')[0];
	var accountName = document.getElementsByClassName('username')[0];
	var overGuilds = document.getElementById('hg_hoverOver');
	var outGuilds = document.getElementById('hg_hoverOut');
	overGuilds.parentNode.removeChild(overGuilds);
	outGuilds.parentNode.removeChild(outGuilds);
	guilds.style = {};
	channels.style = {};
	accountName.style.maxWidth = "";
	channels.style.width = "";
};

// Unused
CompactGuilds.prototype.load = function () {};
CompactGuilds.prototype.unload = function () {};
CompactGuilds.prototype.onMessage = function () {};
CompactGuilds.prototype.onSwitch = function () {};
CompactGuilds.prototype.observer = function () {};

// ========
// SETTINGS
// ========

CompactGuilds.prototype.settingsVersion = 10;
	// Changing this value causes old versions of settings to be resetted.
CompactGuilds.prototype.defaultSettings = function () {
	// Returns default settings
	return {
		version: this.settingsVersion,
		show:30, 				// Min cursor distance (px) from left edge to view the sidebar
		hide:300, 				// Cursor distance (px) from left edge to hide the sidebar again
		trim:true,				// Edit channel css to make it slimmer
		activeWidth: 1000,		// Plugin activation threshold
		always: false,			// Ignore activeWidth, keep the bar hidden always
		mobilefy: true,			// Hide channels too. (Originally this plugin only hid the guilds)
		animspeed:200,			// Animation speed in milliseconds
		animstyle:"Linear"		// Animation style
	};
};

CompactGuilds.prototype.loadSettings = function() {
	// Loads settings from localstorage
	var settings = (localStorage.CompactGuilds) ? JSON.parse(localStorage.CompactGuilds) : {version:"0"};
	if(settings.version != this.settingsVersion){
		console.log('[CompactGuilds] Settings were outdated/invalid/nonexistent. Using default settings.');
		settings = this.defaultSettings();
		localStorage.CompactGuilds = JSON.stringify(settings);
	}
	return settings;
};

CompactGuilds.prototype.resetSettings = function (button) {
	// Set settings to default and restarts the plugin
	var settings = this.defaultSettings();
	localStorage.CompactGuilds = JSON.stringify(settings);
	this.stop();
	this.start();
	button.innerHTML = "Settings resetted!";
	setTimeout(function(){button.innerHTML = "Reset settings";},1000);
};

CompactGuilds.prototype.saveSettings = function (button) {
	// Saves settings from setting panel
	var settings = this.loadSettings();
	settings.animspeed = document.getElementById('hg_animspeed').value;
	settings.animstyle = document.getElementById('hg_animstyle').value;
	settings.show = document.getElementById('hg_show').value;
	settings.hide = document.getElementById('hg_hide').value;
	settings.trim = document.getElementById('hg_trim').checked;
	settings.always = document.getElementById('hg_always').checked;
	settings.mobilefy = document.getElementById('hg_mobilefy').checked;
	settings.activeWidth = document.getElementById('hg_activeWidth').value;

	localStorage.CompactGuilds = JSON.stringify(settings);

	this.stop();
	this.start();

	button.innerHTML = "Saved and applied!";
	setTimeout(function(){button.innerHTML = "Save and apply";},1000);
};

CompactGuilds.prototype.getSettingsPanel = function () {
	// ???
	var settings = this.loadSettings();
	var html = "
Settings Panel

";
	html += "Animation speed
";
	html +=	"<input id='hg_animspeed' type='number'value=" + (settings.animspeed) + "> milliseconds

";

	html += "Animation style
";
	html += "<select id='hg_animstyle'>";
	var a = ['Linear','Ease','Ease-in','Ease-out','Ease-in-out'];
	for (var i = 0; i < a.length; i++) {
		html += "<option value='"+a[i]+"'"+((settings.animstyle==a[i])? "selected":"")+">"+a[i];
	}
	html += "</select>

";

	html += "Show distance
";
	html += "<input id='hg_show' type='number' value=" +settings.show+ "> pixels

";

	html += "Hide distance
";
	html +=	"<input id='hg_hide' type='number' value=" +settings.hide+ "> pixels

";

	html += "Max window size to enable compact guilds
";
	html += "<input id='hg_activeWidth' type='number' value=" +settings.activeWidth+ "> pixels

";

	html += "<input type='checkbox' id='hg_always'";
	html += (settings.always) ? " checked>" : ">";
	html += "Enable guild hiding always
";

	html += "<input type='checkbox' id='hg_trim'";
	html += (settings.trim) ? " checked>" : ">";
	html += "Make channels thinner
";

	html += "<input type='checkbox' id='hg_mobilefy'";
	html += (settings.mobilefy) ? " checked>" : ">";
	html += "Hide channels too
";

	html +="
<button onclick='BdApi.getPlugin(\"CompactGuilds\").saveSettings(this)'>Save and apply</button>";
	html +="<button onclick='BdApi.getPlugin(\"CompactGuilds\").resetSettings(this)'>Reset settings</button>

";

	html += "If your hide distance is too low you might not be able to access the settings panel. Use CTRL+COMMA (,) if this happens.";
	return html;
};
<commit_msg>Fixes for minimal mode<commit_after>//META{"name":"CompactGuilds"}*//

'use strict';
var CompactGuilds = function () {};
CompactGuilds.prototype.getAuthor = function () {
	return "kosshi";
};
CompactGuilds.prototype.getName = function () {
	return "CompactGuilds";
};
CompactGuilds.prototype.getDescription = function () {
	return "Reduces sidebar's width or hides it completetly by displaying it only when cursor is near left edge. ";
};
CompactGuilds.prototype.getVersion = function () {
	return "0.1.8";
};

CompactGuilds.prototype.windowResizeEvent = function() {
	// Called when window is resized.
	var settings = CompactGuilds.prototype.loadSettings();
	var plugin = BdApi.getPlugin('CompactGuilds');
	if(settings.always) {
		plugin.enable();
		return;
	}
	if(window.innerWidth < settings.activeWidth){
		if(!plugin.enabled) plugin.enable();
	}else{
		if(plugin.enabled) plugin.disable();
	}
};

CompactGuilds.prototype.enabled = false; // if guilds are hidden

CompactGuilds.prototype.start = function () {
	// Called when plugin is started
	window.addEventListener('resize',this.windowResizeEvent,false);
	this.windowResizeEvent();
};

CompactGuilds.prototype.enable = function() {
	// Hides guilds
	if(this.enabled) return;
	this.enabled = true;
	var settings = this.loadSettings();

	var guilds = document.getElementsByClassName('guilds-wrapper')[0];
	var main = document.getElementsByClassName('flex-horizontal flex-spacer')[0];
	var channels = document.getElementsByClassName('flex-vertical channels-wrap')[0];

	if(settings.trim){
		var accountName = document.getElementsByClassName('username')[0];
		accountName.style.maxWidth = "45px";
		channels.style.width = '200px';
	}

	var guildsHide = true;
	var overGuilds = document.createElement('div');
	overGuilds.id = 'hg_hoverOver';
	main.appendChild(overGuilds);
	var outGuilds = document.createElement('div');
	outGuilds.id = 'hg_hoverOut';
	main.appendChild(outGuilds);

	$('#hg_hoverOver').css({
		"position":"absolute",
		"height":"100%",
		"width": settings.show+"px",
		"left":"0"
	});
	$('#hg_hoverOut').css({
		"position": "fixed",
		"height": "100%",
		"left": settings.hide+"px",
		"overflowX": "hidden",
		"overflowY": "hidden",
		"width": "80%",
		"zIndex": "9001",
		"display": "none"
	});
	$('.guilds-wrapper').css({
		"position": "fixed",
		"height": "100%",
		"zIndex": "3",
		"left": "-80px",
		"transition": settings.animstyle +" "+settings.animspeed+"ms"
	});
	if(settings.mobilefy){
		$('.channels-wrap').css({
			"position": "fixed",
			"height": "100%",
			"zIndex": "2",
			"left": "-240px",
			"transition": settings.animstyle +" "+settings.animspeed+"ms"
		});
	}

	overGuilds.onmouseover = function(){
		guildsHide = false;
		outGuilds.style.display = "block";
		guilds.style.left = "0px";
		if(settings.mobilefy){
			// fix for minimal mode
			channels.style.left = ($("body").hasClass("bd-minimal")) ? "40px" : "80px";
		}
	};
	outGuilds.onmouseover = function(){
		guildsHide = true;
		outGuilds.style.display = "none";
		guilds.style.left = "-80px";
		if(settings.mobilefy){
			channels.style.left = "-240px";
		}
	};
};
CompactGuilds.prototype.stop = function () {
	// Called when plugin is disabled
	window.removeEventListener('resize',this.windowResizeEvent,false);
	this.disable();
};

CompactGuilds.prototype.disable = function(){
	// Permashows guilds
	if(!this.enabled) return;
	this.enabled = false;
	var guilds = document.getElementsByClassName('guilds-wrapper')[0];
	var channels = document.getElementsByClassName('flex-vertical channels-wrap')[0];
	var accountName = document.getElementsByClassName('username')[0];
	var overGuilds = document.getElementById('hg_hoverOver');
	var outGuilds = document.getElementById('hg_hoverOut');
	overGuilds.parentNode.removeChild(overGuilds);
	outGuilds.parentNode.removeChild(outGuilds);
	guilds.style = {};
	channels.style = {};
	accountName.style.maxWidth = "";
	channels.style.width = "";
};

// Unused
CompactGuilds.prototype.load = function () {};
CompactGuilds.prototype.unload = function () {};
CompactGuilds.prototype.onMessage = function () {};
CompactGuilds.prototype.onSwitch = function () {};
CompactGuilds.prototype.observer = function () {};

// ========
// SETTINGS
// ========

CompactGuilds.prototype.settingsVersion = 10;
	// Changing this value causes old versions of settings to be resetted.
CompactGuilds.prototype.defaultSettings = function () {
	// Returns default settings
	return {
		version: this.settingsVersion,
		show:30, 				// Min cursor distance (px) from left edge to view the sidebar
		hide:300, 				// Cursor distance (px) from left edge to hide the sidebar again
		trim:true,				// Edit channel css to make it slimmer
		activeWidth: 1000,		// Plugin activation threshold
		always: false,			// Ignore activeWidth, keep the bar hidden always
		mobilefy: true,			// Hide channels too. (Originally this plugin only hid the guilds)
		animspeed:200,			// Animation speed in milliseconds
		animstyle:"Linear"		// Animation style
	};
};

CompactGuilds.prototype.loadSettings = function() {
	// Loads settings from localstorage
	var settings = (localStorage.CompactGuilds) ? JSON.parse(localStorage.CompactGuilds) : {version:"0"};
	if(settings.version != this.settingsVersion){
		console.log('[CompactGuilds] Settings were outdated/invalid/nonexistent. Using default settings.');
		settings = this.defaultSettings();
		localStorage.CompactGuilds = JSON.stringify(settings);
	}
	return settings;
};

CompactGuilds.prototype.resetSettings = function (button) {
	// Set settings to default and restarts the plugin
	var settings = this.defaultSettings();
	localStorage.CompactGuilds = JSON.stringify(settings);
	this.stop();
	this.start();
	button.innerHTML = "Settings resetted!";
	setTimeout(function(){button.innerHTML = "Reset settings";},1000);
};

CompactGuilds.prototype.saveSettings = function (button) {
	// Saves settings from setting panel
	var settings = this.loadSettings();
	settings.animspeed = document.getElementById('hg_animspeed').value;
	settings.animstyle = document.getElementById('hg_animstyle').value;
	settings.show = document.getElementById('hg_show').value;
	settings.hide = document.getElementById('hg_hide').value;
	settings.trim = document.getElementById('hg_trim').checked;
	settings.always = document.getElementById('hg_always').checked;
	settings.mobilefy = document.getElementById('hg_mobilefy').checked;
	settings.activeWidth = document.getElementById('hg_activeWidth').value;

	localStorage.CompactGuilds = JSON.stringify(settings);

	this.stop();
	this.start();

	button.innerHTML = "Saved and applied!";
	setTimeout(function(){button.innerHTML = "Save and apply";},1000);
};

CompactGuilds.prototype.getSettingsPanel = function () {
	// ???
	var settings = this.loadSettings();
	var html = "
Settings Panel

";
	html += "Animation speed
";
	html +=	"<input id='hg_animspeed' type='number'value=" + (settings.animspeed) + "> milliseconds

";

	html += "Animation style
";
	html += "<select id='hg_animstyle'>";
	var a = ['Linear','Ease','Ease-in','Ease-out','Ease-in-out'];
	for (var i = 0; i < a.length; i++) {
		html += "<option value='"+a[i]+"'"+((settings.animstyle==a[i])? "selected":"")+">"+a[i];
	}
	html += "</select>

";

	html += "Show distance
";
	html += "<input id='hg_show' type='number' value=" +settings.show+ "> pixels

";

	html += "Hide distance
";
	html +=	"<input id='hg_hide' type='number' value=" +settings.hide+ "> pixels

";

	html += "Max window size to enable compact guilds
";
	html += "<input id='hg_activeWidth' type='number' value=" +settings.activeWidth+ "> pixels

";

	html += "<input type='checkbox' id='hg_always'";
	html += (settings.always) ? " checked>" : ">";
	html += "Enable guild hiding always
";

	html += "<input type='checkbox' id='hg_trim'";
	html += (settings.trim) ? " checked>" : ">";
	html += "Make channels thinner
";

	html += "<input type='checkbox' id='hg_mobilefy'";
	html += (settings.mobilefy) ? " checked>" : ">";
	html += "Hide channels too
";

	html +="
<button onclick='BdApi.getPlugin(\"CompactGuilds\").saveSettings(this)'>Save and apply</button>";
	html +="<button onclick='BdApi.getPlugin(\"CompactGuilds\").resetSettings(this)'>Reset settings</button>

";

	html += "If your hide distance is too low you might not be able to access the settings panel. Use CTRL+COMMA (,) if this happens.";
	return html;
};
<|endoftext|>


<commit_before>function home()
{
	parentPathA=path.split("assets");
	parentPath=""
	for(i=0; i<parentPathA.length-1; i++)
	{
		parentPath+=parentPathA[i]
		if(i!==parentPathA.length-2)
			parentPath+="assets";
	}
	window.location.assign(parentPath+"game.html")
}
var paths=window.location.href.split("assets");
var path="";
for(i=0; i<paths.length-1; i++)
{
	path+=paths[i]+"assets"
}
if(localStorage.reloaded==="1")
{
	home();
}
localStorage.reloaded="1";
<commit_msg>added back function<commit_after>function home()
{
	parentPathA=path.split("assets");
	parentPath=""
	for(i=0; i<parentPathA.length-1; i++)
	{
		parentPath+=parentPathA[i]
		if(i!==parentPathA.length-2)
			parentPath+="assets";
	}
	window.location.assign(parentPath+"game.html")
}
function back()
{
	localStorage.reloaded="0";
	window.location.assign("../../playmenu.html");
}
var paths=window.location.href.split("assets");
var path="";
for(i=0; i<paths.length-1; i++)
{
	path+=paths[i]+"assets"
}
if(localStorage.reloaded==="1")
{
	home();
}
localStorage.reloaded="1";
<|endoftext|>


<commit_before>$(document).ready(getposts);
function getposts(){
    $.getJSON('entries.json', function(data) {
		$.each(data.entries, function(key, val) {
				console.log(key);
        }
     }
}<commit_msg>no message<commit_after>$(document).ready(getposts);
function getposts(){
    $.getJSON('entries.json', function(data) {
		$.each(data.entries, function(key, val) {
				console.log(key);
        });
	});
}<|endoftext|>


<commit_before>import { Field, Formik } from 'formik'
import React, { Component } from 'react'
import {
  Button,
  ButtonToolbar,
  ControlLabel,
  FormControl,
  FormGroup,
  HelpBlock,
  Label,
  ToggleButton,
  ToggleButtonGroup
} from 'react-bootstrap'
import { formatPhoneNumber, isPossiblePhoneNumber } from 'react-phone-number-input'
import Input from 'react-phone-number-input/input'
import styled, { css } from 'styled-components'
import * as yup from 'yup'

import { isBlank } from '../../util/ui'

const allowedNotificationChannels = [
  {
    type: 'email',
    text: 'Email'
  },
  {
    type: 'sms',
    text: 'SMS'
  },
  {
    type: 'none',
    text: 'Don\'t notify me'
  }
]

// Styles
// HACK: Preverve container height.
const Details = styled.div`
  min-height: 150px;
  margin-bottom: 15px;
`
const ControlStrip = styled.div`
  > * {
    margin-right: 4px;
  }
`
const phoneFieldCss = css`
  display: inline-block;
  vertical-align: middle;
  width: 14em;
`
const InlineTextInput = styled(FormControl)`
  ${phoneFieldCss}
`
const InlineStatic = styled(FormControl.Static)`
  ${phoneFieldCss}
`
const InlinePhoneInput = styled(Input)`
  ${phoneFieldCss}
`

const FlushLink = styled(Button)`
  padding-left: 0;
  padding-right: 0;
`

/**
 * @param {*} props The props from which to extract the Formik state to test.
 * @param {*} field THe field name to test.
 * @returns One of the Bootstrao validationState values.
 */
function getErrorState (props, field) {
  const { errors, touched } = props

  // one of the Bootstrap validationState values.
  return errors[field] && touched[field]
    ? 'error'
    : null
}

const INVALID_PHONE_MSG = 'Please enter a valid phone number.'
const VALIDATION_CODE_MSG = 'Please enter 6 digits for the validation code.'
const codeValidationSchema = yup.object({
  validationCode: yup.string()
    .required(VALIDATION_CODE_MSG)
    .matches(/^\d{6}$/, VALIDATION_CODE_MSG) // 6-digit string
})

/**
 * User notification preferences pane.
 */
const NotificationPrefsPane = ({
  handleBlur, // Formik prop
  handleChange, // Formik prop
  loggedInUser,
  onRequestPhoneVerificationCode,
  onSendPhoneVerificationCode,
  phoneFormatOptions,
  values: userData // Formik prop
}) => {
  const {
    email,
    isPhoneNumberVerified,
    phoneNumber
  } = loggedInUser

  const {
    notificationChannel
  } = userData

  const initialFormikValues = {
    validationCode: ''
  }

  return (

          You can receive notifications about trips you frequently take.

      <FormGroup>
        <ControlLabel>How would you like to receive notifications?</ControlLabel>
        <ButtonToolbar>
          <ToggleButtonGroup
            name='notificationChannel'
            type='radio'
            defaultValue={notificationChannel}
          >
            {allowedNotificationChannels.map(({ type, text }, index) => (
              // TODO: If removing the Save/Cancel buttons on the account screen,
              // persist changes immediately when onChange is triggered.
              <ToggleButton
                bsStyle={notificationChannel === type ? 'primary' : 'default'}
                key={index}
                // onBlur and onChange have to be set on individual controls instead of the control group
                // in order for Formik to correcly process the changes.
                onBlur={handleBlur}
                onChange={handleChange}
                value={type}
              >
                {text}
              </ToggleButton>
            ))}
          </ToggleButtonGroup>
        </ButtonToolbar>
      </FormGroup>

        {notificationChannel === 'email' && (
          <FormGroup>
            <ControlLabel>Notification emails will be sent to:</ControlLabel>
            <FormControl.Static>{email}</FormControl.Static>
          </FormGroup>
        )}
        {notificationChannel === 'sms' && (
          <Formik
            validateOnChange
            validationSchema={codeValidationSchema}
            initialValues={initialFormikValues}
          >
            {
              // Pass Formik props to the component rendered so Formik can manage its validation.
              // (The validation for this component is independent of the validation set in UserAccountScreen.)
              innerProps => {
                return (
                  <PhoneNumberEditor
                    {...innerProps}
                    initialPhoneNumber={phoneNumber}
                    initialPhoneNumberVerified={isPhoneNumberVerified}
                    onRequestCode={onRequestPhoneVerificationCode}
                    onSubmitCode={onSendPhoneVerificationCode}
                    phoneFormatOptions={phoneFormatOptions}
                  />
                )
              }
            }
          </Formik>
        )}

  )
}

export default NotificationPrefsPane

/**
 * Sub-component that handles phone number and validation code editing and validation intricacies.
 */
class PhoneNumberEditor extends Component {
  constructor (props) {
    super(props)

    const { initialPhoneNumber } = props
    this.state = {
      // If true, phone number is being edited.
      // For new users, render component in editing state.
      isEditing: isBlank(initialPhoneNumber),

      // Holds the new phone number (+15555550123 format) entered by the user
      // (outside of Formik because (Phone)Input does not have a standard onChange event or simple valitity test).
      newPhoneNumber: ''
    }
  }

  _handleEditNumber = () => {
    this.setState({
      isEditing: true,
      newPhoneNumber: ''
    })
  }

  _handleNewPhoneNumberChange = newPhoneNumber => {
    this.setState({
      newPhoneNumber
    })
  }

  _handleCancelEditNumber = () => {
    this.setState({
      isEditing: false
    })
  }

  _handlePhoneNumberKeyDown = e => {
    if (e.keyCode === 13) {
      // On the user pressing enter (keyCode 13) on the phone number field,
      // prevent form submission and request the code.
      e.preventDefault()
      this._handleRequestCode()
    }
  }

  _handleValidationCodeKeyDown = e => {
    if (e.keyCode === 13) {
      // On the user pressing enter (keyCode 13) on the validation code field,
      // prevent form submission and send the validation code.
      e.preventDefault()
      this._handleSubmitCode()
    }
  }

  /**
   * Send phone verification request with the entered values.
   */
  _handleRequestCode = () => {
    const { initialPhoneNumber, initialPhoneNumberVerified, onRequestCode } = this.props
    const { newPhoneNumber } = this.state

    this._handleCancelEditNumber()

    // Send the SMS request if one of these conditions apply:
    // - the user entered a valid phone number different than their current verified number,
    // - the user clicks 'Request new code' for an already pending number
    //   (they could have refreshed the page in between).
    let submittedNumber

    if (newPhoneNumber &&
      isPossiblePhoneNumber(newPhoneNumber) &&
      !(newPhoneNumber === initialPhoneNumber && initialPhoneNumberVerified)) {
      submittedNumber = newPhoneNumber
    } else if (this._isPhoneNumberPending()) {
      submittedNumber = initialPhoneNumber
    }

    if (submittedNumber) {
      onRequestCode(submittedNumber)
    }
  }

  _handleSubmitCode = () => {
    const { errors, onSubmitCode, values } = this.props
    const { validationCode } = values

    if (!errors.validationCode) {
      onSubmitCode(validationCode)
    }
  }

  _isPhoneNumberPending = () => {
    const { initialPhoneNumber, initialPhoneNumberVerified } = this.props
    return !isBlank(initialPhoneNumber) && !initialPhoneNumberVerified
  }

  componentDidUpdate (prevProps) {
    // If new phone number and verified status are received,
    // then reset/clear the inputs.
    if (this.props.phoneNumber !== prevProps.phoneNumber ||
        this.props.isPhoneNumberVerified !== prevProps.isPhoneNumberVerified
    ) {
      this._handleCancelEditNumber()
      this.props.resetForm()
    }
  }

  render () {
    const {
      errors, // Formik prop
      initialPhoneNumber,
      phoneFormatOptions,
      touched // Formik prop
    } = this.props
    const { isEditing, newPhoneNumber } = this.state
    const isPending = this._isPhoneNumberPending()

    // Here are the states we are dealing with:
    // - First time entering a phone number/validation code (blank value, not modified)
    //   => no color, no feedback indication.
    // - Typing backspace all the way to erase a number/code (blank value, modified)
    //   => red error.
    // - Typing a phone number that doesn't match the configured phoneNumberRegEx
    //   => red error.
    const isPhoneInvalid = !isPossiblePhoneNumber(newPhoneNumber)
    const showPhoneError = isPhoneInvalid && !isBlank(newPhoneNumber)
    const phoneErrorState = showPhoneError ? 'error' : null
    const codeErrorState = getErrorState(this.props, 'validationCode')

    return (
      <>
        {isEditing
          ? (
            // FIXME: If removing the Save/Cancel buttons on the account screen,
            // make this <FormGroup> a <form> and remove onKeyDown handler.
            <FormGroup validationState={phoneErrorState}>
              <ControlLabel>Enter your phone number for SMS notifications:</ControlLabel>
              <ControlStrip>
                <InlinePhoneInput
                  className='form-control'
                  country={phoneFormatOptions.countryCode}
                  onChange={this._handleNewPhoneNumberChange}
                  onKeyDown={this._handlePhoneNumberKeyDown}
                  placeholder='Enter phone number'
                  type='tel'
                  value={newPhoneNumber}
                />
                <Button
                  bsStyle='primary'
                  disabled={isPhoneInvalid}
                  onClick={this._handleRequestCode}
                >
                  Send verification text
                </Button>
                { // Show cancel button only if a phone number is already recorded.
                  initialPhoneNumber && <Button onClick={this._handleCancelEditNumber}>Cancel</Button>}
                {showPhoneError && <HelpBlock>{INVALID_PHONE_MSG}</HelpBlock>}
              </ControlStrip>
            </FormGroup>
          ) : (
            <FormGroup>
              <ControlLabel>SMS notifications will be sent to:</ControlLabel>
              <ControlStrip>
                <InlineStatic>
                  {formatPhoneNumber(initialPhoneNumber)}
                  {' '}
                  {isPending
                    // eslint-disable-next-line jsx-a11y/label-has-for
                    ? Pending
                    // eslint-disable-next-line jsx-a11y/label-has-for
                    : Verified
                  }
                </InlineStatic>
                <Button onClick={this._handleEditNumber}>Change number</Button>
              </ControlStrip>
            </FormGroup>
          )}

        {isPending && !isEditing && (
          // FIXME: If removing the Save/Cancel buttons on the account screen,
          // make this <FormGroup> a <form> and remove onKeyDown handler.
          <FormGroup validationState={codeErrorState}>

              Please check the SMS messaging app on your mobile phone
              for a text message with a verification code, and enter the code below.
              The verification code expires after 10 minutes.

            <ControlLabel>Verification code:</ControlLabel>
            <ControlStrip>
              <Field as={InlineTextInput}
                maxLength={6}
                name='validationCode'
                onKeyDown={this._handleValidationCodeKeyDown}
                placeholder='123456'
                // HACK: <input type='tel'> triggers the numerical keypad on mobile devices, and otherwise
                // behaves like <input type='text'> with support of leading zeros and the maxLength prop.
                // <input type='number'> causes values to be stored as Number, resulting in
                // leading zeros to be invalid and stripped upon submission.
                type='tel'

                // onBlur, onChange, and value are passed automatically by Formik
              />
              <Button
                bsStyle='primary'
                disabled={!!errors.validationCode}
                onClick={this._handleSubmitCode}
              >
                Verify
              </Button>
              {touched.validationCode && errors.validationCode && (
                <HelpBlock>{errors.validationCode}</HelpBlock>
              )}
            </ControlStrip>
            <FlushLink bsStyle='link' onClick={this._handleRequestCode}>Request a new code</FlushLink>
          </FormGroup>
        )}
      </>
    )
  }
}
<commit_msg>refactor(PhoneNumberEditor): Tweak expiration text.<commit_after>import { Field, Formik } from 'formik'
import React, { Component } from 'react'
import {
  Button,
  ButtonToolbar,
  ControlLabel,
  FormControl,
  FormGroup,
  HelpBlock,
  Label,
  ToggleButton,
  ToggleButtonGroup
} from 'react-bootstrap'
import { formatPhoneNumber, isPossiblePhoneNumber } from 'react-phone-number-input'
import Input from 'react-phone-number-input/input'
import styled, { css } from 'styled-components'
import * as yup from 'yup'

import { isBlank } from '../../util/ui'

const allowedNotificationChannels = [
  {
    type: 'email',
    text: 'Email'
  },
  {
    type: 'sms',
    text: 'SMS'
  },
  {
    type: 'none',
    text: 'Don\'t notify me'
  }
]

// Styles
// HACK: Preverve container height.
const Details = styled.div`
  min-height: 150px;
  margin-bottom: 15px;
`
const ControlStrip = styled.div`
  > * {
    margin-right: 4px;
  }
`
const phoneFieldCss = css`
  display: inline-block;
  vertical-align: middle;
  width: 14em;
`
const InlineTextInput = styled(FormControl)`
  ${phoneFieldCss}
`
const InlineStatic = styled(FormControl.Static)`
  ${phoneFieldCss}
`
const InlinePhoneInput = styled(Input)`
  ${phoneFieldCss}
`

const FlushLink = styled(Button)`
  padding-left: 0;
  padding-right: 0;
`

/**
 * @param {*} props The props from which to extract the Formik state to test.
 * @param {*} field THe field name to test.
 * @returns One of the Bootstrao validationState values.
 */
function getErrorState (props, field) {
  const { errors, touched } = props

  // one of the Bootstrap validationState values.
  return errors[field] && touched[field]
    ? 'error'
    : null
}

const INVALID_PHONE_MSG = 'Please enter a valid phone number.'
const VALIDATION_CODE_MSG = 'Please enter 6 digits for the validation code.'
const codeValidationSchema = yup.object({
  validationCode: yup.string()
    .required(VALIDATION_CODE_MSG)
    .matches(/^\d{6}$/, VALIDATION_CODE_MSG) // 6-digit string
})

/**
 * User notification preferences pane.
 */
const NotificationPrefsPane = ({
  handleBlur, // Formik prop
  handleChange, // Formik prop
  loggedInUser,
  onRequestPhoneVerificationCode,
  onSendPhoneVerificationCode,
  phoneFormatOptions,
  values: userData // Formik prop
}) => {
  const {
    email,
    isPhoneNumberVerified,
    phoneNumber
  } = loggedInUser

  const {
    notificationChannel
  } = userData

  const initialFormikValues = {
    validationCode: ''
  }

  return (

          You can receive notifications about trips you frequently take.

      <FormGroup>
        <ControlLabel>How would you like to receive notifications?</ControlLabel>
        <ButtonToolbar>
          <ToggleButtonGroup
            name='notificationChannel'
            type='radio'
            defaultValue={notificationChannel}
          >
            {allowedNotificationChannels.map(({ type, text }, index) => (
              // TODO: If removing the Save/Cancel buttons on the account screen,
              // persist changes immediately when onChange is triggered.
              <ToggleButton
                bsStyle={notificationChannel === type ? 'primary' : 'default'}
                key={index}
                // onBlur and onChange have to be set on individual controls instead of the control group
                // in order for Formik to correcly process the changes.
                onBlur={handleBlur}
                onChange={handleChange}
                value={type}
              >
                {text}
              </ToggleButton>
            ))}
          </ToggleButtonGroup>
        </ButtonToolbar>
      </FormGroup>

        {notificationChannel === 'email' && (
          <FormGroup>
            <ControlLabel>Notification emails will be sent to:</ControlLabel>
            <FormControl.Static>{email}</FormControl.Static>
          </FormGroup>
        )}
        {notificationChannel === 'sms' && (
          <Formik
            validateOnChange
            validationSchema={codeValidationSchema}
            initialValues={initialFormikValues}
          >
            {
              // Pass Formik props to the component rendered so Formik can manage its validation.
              // (The validation for this component is independent of the validation set in UserAccountScreen.)
              innerProps => {
                return (
                  <PhoneNumberEditor
                    {...innerProps}
                    initialPhoneNumber={phoneNumber}
                    initialPhoneNumberVerified={isPhoneNumberVerified}
                    onRequestCode={onRequestPhoneVerificationCode}
                    onSubmitCode={onSendPhoneVerificationCode}
                    phoneFormatOptions={phoneFormatOptions}
                  />
                )
              }
            }
          </Formik>
        )}

  )
}

export default NotificationPrefsPane

/**
 * Sub-component that handles phone number and validation code editing and validation intricacies.
 */
class PhoneNumberEditor extends Component {
  constructor (props) {
    super(props)

    const { initialPhoneNumber } = props
    this.state = {
      // If true, phone number is being edited.
      // For new users, render component in editing state.
      isEditing: isBlank(initialPhoneNumber),

      // Holds the new phone number (+15555550123 format) entered by the user
      // (outside of Formik because (Phone)Input does not have a standard onChange event or simple valitity test).
      newPhoneNumber: ''
    }
  }

  _handleEditNumber = () => {
    this.setState({
      isEditing: true,
      newPhoneNumber: ''
    })
  }

  _handleNewPhoneNumberChange = newPhoneNumber => {
    this.setState({
      newPhoneNumber
    })
  }

  _handleCancelEditNumber = () => {
    this.setState({
      isEditing: false
    })
  }

  _handlePhoneNumberKeyDown = e => {
    if (e.keyCode === 13) {
      // On the user pressing enter (keyCode 13) on the phone number field,
      // prevent form submission and request the code.
      e.preventDefault()
      this._handleRequestCode()
    }
  }

  _handleValidationCodeKeyDown = e => {
    if (e.keyCode === 13) {
      // On the user pressing enter (keyCode 13) on the validation code field,
      // prevent form submission and send the validation code.
      e.preventDefault()
      this._handleSubmitCode()
    }
  }

  /**
   * Send phone verification request with the entered values.
   */
  _handleRequestCode = () => {
    const { initialPhoneNumber, initialPhoneNumberVerified, onRequestCode } = this.props
    const { newPhoneNumber } = this.state

    this._handleCancelEditNumber()

    // Send the SMS request if one of these conditions apply:
    // - the user entered a valid phone number different than their current verified number,
    // - the user clicks 'Request new code' for an already pending number
    //   (they could have refreshed the page in between).
    let submittedNumber

    if (newPhoneNumber &&
      isPossiblePhoneNumber(newPhoneNumber) &&
      !(newPhoneNumber === initialPhoneNumber && initialPhoneNumberVerified)) {
      submittedNumber = newPhoneNumber
    } else if (this._isPhoneNumberPending()) {
      submittedNumber = initialPhoneNumber
    }

    if (submittedNumber) {
      onRequestCode(submittedNumber)
    }
  }

  _handleSubmitCode = () => {
    const { errors, onSubmitCode, values } = this.props
    const { validationCode } = values

    if (!errors.validationCode) {
      onSubmitCode(validationCode)
    }
  }

  _isPhoneNumberPending = () => {
    const { initialPhoneNumber, initialPhoneNumberVerified } = this.props
    return !isBlank(initialPhoneNumber) && !initialPhoneNumberVerified
  }

  componentDidUpdate (prevProps) {
    // If new phone number and verified status are received,
    // then reset/clear the inputs.
    if (this.props.phoneNumber !== prevProps.phoneNumber ||
        this.props.isPhoneNumberVerified !== prevProps.isPhoneNumberVerified
    ) {
      this._handleCancelEditNumber()
      this.props.resetForm()
    }
  }

  render () {
    const {
      errors, // Formik prop
      initialPhoneNumber,
      phoneFormatOptions,
      touched // Formik prop
    } = this.props
    const { isEditing, newPhoneNumber } = this.state
    const isPending = this._isPhoneNumberPending()

    // Here are the states we are dealing with:
    // - First time entering a phone number/validation code (blank value, not modified)
    //   => no color, no feedback indication.
    // - Typing backspace all the way to erase a number/code (blank value, modified)
    //   => red error.
    // - Typing a phone number that doesn't match the configured phoneNumberRegEx
    //   => red error.
    const isPhoneInvalid = !isPossiblePhoneNumber(newPhoneNumber)
    const showPhoneError = isPhoneInvalid && !isBlank(newPhoneNumber)
    const phoneErrorState = showPhoneError ? 'error' : null
    const codeErrorState = getErrorState(this.props, 'validationCode')

    return (
      <>
        {isEditing
          ? (
            // FIXME: If removing the Save/Cancel buttons on the account screen,
            // make this <FormGroup> a <form> and remove onKeyDown handler.
            <FormGroup validationState={phoneErrorState}>
              <ControlLabel>Enter your phone number for SMS notifications:</ControlLabel>
              <ControlStrip>
                <InlinePhoneInput
                  className='form-control'
                  country={phoneFormatOptions.countryCode}
                  onChange={this._handleNewPhoneNumberChange}
                  onKeyDown={this._handlePhoneNumberKeyDown}
                  placeholder='Enter phone number'
                  type='tel'
                  value={newPhoneNumber}
                />
                <Button
                  bsStyle='primary'
                  disabled={isPhoneInvalid}
                  onClick={this._handleRequestCode}
                >
                  Send verification text
                </Button>
                { // Show cancel button only if a phone number is already recorded.
                  initialPhoneNumber && <Button onClick={this._handleCancelEditNumber}>Cancel</Button>}
                {showPhoneError && <HelpBlock>{INVALID_PHONE_MSG}</HelpBlock>}
              </ControlStrip>
            </FormGroup>
          ) : (
            <FormGroup>
              <ControlLabel>SMS notifications will be sent to:</ControlLabel>
              <ControlStrip>
                <InlineStatic>
                  {formatPhoneNumber(initialPhoneNumber)}
                  {' '}
                  {isPending
                    // eslint-disable-next-line jsx-a11y/label-has-for
                    ? Pending
                    // eslint-disable-next-line jsx-a11y/label-has-for
                    : Verified
                  }
                </InlineStatic>
                <Button onClick={this._handleEditNumber}>Change number</Button>
              </ControlStrip>
            </FormGroup>
          )}

        {isPending && !isEditing && (
          // FIXME: If removing the Save/Cancel buttons on the account screen,
          // make this <FormGroup> a <form> and remove onKeyDown handler.
          <FormGroup validationState={codeErrorState}>

              Please check the SMS messaging app on your mobile phone
              for a text message with a verification code, and enter the code below
              (code expires after 10 minutes).

            <ControlLabel>Verification code:</ControlLabel>
            <ControlStrip>
              <Field as={InlineTextInput}
                maxLength={6}
                name='validationCode'
                onKeyDown={this._handleValidationCodeKeyDown}
                placeholder='123456'
                // HACK: <input type='tel'> triggers the numerical keypad on mobile devices, and otherwise
                // behaves like <input type='text'> with support of leading zeros and the maxLength prop.
                // <input type='number'> causes values to be stored as Number, resulting in
                // leading zeros to be invalid and stripped upon submission.
                type='tel'

                // onBlur, onChange, and value are passed automatically by Formik
              />
              <Button
                bsStyle='primary'
                disabled={!!errors.validationCode}
                onClick={this._handleSubmitCode}
              >
                Verify
              </Button>
              {touched.validationCode && errors.validationCode && (
                <HelpBlock>{errors.validationCode}</HelpBlock>
              )}
            </ControlStrip>
            <FlushLink bsStyle='link' onClick={this._handleRequestCode}>Request a new code</FlushLink>
          </FormGroup>
        )}
      </>
    )
  }
}
<|endoftext|>


<commit_before>angular.module('starter.contactcontrollers', [])

.controller('ContactCtrl', function($http, $scope,$ionicLoading,$state,ContactService) {
    $ionicLoading.show({
        template:'
Loading...'
    });

    ContactService.getMainInfo().then(function(res){
        $scope.contacts = res.data;
    }).then(function(){
            $ionicLoading.hide();
    });

    // $scope.passcontact = function(id){
    //     var contactPath = {};
    //     contactPath.id = id;
    //     contactPath.path = "contact";
    //     return contactPath;
    // }

    $scope.godiscover = function(){
            $state.go("tab.discovery");
    }

})

.controller('ContactDetailCtrl', function($scope,$stateParams,$state,$ionicLoading,ContactService,$window,$location) {

    // var contactPath = JSON.parse($stateParams.contact);
    // console.log(contactPath);
    console.log($stateParams);

    // var num = contactPath.id;
    // var urlPara = contactPath.path;
    var num = $stateParams.contact;

    // $scope.urlPath = {};
    // $scope.urlPath.id = contactPath.id;
    // $scope.urlPath.path = contactPath.path;

    // var num = $stateParams.contact;
    // console.log(num);

    $ionicLoading.show({
        template:'
Loading...'
    });

    ContactService.getMainInfo().success(function(data){
        $scope.contactpath = {};
        for (var i = 0; i < data.length; i++) {
            if(data[i].contact_id == num){
                $scope.contactitem = data[i];
                $scope.contactpath.id = $scope.contactitem.contact_id;
                $scope.contactpath.path = "contact-detail";
            }
        }
    }).then(function(){
            $ionicLoading.hide();
    });

    $scope.goback = function(){
        console.log(urlPara);
        if (urlPara == "contact-detail") {
            history.go(-3);
        }
        else{
            history.back();
        }
        //暂时通，满满研究history，未完待续
        // $location.path(BrowsingHistory.prev());
        console.log($location.path());
        console.log($location.absUrl());
        console.log($location.search());
        // BrowserHistory.changeHash();
    };

    // $scope.sendmessage = function(contact_id){
    //     $state.go("tab.message",{contact_id:contact_id});
    // }

})
<commit_msg>go back<commit_after>angular.module('starter.contactcontrollers', [])

.controller('ContactCtrl', function($http, $scope,$ionicLoading,$state,ContactService) {
    $ionicLoading.show({
        template:'
Loading...'
    });

    ContactService.getMainInfo().then(function(res){
        $scope.contacts = res.data;
    }).then(function(){
            $ionicLoading.hide();
    });

    // $scope.passcontact = function(id){
    //     var contactPath = {};
    //     contactPath.id = id;
    //     contactPath.path = "contact";
    //     return contactPath;
    // }

    $scope.godiscover = function(){
            $state.go("tab.discovery");
    }

})

.controller('ContactDetailCtrl', function($scope,$stateParams,$state,$ionicLoading,ContactService,$window,$location) {

    // var contactPath = JSON.parse($stateParams.contact);
    // console.log(contactPath);
    console.log($stateParams);

    // var num = contactPath.id;
    // var urlPara = contactPath.path;
    var num = $stateParams.contact;

    // $scope.urlPath = {};
    // $scope.urlPath.id = contactPath.id;
    // $scope.urlPath.path = contactPath.path;

    // var num = $stateParams.contact;
    // console.log(num);

    $ionicLoading.show({
        template:'
Loading...'
    });

    ContactService.getMainInfo().success(function(data){
        $scope.contactpath = {};
        for (var i = 0; i < data.length; i++) {
            if(data[i].contact_id == num){
                $scope.contactitem = data[i];
                $scope.contactpath.id = $scope.contactitem.contact_id;
                $scope.contactpath.path = "contact-detail";
            }
        }
        console.log($scope.contactitem)
    }).then(function(){
            $ionicLoading.hide();
    });

    $scope.goback = function(){
            history.back()
    }

    // $scope.sendmessage = function(contact_id){
    //     $state.go("tab.message",{contact_id:contact_id});
    // }

})
<|endoftext|>


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

/**
 * Class that represents a solar panel in the view.
 *
 * @author John Blanco
 * @author Andrew Adare
 */
define( function( require ) {
  'use strict';

  // Modules
  var Bounds2 = require( 'DOT/Bounds2' );
  var EFACModelImage = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EFACModelImage' );
  var EnergyConverter = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EnergyConverter' );
  var Image = require( 'SCENERY/nodes/Image' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Random = require( 'DOT/Random' );
  var SunEnergySource = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/SunEnergySource' );
  var Vector2 = require( 'DOT/Vector2' );

  // Images
  // TODO: These are in the Java code, but should they be moved to view code?
  var CONNECTOR = require( 'image!ENERGY_FORMS_AND_CHANGES/connector.png' );
  var SOLAR_PANEL = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel.png' );
  var SOLAR_PANEL_GEN = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel_gen.png' );
  var SOLAR_PANEL_ICON = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel_icon.png' );
  var SOLAR_PANEL_POST_2 = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel_post_2.png' );
  var SUN_ICON = require( 'image!ENERGY_FORMS_AND_CHANGES/sun_icon.png' );
  var WIRE_BLACK_LEFT = require( 'image!ENERGY_FORMS_AND_CHANGES/wire_black_left.png' );

  // Constants
  var RAND = new Random();
  var SOLAR_PANEL_OFFSET = new Vector2( 0, 0.044 );
  var CONVERTER_IMAGE_OFFSET = new Vector2( 0.015, -0.040 );
  var CONNECTOR_IMAGE_OFFSET = new Vector2( 0.057, -0.04 );

  var SOLAR_PANEL_IMAGE = new EFACModelImage( SOLAR_PANEL, 0.15, SOLAR_PANEL_OFFSET );
  var CONVERTER_IMAGE = new EFACModelImage( SOLAR_PANEL_GEN, SOLAR_PANEL_GEN.width, CONVERTER_IMAGE_OFFSET );
  var CURVED_WIRE_IMAGE = new EFACModelImage( WIRE_BLACK_LEFT, WIRE_BLACK_LEFT.width, CONVERTER_IMAGE_OFFSET.plus( 0.009, 0.024 ) );
  var POST_IMAGE = new EFACModelImage( SOLAR_PANEL_POST_2, SOLAR_PANEL_POST_2.width, CONVERTER_IMAGE_OFFSET.plus( new Vector2( 0, 0.04 ) ) );
  var CONNECTOR_IMAGE = new EFACModelImage( CONNECTOR, CONNECTOR.width, CONNECTOR_IMAGE_OFFSET );

  var halfWidth = SOLAR_PANEL_IMAGE.width / 2;
  var halfHeight = SOLAR_PANEL_IMAGE.height / 2;
  var PANEL_IMAGE_BOUNDS = new Bounds2( -halfWidth, -halfHeight, halfWidth, halfHeight );

  // TODO
  // private static final DoubleGeneralPath ABSORPTION_SHAPE = new DoubleGeneralPath() {{
  //     double absorptionZoneWidth = PANEL_IMAGE_BOUNDS.getWidth() * 0.2;
  //     moveTo( PANEL_IMAGE_BOUNDS.getMinX(), PANEL_IMAGE_BOUNDS.getMinY() );
  //     moveTo( PANEL_IMAGE_BOUNDS.getMaxX() - absorptionZoneWidth, PANEL_IMAGE_BOUNDS.getMaxY() );
  //     lineTo( PANEL_IMAGE_BOUNDS.getMaxX(), PANEL_IMAGE_BOUNDS.getMaxY() );
  //     lineTo( PANEL_IMAGE_BOUNDS.getMinX() + absorptionZoneWidth, PANEL_IMAGE_BOUNDS.getMinY() );
  //     lineTo( PANEL_IMAGE_BOUNDS.getMinX(), PANEL_IMAGE_BOUNDS.getMinY() );
  //     closePath();
  // }};

  // Constants used for creating the path followed by the energy chunks.
  // Many of these numbers were empirically determined based on the images,
  // and will need updating if the images change.
  var OFFSET_TO_CONVERGENCE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x, 0.01 );
  var OFFSET_TO_FIRST_CURVE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x, -0.025 );
  var OFFSET_TO_SECOND_CURVE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x + 0.005, -0.033 );
  var OFFSET_TO_THIRD_CURVE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x + 0.015, CONNECTOR_IMAGE_OFFSET.y );
  var OFFSET_TO_CONNECTOR_CENTER = CONNECTOR_IMAGE_OFFSET;

  // Inter chunk spacing time for when the chunks reach the 'convergence
  // point' at the bottom of the solar panel.  It is intended to
  // approximately match the rate at which the sun emits energy chunks.
  var MIN_INTER_CHUNK_TIME = 1 / ( SunEnergySource.ENERGY_CHUNK_EMISSION_PERIOD * SunEnergySource.NUM_EMISSION_SECTORS ); // In seconds.

  /**
   * Solar panel is an energy converter
   *
   * @param {[type]} energyChunksVisible [description]
   * @constructor
   */
  function SolarPanel( energyChunksVisible ) {
    EnergyConverter.call( this, new Image( SOLAR_PANEL_ICON ) );
    this.energyChunkMovers = [];
    // TODO: simulation clock? I don't think it is needed.
    this.latestChunkArrivalTime = 0;
    this.energyOutputRate = 0;
    this.energyChunksVisible = energyChunksVisible;
  }

  // TODO fill out these stubs
  return inherit( EnergyConverter, SolarPanel, {
    stepInTime: function( dt, incomingEnergy ) {},
    moveEnergyChunks: function( dt ) {},
    preLoadEnergyChunks: function( incomingEnergyRate ) {},
    getEnergyOutputRate: function() {},
    chooseChunkVelocityOnPanel: function() {},
    clearEnergyChunks: function() {},
    createPathToPanelBottom: function() {},
    createPathThroughConverter: function() {},
    getAbsorptionShape: function() {},
    getUserComponent: function() {},
    temp: function() {
      console.log(
        SUN_ICON,
        RAND,
        PANEL_IMAGE_BOUNDS,
        OFFSET_TO_CONVERGENCE_POINT,
        OFFSET_TO_FIRST_CURVE_POINT,
        OFFSET_TO_SECOND_CURVE_POINT,
        OFFSET_TO_THIRD_CURVE_POINT,
        OFFSET_TO_CONNECTOR_CENTER,
        MIN_INTER_CHUNK_TIME
      );
    }

  }, {
    CURVED_WIRE_IMAGE: CURVED_WIRE_IMAGE,
    POST_IMAGE: POST_IMAGE,
    SOLAR_PANEL_IMAGE: SOLAR_PANEL_IMAGE,
    CONVERTER_IMAGE: CONVERTER_IMAGE,
    CONNECTOR_IMAGE: CONNECTOR_IMAGE
  } );
} );<commit_msg>Minor doc updates<commit_after>// Copyright 2014-2015, University of Colorado Boulder

/**
 * Class that represents a solar panel in the view.
 *
 * @author John Blanco
 * @author Andrew Adare
 */
define( function( require ) {
  'use strict';

  // Modules
  var Bounds2 = require( 'DOT/Bounds2' );
  var EFACModelImage = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EFACModelImage' );
  var EnergyConverter = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EnergyConverter' );
  var Image = require( 'SCENERY/nodes/Image' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Random = require( 'DOT/Random' );
  var SunEnergySource = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/SunEnergySource' );
  var Vector2 = require( 'DOT/Vector2' );

  // Images
  // TODO: These are in the Java code, but should they be moved to view code?
  var CONNECTOR = require( 'image!ENERGY_FORMS_AND_CHANGES/connector.png' );
  var SOLAR_PANEL = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel.png' );
  var SOLAR_PANEL_GEN = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel_gen.png' );
  var SOLAR_PANEL_ICON = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel_icon.png' );
  var SOLAR_PANEL_POST_2 = require( 'image!ENERGY_FORMS_AND_CHANGES/solar_panel_post_2.png' );
  var SUN_ICON = require( 'image!ENERGY_FORMS_AND_CHANGES/sun_icon.png' );
  var WIRE_BLACK_LEFT = require( 'image!ENERGY_FORMS_AND_CHANGES/wire_black_left.png' );

  // Constants
  var RAND = new Random();
  var SOLAR_PANEL_OFFSET = new Vector2( 0, 0.044 );
  var CONVERTER_IMAGE_OFFSET = new Vector2( 0.015, -0.040 );
  var CONNECTOR_IMAGE_OFFSET = new Vector2( 0.057, -0.04 );

  var SOLAR_PANEL_IMAGE = new EFACModelImage( SOLAR_PANEL, 0.15, SOLAR_PANEL_OFFSET );
  var CONVERTER_IMAGE = new EFACModelImage( SOLAR_PANEL_GEN, SOLAR_PANEL_GEN.width, CONVERTER_IMAGE_OFFSET );
  var CURVED_WIRE_IMAGE = new EFACModelImage( WIRE_BLACK_LEFT, WIRE_BLACK_LEFT.width, CONVERTER_IMAGE_OFFSET.plus( 0.009, 0.024 ) );
  var POST_IMAGE = new EFACModelImage( SOLAR_PANEL_POST_2, SOLAR_PANEL_POST_2.width, CONVERTER_IMAGE_OFFSET.plus( new Vector2( 0, 0.04 ) ) );
  var CONNECTOR_IMAGE = new EFACModelImage( CONNECTOR, CONNECTOR.width, CONNECTOR_IMAGE_OFFSET );

  var halfWidth = SOLAR_PANEL_IMAGE.width / 2;
  var halfHeight = SOLAR_PANEL_IMAGE.height / 2;
  var PANEL_IMAGE_BOUNDS = new Bounds2( -halfWidth, -halfHeight, halfWidth, halfHeight );

  // TODO
  // private static final DoubleGeneralPath ABSORPTION_SHAPE = new DoubleGeneralPath() {{
  //     double absorptionZoneWidth = PANEL_IMAGE_BOUNDS.getWidth() * 0.2;
  //     moveTo( PANEL_IMAGE_BOUNDS.getMinX(), PANEL_IMAGE_BOUNDS.getMinY() );
  //     moveTo( PANEL_IMAGE_BOUNDS.getMaxX() - absorptionZoneWidth, PANEL_IMAGE_BOUNDS.getMaxY() );
  //     lineTo( PANEL_IMAGE_BOUNDS.getMaxX(), PANEL_IMAGE_BOUNDS.getMaxY() );
  //     lineTo( PANEL_IMAGE_BOUNDS.getMinX() + absorptionZoneWidth, PANEL_IMAGE_BOUNDS.getMinY() );
  //     lineTo( PANEL_IMAGE_BOUNDS.getMinX(), PANEL_IMAGE_BOUNDS.getMinY() );
  //     closePath();
  // }};

  // Constants used for creating the path followed by the energy chunks.
  // Many of these numbers were empirically determined based on the images,
  // and will need updating if the images change.
  var OFFSET_TO_CONVERGENCE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x, 0.01 );
  var OFFSET_TO_FIRST_CURVE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x, -0.025 );
  var OFFSET_TO_SECOND_CURVE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x + 0.005, -0.033 );
  var OFFSET_TO_THIRD_CURVE_POINT = new Vector2( CONVERTER_IMAGE_OFFSET.x + 0.015, CONNECTOR_IMAGE_OFFSET.y );
  var OFFSET_TO_CONNECTOR_CENTER = CONNECTOR_IMAGE_OFFSET;

  // Inter chunk spacing time for when the chunks reach the 'convergence
  // point' at the bottom of the solar panel.  It is intended to
  // approximately match the rate at which the sun emits energy chunks.
  var MIN_INTER_CHUNK_TIME = 1 / ( SunEnergySource.ENERGY_CHUNK_EMISSION_PERIOD * SunEnergySource.NUM_EMISSION_SECTORS ); // In seconds.

  /**
   * Solar panel is an energy converter
   *
   * @param {Property<boolean>} energyChunksVisible
   * @constructor
   */
  function SolarPanel( energyChunksVisible ) {
    EnergyConverter.call( this, new Image( SOLAR_PANEL_ICON ) );
    this.energyChunkMovers = [];
    this.latestChunkArrivalTime = 0;
    this.energyOutputRate = 0;
    this.energyChunksVisible = energyChunksVisible;
  }

  // TODO fill out these stubs
  return inherit( EnergyConverter, SolarPanel, {
    stepInTime: function( dt, incomingEnergy ) {},
    moveEnergyChunks: function( dt ) {},
    preLoadEnergyChunks: function( incomingEnergyRate ) {},
    getEnergyOutputRate: function() {},
    chooseChunkVelocityOnPanel: function() {},
    clearEnergyChunks: function() {},
    createPathToPanelBottom: function() {},
    createPathThroughConverter: function() {},
    getAbsorptionShape: function() {},
    getUserComponent: function() {},
    temp: function() {
      console.log(
        SUN_ICON,
        RAND,
        PANEL_IMAGE_BOUNDS,
        OFFSET_TO_CONVERGENCE_POINT,
        OFFSET_TO_FIRST_CURVE_POINT,
        OFFSET_TO_SECOND_CURVE_POINT,
        OFFSET_TO_THIRD_CURVE_POINT,
        OFFSET_TO_CONNECTOR_CENTER,
        MIN_INTER_CHUNK_TIME
      );
    }

  }, {
    CURVED_WIRE_IMAGE: CURVED_WIRE_IMAGE,
    POST_IMAGE: POST_IMAGE,
    SOLAR_PANEL_IMAGE: SOLAR_PANEL_IMAGE,
    CONVERTER_IMAGE: CONVERTER_IMAGE,
    CONNECTOR_IMAGE: CONNECTOR_IMAGE
  } );
} );<|endoftext|>


<commit_before>function show()
{
    var levelToUpload = prompt("paste level data here");
    eval('addLevel(' + levelToUpload + ');');
}
function addLevel(loadlevel)
{
    document.getElementById("name").value = loadlevel.name;
    document.getElementById("themeSelect").value = loadlevel.theme.toString();
    theme = loadlevel.theme;
    document.getElementById("musicSelect").value = loadlevel.music.toString();
    music = loadlevel.music;
    document.getElementById("playerSelect").value = loadlevel.player.toString();
    player = loadlevel.player;
    //when you program something backwards, you gotta live with the consequences
    for(h=0;h<17;h++)
    {
    console.log("i will burn you in an endless fire "+h)
        for(c=0; c<30; c++)
        {
            console.log(c+"x"+h);
            levelData[c][h] = loadlevel.data[h][c];
            document.getElementById(c + "x" + h).className = "type" + loadlevel.data[h][c];
        }
    }
}
function upload(uploadFile)
{
	document.getElementById("loadbox").innerHTML="<script type='text/javascript' src='"+uploadFile+"'><\/script>"
}
<commit_msg>Delete load.js<commit_after><|endoftext|>


<commit_before>$(function(){
	$("form#form_actions").each(function() {
		$(this).submit(function(e){
			e.preventDefault();
		});

		$(this).find('div#validation').click(function(){
			$(this).toggleClass('hidden');
			$(this).parent().find('div#annulation').toggleClass('hidden');
			$('button#appliquer').prop('disabled', false);
			$('button#appliquer').addClass('btn-primary')
		});

		$(this).find('button#valide').click(function(){
			$(this).val(true);
			$(this).parent().find('button#refuse').val(false);
		});

		$(this).find('button#refuse').click(function(){
			$(this).val(true);
			$(this).parent().find('button#valide').val(false);
		});

		$(this).find('button#annule').click(function(){
			$(this).parent().toggleClass('hidden');
			$(this).parent().parent().find('button#refuse').val(false);
			$(this).parent().parent().find('button#valide').val(false);
			$(this).parent().parent().find('div#validation').toggleClass('hidden');
			var selection = $("form#form_actions div#validation").filter(function(){
				return $(this).hasClass('hidden');
			});
			if(selection.length <= 0){
				$('button#appliquer').prop('disabled', true);
				$('button#appliquer').removeClass('btn-primary')
			}
		});

	});
	$('#appliquer').click(function(){
		$("form#form_actions").each(function() {
			var valide = $(this).find('button#valide').val();
			var refuse = $(this).find('button#refuse').val();
			var id = $(this).find('input#id').val();
			$.ajax({
				url : "journal/actionNotification",
				type: 'post',
				data: { 'valider': (valide == 'true'), 'refuser': (refuse == 'true'), 'id': id},
				success: function(){
					$('tr#'+id).remove();
					var notifications_count = $("form").length;
					var text = $('a#notifications_count');
					if(notifications_count > 0){
						text.text('Journal');
						$('font#notifications_count_font').text('(' + notifications_count + ')' );
					} else {
						text.text('Journal');
					}
				}
			});
		});
	});
});
<commit_msg>n'elenve que les notifications concernees<commit_after>$(function(){
	$("form#form_actions").each(function() {
		$(this).submit(function(e){
			e.preventDefault();
		});

		$(this).find('div#validation').click(function(){
			$(this).toggleClass('hidden');
			$(this).parent().find('div#annulation').toggleClass('hidden');
			$('button#appliquer').prop('disabled', false);
			$('button#appliquer').addClass('btn-primary')
		});

		$(this).find('button#valide').click(function(){
			$(this).val(true);
			$(this).parent().find('button#refuse').val(false);
		});

		$(this).find('button#refuse').click(function(){
			$(this).val(true);
			$(this).parent().find('button#valide').val(false);
		});

		$(this).find('button#annule').click(function(){
			$(this).parent().toggleClass('hidden');
			$(this).parent().parent().find('button#refuse').val(false);
			$(this).parent().parent().find('button#valide').val(false);
			$(this).parent().parent().find('div#validation').toggleClass('hidden');
			var selection = $("form#form_actions div#validation").filter(function(){
				return $(this).hasClass('hidden');
			});
			if(selection.length <= 0){
				$('button#appliquer').prop('disabled', true);
				$('button#appliquer').removeClass('btn-primary')
			}
		});

	});
	$('#appliquer').click(function(){
		$("form#form_actions").each(function() {
			var valide = $(this).find('button#valide').val();
			var refuse = $(this).find('button#refuse').val();
			valide = (valide == 'true');
			refuse = (refuse == 'true')
			var id = $(this).find('input#id').val();
			if(valide || refuse){
				$.ajax({
					url : "journal/actionNotification",
					type: 'post',
					data: { 'valider': valide, 'refuser': refuse, 'id': id},
					success: function(){
						$('tr#'+id).remove();
						var notifications_count = $("form").length;
						var text = $('a#notifications_count');
						if(notifications_count > 0){
							text.text('Journal');
							$('font#notifications_count_font').text('(' + notifications_count + ')' );
						} else {
							text.text('Journal');
						}
					}
				});
			}
		});
	});
});
<|endoftext|>


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

/**
 * Shows a Dialog with content describing keyboard interactions. Brought up by a button
 * in the navigation bar.
 *
 * @author Jesse Greenberg
 */
define( function( require ) {
  'use strict';

  // modules
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );
  var Dialog = require( 'SUN/Dialog' );
  var FocusHighlightPath = require( 'SCENERY/accessibility/FocusHighlightPath' );
  var inherit = require( 'PHET_CORE/inherit' );
  var joist = require( 'JOIST/joist' );
  var JoistA11yStrings = require( 'JOIST/JoistA11yStrings' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Shape = require( 'KITE/Shape' );
  var SunA11yStrings = require( 'SUN/SunA11yStrings' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Text = require( 'SCENERY/nodes/Text' );

  // constants
  var CLOSE_BUTTON_WIDTH = 7;
  var CLOSE_BUTTON_MARGIN = 10;
  var HELP_CONTENT_MARGIN = 15;
  var TITLE_MAX_WIDTH = 500;

  // string
  var keyboardShortcutsTitleString = require( 'string!JOIST/keyboardShortcuts.title' );

  // a11y string
  var closeString = SunA11yStrings.close.value;
  var hotKeysAndHelpString = JoistA11yStrings.hotKeysAndHelp.value;

  /**
   * Constructor.
   * @param {KeyboardHelpButton} keyboardHelpButton
   * @param {Node} helpContent - a node containing the sim specific keyboard help content
   * @param {Object} [options]
   * @constructor
   */
  function KeyboardHelpDialog( keyboardHelpButton, helpContent, options ) {

    // title
    var titleText = new Text( keyboardShortcutsTitleString, {
      font: new PhetFont( {
        weight: 'bold',
        size: 18
      } ),
      maxWidth: TITLE_MAX_WIDTH,

      // a11y options
      tagName: 'h1',
      innerContent: hotKeysAndHelpString
    } );

    options = _.extend( {
      titleAlign: 'center',
      title: titleText,
      modal: true,
      hasCloseButton: false,
      fill: 'rgb( 214, 237, 249 )',
      xMargin: HELP_CONTENT_MARGIN,
      yMargin: HELP_CONTENT_MARGIN,
      titleSpacing: HELP_CONTENT_MARGIN,
      focusOnCloseNode: keyboardHelpButton,
      tandem: Tandem.required
    }, options );

    // help content surrounded by a div unless already specified, so that all content is read when dialog opens
    helpContent.tagName = helpContent.tagName || 'div';

    // shape and path for a custom close button
    var closeButtonShape = new Shape();
    closeButtonShape.moveTo( -CLOSE_BUTTON_WIDTH, -CLOSE_BUTTON_WIDTH ).lineTo( CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_WIDTH );
    closeButtonShape.moveTo( CLOSE_BUTTON_WIDTH, -CLOSE_BUTTON_WIDTH ).lineTo( -CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_WIDTH );

    // @public (joist-internal)
    this.closeButtonPath = new Path( closeButtonShape, {
      stroke: 'black',
      lineCap: 'round',
      lineWidth: 2,
      cursor: 'pointer',
      tandem: options.tandem.createTandem( 'closeButtonPath' ),

      // a11y
      tagName: 'button',
      innerContent: closeString
    } );
    var dilationCoefficient = FocusHighlightPath.getDilationCoefficient( this.closeButtonPath );
    this.closeButtonPath.focusHighlight = Shape.bounds( closeButtonShape.getBounds().dilated( dilationCoefficient ) );

    // add a listener to hide the dialog
    var self = this;
    var buttonListener = new ButtonListener( {
      down: function() {
        self.hide();
      }
    } );
    this.closeButtonPath.addInputListener( buttonListener );

    // mouse/touch areas for the close button
    var areaX = this.closeButtonPath.left - this.closeButtonPath.width * 2;
    var areaY = this.closeButtonPath.top - CLOSE_BUTTON_MARGIN / 2;
    var width = this.closeButtonPath.width * 4;
    var height = this.closeButtonPath.height + CLOSE_BUTTON_MARGIN;
    this.closeButtonPath.mouseArea = Shape.rect( areaX, areaY, width, height );
    this.closeButtonPath.touchArea = this.closeButtonPath.mouseArea;

    Dialog.call( this, helpContent, options );

    // position and add the close button
    this.closeButtonPath.right = helpContent.right + 2 * HELP_CONTENT_MARGIN - CLOSE_BUTTON_MARGIN;
    this.closeButtonPath.top = helpContent.top + CLOSE_BUTTON_MARGIN;
    this.addChild( this.closeButtonPath );

    // a11y - the close button comes first so that the remaining content can easily be read with the screen reader's
    // virtual cursor
    this.accessibleOrder = [ this.closeButtonPath, titleText ];

    // @private (a11y) - input listener for the close button, must be disposed
    var clickListener = this.closeButtonPath.addAccessibleInputListener( {
        click: function() {
          self.hide();
          self.focusActiveElement();
        }
      }
    );

    // @private - to be called by dispose
    this.disposeKeyboardHelpDialog = function() {
      self.closeButtonPath.removeInputListener( buttonListener );
      self.closeButtonPath.removeAccessibleInputListener( clickListener );
    };
  }

  joist.register( 'KeyboardHelpDialog', KeyboardHelpDialog );

  return inherit( Dialog, KeyboardHelpDialog, {

    /**
     * So the Dialog is eligible for garbage collection.
     */
    dispose: function() {
      this.disposeKeyboardHelpDialog();
      Dialog.prototype.dispose.call( this );
    }
  } );
} );<commit_msg>update usage of addAccessibleInputListener, see phetsims/scenery#764<commit_after>// Copyright 2016-2018, University of Colorado Boulder

/**
 * Shows a Dialog with content describing keyboard interactions. Brought up by a button
 * in the navigation bar.
 *
 * @author Jesse Greenberg
 */
define( function( require ) {
  'use strict';

  // modules
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );
  var Dialog = require( 'SUN/Dialog' );
  var FocusHighlightPath = require( 'SCENERY/accessibility/FocusHighlightPath' );
  var inherit = require( 'PHET_CORE/inherit' );
  var joist = require( 'JOIST/joist' );
  var JoistA11yStrings = require( 'JOIST/JoistA11yStrings' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Shape = require( 'KITE/Shape' );
  var SunA11yStrings = require( 'SUN/SunA11yStrings' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Text = require( 'SCENERY/nodes/Text' );

  // constants
  var CLOSE_BUTTON_WIDTH = 7;
  var CLOSE_BUTTON_MARGIN = 10;
  var HELP_CONTENT_MARGIN = 15;
  var TITLE_MAX_WIDTH = 500;

  // string
  var keyboardShortcutsTitleString = require( 'string!JOIST/keyboardShortcuts.title' );

  // a11y string
  var closeString = SunA11yStrings.close.value;
  var hotKeysAndHelpString = JoistA11yStrings.hotKeysAndHelp.value;

  /**
   * Constructor.
   * @param {KeyboardHelpButton} keyboardHelpButton
   * @param {Node} helpContent - a node containing the sim specific keyboard help content
   * @param {Object} [options]
   * @constructor
   */
  function KeyboardHelpDialog( keyboardHelpButton, helpContent, options ) {

    // title
    var titleText = new Text( keyboardShortcutsTitleString, {
      font: new PhetFont( {
        weight: 'bold',
        size: 18
      } ),
      maxWidth: TITLE_MAX_WIDTH,

      // a11y options
      tagName: 'h1',
      innerContent: hotKeysAndHelpString
    } );

    options = _.extend( {
      titleAlign: 'center',
      title: titleText,
      modal: true,
      hasCloseButton: false,
      fill: 'rgb( 214, 237, 249 )',
      xMargin: HELP_CONTENT_MARGIN,
      yMargin: HELP_CONTENT_MARGIN,
      titleSpacing: HELP_CONTENT_MARGIN,
      focusOnCloseNode: keyboardHelpButton,
      tandem: Tandem.required
    }, options );

    // help content surrounded by a div unless already specified, so that all content is read when dialog opens
    helpContent.tagName = helpContent.tagName || 'div';

    // shape and path for a custom close button
    var closeButtonShape = new Shape();
    closeButtonShape.moveTo( -CLOSE_BUTTON_WIDTH, -CLOSE_BUTTON_WIDTH ).lineTo( CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_WIDTH );
    closeButtonShape.moveTo( CLOSE_BUTTON_WIDTH, -CLOSE_BUTTON_WIDTH ).lineTo( -CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_WIDTH );

    // @public (joist-internal)
    this.closeButtonPath = new Path( closeButtonShape, {
      stroke: 'black',
      lineCap: 'round',
      lineWidth: 2,
      cursor: 'pointer',
      tandem: options.tandem.createTandem( 'closeButtonPath' ),

      // a11y
      tagName: 'button',
      innerContent: closeString
    } );
    var dilationCoefficient = FocusHighlightPath.getDilationCoefficient( this.closeButtonPath );
    this.closeButtonPath.focusHighlight = Shape.bounds( closeButtonShape.getBounds().dilated( dilationCoefficient ) );

    // add a listener to hide the dialog
    var self = this;
    var buttonListener = new ButtonListener( {
      down: function() {
        self.hide();
      }
    } );
    this.closeButtonPath.addInputListener( buttonListener );

    // mouse/touch areas for the close button
    var areaX = this.closeButtonPath.left - this.closeButtonPath.width * 2;
    var areaY = this.closeButtonPath.top - CLOSE_BUTTON_MARGIN / 2;
    var width = this.closeButtonPath.width * 4;
    var height = this.closeButtonPath.height + CLOSE_BUTTON_MARGIN;
    this.closeButtonPath.mouseArea = Shape.rect( areaX, areaY, width, height );
    this.closeButtonPath.touchArea = this.closeButtonPath.mouseArea;

    Dialog.call( this, helpContent, options );

    // position and add the close button
    this.closeButtonPath.right = helpContent.right + 2 * HELP_CONTENT_MARGIN - CLOSE_BUTTON_MARGIN;
    this.closeButtonPath.top = helpContent.top + CLOSE_BUTTON_MARGIN;
    this.addChild( this.closeButtonPath );

    // a11y - the close button comes first so that the remaining content can easily be read with the screen reader's
    // virtual cursor
    this.accessibleOrder = [ this.closeButtonPath, titleText ];

    // @private (a11y) - input listener for the close button, must be disposed
    var clickListener = {
      click: function() {
        self.hide();
        self.focusActiveElement();
      }
    };
    this.addAccessibleInputListener( clickListener );

    // @private - to be called by dispose
    this.disposeKeyboardHelpDialog = function() {
      self.closeButtonPath.removeInputListener( buttonListener );
      self.closeButtonPath.removeAccessibleInputListener( clickListener );
    };
  }

  joist.register( 'KeyboardHelpDialog', KeyboardHelpDialog );

  return inherit( Dialog, KeyboardHelpDialog, {

    /**
     * So the Dialog is eligible for garbage collection.
     */
    dispose: function() {
      this.disposeKeyboardHelpDialog();
      Dialog.prototype.dispose.call( this );
    }
  } );
} );<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  name: 'SearchController',
  package: 'foam.navigator',
  extendsModel: 'View',
  requires: [
    'foam.navigator.views.GSnippet',
    'foam.navigator.views.EMailGSnippet',
    'foam.navigator.views.ContactGSnippet',
    'foam.navigator.views.IssueGSnippet',
    'foam.navigator.views.PhoneGSnippet',
    'foam.navigator.views.TodoGSnippet',
    'foam.navigator.views.AudioGSnippet',
    'foam.navigator.BrowserConfig',
    'foam.navigator.FOAMlet',
    'foam.navigator.IssueConfig',
    'foam.navigator.dao.MultiDAO',
    'foam.navigator.types.Issue',
    'foam.navigator.types.Mail',
    'foam.navigator.types.Todo',
    'foam.navigator.types.Audio',
    'foam.core.dao.VersionNoDAO',
    'CachingDAO',
    'IDBDAO',
    'com.google.mail.FOAMGMailMessage',
    'foam.lib.email.EMail',
    'MDAO',
    'com.google.mail.GMailToEMailDAO',
    'foam.lib.contacts.Contact',
    'Phone'
  ],
  imports: [
    'window'
  ],
  properties: [
    {
      name: 'configDao',
      factory: function() {
        var self = this;

        return [
          this.BrowserConfig.create({
            model: 'foam.navigator.types.Todo',
            dao: this.CachingDAO.create({
              src: this.IDBDAO.create({
                model: this.Todo,
                useSimpleSerialization: false
              }),
              delegate: this.MDAO.create({ model: this.Audio })
            })
          }),
          this.BrowserConfig.create({
            model: 'foam.navigator.types.Audio',
            dao: this.CachingDAO.create({
              src: this.IDBDAO.create({
                model: this.Audio,
                useSimpleSerialization: false
              }),
              delegate: this.MDAO.create({ model: this.Audio })
            })
          }),
          this.IssueConfig.create(),
          this.BrowserConfig.create({
            model: 'foam.lib.email.EMail',
            dao: this.CachingDAO.create({
              src: this.GMailToEMailDAO.create({
                delegate: this.VersionNoDAO.create({
                  delegate: this.CachingDAO.create({
                    delegate: this.MDAO.create({ model: this.FOAMGMailMessage }),
                    src: this.IDBDAO.create({
                      model: this.FOAMGMailMessage, useSimpleSerialization: false
                    })
                  }),
                  property: this.FOAMGMailMessage.CLIENT_VERSION
                })
              }),
              delegate: this.MDAO.create({ model: this.EMail })
            })
          }),
          this.BrowserConfig.create({
            model: this.Contact,
            dao: this.CachingDAO.create({
              src: this.IDBDAO.create({
                model: this.Contact,
                useSimpleSerialization: false
              }),
              delegate: this.MDAO.create({ model: this.Contact })
            })
          }),
          this.BrowserConfig.create({
            model: this.Phone,
            dao: phones
          })
        ].dao;
      },
      postSet: function(_, value) {
        for ( var i = 0; i < value.length; i++ ) {
          var config = value[i];
          this.X[config.model.name + 'DAO'] = config.dao;
        }
      }
    },
    {
      model_: 'DAOProperty',
      name: 'dao',
      factory: function() {
        return this.MultiDAO.create({ configDAO: this.configDao });
      }
    },
    {
      name: 'logo',
      defaultValue: 'https://www.google.ca/images/srpr/logo11w.png',
      view: 'ImageView'
    },
    {
      model_: 'StringProperty',
      name: 'query',
      postSet: function(old, nu) { if (nu) this.expanded = true; }
    },
    {
      model_: 'DAOProperty',
      name: 'filteredDao',
      view: {
        factory_: 'DAOListView',
        rowView: 'foam.navigator.views.GSnippet'
      }
    },
    {
      model_: 'BooleanProperty',
      name: 'expanded',
      defaultValue: false,
      postSet: function(old, nu) {
        if ( old != nu ) this.updateHTML();
      }
    },
    {
      name: 'modelNames',
      factory: function() {
        return [
          'All',
          'EMail',
          'Todo',
          'Audio',
          'Contacts'
        ].sink;
      }
    },
    {
      name: 'modelFilter',
      defaultValue: 'All',
      view: { factory_: 'ChoiceListView', extraClassName: 'model-names' }
    }
  ],
  methods: {
    init: function() {
      this.SUPER();
      Events.dynamic(
        function() { this.dao; this.query; this.modelFilter }.bind(this),
        function() {
          var modelQuery = this.modelFilter === 'All' ? TRUE :
              EQ(this.FOAMlet.TYPE, this.modelFilter);
          this.filteredDao = this.dao &&
              this.dao.where(AND(modelQuery, MQL(this.query))).limit(10);
        }.bind(this));
      this.maybeLoadData('Todo', 'Audio');
    },
    updateHTML: function() {
      if ( ! this.$ ) return;
      this.$.outerHTML = this.toHTML();
      this.initHTML();
    },
    initHTML: function() {
      this.SUPER();
      // TODO: Hack, should views should have a focus() method?
      this.queryView.$.focus();
    },
    toHTML: function() {
      return this.expanded ? this.expandedHTML() : this.collapsedHTML();
    },
    maybeLoadData: function() {
      var args = argsToArray(arguments);
      args.forEach(function(modelName) {
        this.dao.where(EQ(this.FOAMlet.TYPE, modelName)).select(COUNT())(
            function(res) {
              if ( res.count <= 0 && this.window[modelName + 'Data']) {
                console.log('Adding canned data for ' + modelName);
                this.window[modelName + 'Data'].forEach(function(item) {
                  console.log('Putting', item, 'for', modelName);
                  this.dao.put(item);
                }.bind(this));
              }
            }.bind(this));
      }.bind(this));
    }
  },
  templates: [
    function CSS() {/*
      .searchBox {
        width: 523px;
        font: 16px arial,sans-serif;
        flex-grow: 0;
        flex-string: 0;
      }
      body {
        margin: 0;
        padding: 0;
        border: 0;
      }

      .search-results {
        padding: 20px 80px;
      }
      .filters {
        border-bottom: 1px solid #ccc;
        padding-left: 70px;
        width: 100%;
      }
      .model-names .choice {
        margin: 0;
        padding: 0 12px 10px;
        cursor: pointer;
      }
      .model-names .choice.selected {
        border-bottom: 3px solid #dd4b39;
        color: #dd4b39;
      }
    */},
    function expandedHTML() {/*
      <div id="<%= this.id %>">

          <div style="display: inline-block; flex-grow: 0; flex-shrink: 0; padding-right: 12px; margin-left: 12px; background: url('<%= this.logo %>') no-repeat; background-size: 92px 33px; height: 33px; width: 92px">

          $$query{ onKeyMode: true, extraClassName: 'searchBox' }

$$modelFilter{ choices: this.modelNames }

$$filteredDao

    */},
    function collapsedHTML() {/*
      <div id="<%= this.id %>" style="padding-top: 120px">

          <div style="background: url('<%= this.logo %>') no-repeat; background-size: 269px 95px; height: 95px; width:269px; padding-bottom: 20px">

$$query{ onKeyMode: true, extraClassName: 'searchBox' }

$$filteredDao

 */}
  ]
});
<commit_msg>Add hard dependencies on auxillary contacts models until IDBDAO knows to use the work feature of JSONUtil.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  name: 'SearchController',
  package: 'foam.navigator',
  extendsModel: 'View',
  requires: [
    'foam.navigator.views.GSnippet',
    'foam.navigator.views.EMailGSnippet',
    'foam.navigator.views.ContactGSnippet',
    'foam.navigator.views.IssueGSnippet',
    'foam.navigator.views.PhoneGSnippet',
    'foam.navigator.views.TodoGSnippet',
    'foam.navigator.views.AudioGSnippet',
    'foam.navigator.BrowserConfig',
    'foam.navigator.FOAMlet',
    'foam.navigator.IssueConfig',
    'foam.navigator.dao.MultiDAO',
    'foam.navigator.types.Issue',
    'foam.navigator.types.Mail',
    'foam.navigator.types.Todo',
    'foam.navigator.types.Audio',
    'foam.core.dao.VersionNoDAO',
    'CachingDAO',
    'IDBDAO',
    'com.google.mail.FOAMGMailMessage',
    'foam.lib.email.EMail',
    'MDAO',
    'com.google.mail.GMailToEMailDAO',
    'foam.lib.contacts.Contact',
    'foam.lib.contacts.Address',
    'foam.lib.contacts.PhoneNumber',
    'Phone'
  ],
  imports: [
    'window'
  ],
  properties: [
    {
      name: 'configDao',
      factory: function() {
        var self = this;

        return [
          this.BrowserConfig.create({
            model: 'foam.navigator.types.Todo',
            dao: this.CachingDAO.create({
              src: this.IDBDAO.create({
                model: this.Todo,
                useSimpleSerialization: false
              }),
              delegate: this.MDAO.create({ model: this.Audio })
            })
          }),
          this.BrowserConfig.create({
            model: 'foam.navigator.types.Audio',
            dao: this.CachingDAO.create({
              src: this.IDBDAO.create({
                model: this.Audio,
                useSimpleSerialization: false
              }),
              delegate: this.MDAO.create({ model: this.Audio })
            })
          }),
          this.IssueConfig.create(),
          this.BrowserConfig.create({
            model: 'foam.lib.email.EMail',
            dao: this.CachingDAO.create({
              src: this.GMailToEMailDAO.create({
                delegate: this.VersionNoDAO.create({
                  delegate: this.CachingDAO.create({
                    delegate: this.MDAO.create({ model: this.FOAMGMailMessage }),
                    src: this.IDBDAO.create({
                      model: this.FOAMGMailMessage, useSimpleSerialization: false
                    })
                  }),
                  property: this.FOAMGMailMessage.CLIENT_VERSION
                })
              }),
              delegate: this.MDAO.create({ model: this.EMail })
            })
          }),
          this.BrowserConfig.create({
            model: this.Contact,
            dao: this.CachingDAO.create({
              src: this.IDBDAO.create({
                model: this.Contact,
                useSimpleSerialization: false
              }),
              delegate: this.MDAO.create({ model: this.Contact })
            })
          }),
          this.BrowserConfig.create({
            model: this.Phone,
            dao: phones
          })
        ].dao;
      },
      postSet: function(_, value) {
        for ( var i = 0; i < value.length; i++ ) {
          var config = value[i];
          this.X[config.model.name + 'DAO'] = config.dao;
        }
      }
    },
    {
      model_: 'DAOProperty',
      name: 'dao',
      factory: function() {
        return this.MultiDAO.create({ configDAO: this.configDao });
      }
    },
    {
      name: 'logo',
      defaultValue: 'https://www.google.ca/images/srpr/logo11w.png',
      view: 'ImageView'
    },
    {
      model_: 'StringProperty',
      name: 'query',
      postSet: function(old, nu) { if (nu) this.expanded = true; }
    },
    {
      model_: 'DAOProperty',
      name: 'filteredDao',
      view: {
        factory_: 'DAOListView',
        rowView: 'foam.navigator.views.GSnippet'
      }
    },
    {
      model_: 'BooleanProperty',
      name: 'expanded',
      defaultValue: false,
      postSet: function(old, nu) {
        if ( old != nu ) this.updateHTML();
      }
    },
    {
      name: 'modelNames',
      factory: function() {
        return [
          'All',
          'EMail',
          'Todo',
          'Audio',
          'Contacts'
        ].sink;
      }
    },
    {
      name: 'modelFilter',
      defaultValue: 'All',
      view: { factory_: 'ChoiceListView', extraClassName: 'model-names' }
    }
  ],
  methods: {
    init: function() {
      this.SUPER();
      Events.dynamic(
        function() { this.dao; this.query; this.modelFilter }.bind(this),
        function() {
          var modelQuery = this.modelFilter === 'All' ? TRUE :
              EQ(this.FOAMlet.TYPE, this.modelFilter);
          this.filteredDao = this.dao &&
              this.dao.where(AND(modelQuery, MQL(this.query))).limit(10);
        }.bind(this));
      this.maybeLoadData('Todo', 'Audio');
    },
    updateHTML: function() {
      if ( ! this.$ ) return;
      this.$.outerHTML = this.toHTML();
      this.initHTML();
    },
    initHTML: function() {
      this.SUPER();
      // TODO: Hack, should views should have a focus() method?
      this.queryView.$.focus();
    },
    toHTML: function() {
      return this.expanded ? this.expandedHTML() : this.collapsedHTML();
    },
    maybeLoadData: function() {
      var args = argsToArray(arguments);
      args.forEach(function(modelName) {
        this.dao.where(EQ(this.FOAMlet.TYPE, modelName)).select(COUNT())(
            function(res) {
              if ( res.count <= 0 && this.window[modelName + 'Data']) {
                console.log('Adding canned data for ' + modelName);
                this.window[modelName + 'Data'].forEach(function(item) {
                  console.log('Putting', item, 'for', modelName);
                  this.dao.put(item);
                }.bind(this));
              }
            }.bind(this));
      }.bind(this));
    }
  },
  templates: [
    function CSS() {/*
      .searchBox {
        width: 523px;
        font: 16px arial,sans-serif;
        flex-grow: 0;
        flex-string: 0;
      }
      body {
        margin: 0;
        padding: 0;
        border: 0;
      }

      .search-results {
        padding: 20px 80px;
      }
      .filters {
        border-bottom: 1px solid #ccc;
        padding-left: 70px;
        width: 100%;
      }
      .model-names .choice {
        margin: 0;
        padding: 0 12px 10px;
        cursor: pointer;
      }
      .model-names .choice.selected {
        border-bottom: 3px solid #dd4b39;
        color: #dd4b39;
      }
    */},
    function expandedHTML() {/*
      <div id="<%= this.id %>">

          <div style="display: inline-block; flex-grow: 0; flex-shrink: 0; padding-right: 12px; margin-left: 12px; background: url('<%= this.logo %>') no-repeat; background-size: 92px 33px; height: 33px; width: 92px">

          $$query{ onKeyMode: true, extraClassName: 'searchBox' }

$$modelFilter{ choices: this.modelNames }

$$filteredDao

    */},
    function collapsedHTML() {/*
      <div id="<%= this.id %>" style="padding-top: 120px">

          <div style="background: url('<%= this.logo %>') no-repeat; background-size: 269px 95px; height: 95px; width:269px; padding-bottom: 20px">

$$query{ onKeyMode: true, extraClassName: 'searchBox' }

$$filteredDao

 */}
  ]
});
<|endoftext|>