<commit_before>// @flow
import { NARROW_SPACE, WIDE_SPACE, NARROW_BAR, WIDE_BAR } from "../Core/Characters"

export function rect(x: number, height: number, width: number, filled: boolean): string {
	return `<rect x="${x}" y="0" width="${width}" height="${height}" fill="${filled ? "black" : "white"}"/>`
}

export function renderBarcodeToSVG(input: string, height: number, baseWidth: number): string {
	let svg = ""
	let x = 0

	for (const char of input) {
		switch (char) {
			case NARROW_SPACE:
				svg += rect(x, height, baseWidth, false)
				x += baseWidth
				break
			case WIDE_SPACE:
				svg += rect(x, height, baseWidth * 3, false)
				x += baseWidth * 3
				break
			case NARROW_BAR:
				svg += rect(x, height, baseWidth, true)
				x += baseWidth
				break
			case WIDE_BAR:
				svg += rect(x, height, baseWidth * 3, true)
				x += baseWidth * 3
				break
		}
	}

	return `<svg viewBox="0 0 ${x} ${height}">${svg}</svg>`
}
<commit_msg>Make SVG dimensions normalized and remove width and height attrs.<commit_after>// @flow
import { NARROW_SPACE, WIDE_SPACE, NARROW_BAR, WIDE_BAR } from "../Core/Characters"

const NARROW_WIDTH = 1
const WIDE_WIDTH = 3

export function rect(x: number, wide: boolean, filled: boolean): string {
	return `<rect x="${x}" y="0" width="${wide ? WIDE_WIDTH : NARROW_WIDTH}" height="1" fill="${filled ? "black" : "white"}"/>`
}

export function renderBarcodeToSVG(input: string): string {
	let svg = ""
	let x = 0

	for (const char of input) {
		switch (char) {
			case NARROW_SPACE:
				svg += rect(x, false, false)
				x += NARROW_WIDTH
				break
			case WIDE_SPACE:
				svg += rect(x, true, false)
				x += WIDE_WIDTH
				break
			case NARROW_BAR:
				svg += rect(x, false, true)
				x += NARROW_WIDTH
				break
			case WIDE_BAR:
				svg += rect(x, true, true)
				x += WIDE_WIDTH
				break
		}
	}

	return `<svg viewBox="0 0 ${x} 1">${svg}</svg>`
}
<|endoftext|>


<commit_before>import React, { useState, useEffect } from "react";
import Button from "@agir/front/genericComponents/Button";
import TextField from "@agir/front/formComponents/TextField";
import SelectField from "@agir/front/formComponents/SelectField";
import styled from "styled-components";
import style from "@agir/front/genericComponents/_variables.scss";
import helloDesktop from "@agir/front/genericComponents/images/hello-desktop.svg";
import { updateProfile, getProfile } from "@agir/front/authentication/api";

const LeftBlock = styled.div`
  width: 40%;
  height: 100vh;
  display: flex;
  position: relative;
  align-items: center;
  justify-content: flex-end;
  @media (max-width: ${style.collapse}px) {
    display: none;
  }
`;

const MainBlock = styled.div`
  width: 60%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  font-size: 13px;
  padding: 32px;

  input {
    border-color: #c4c4c4;
  }
  label {
    font-weight: 600;
  }

  h1 {
    margin: 0px;
    margin-bottom: 1.125rem;
    font-weight: 700;
    font-size: 2rem;
  }

  @media (max-width: ${style.collapse}px) {
    width: 100%;
  }
`;

const InputGroup = styled.div`
  display: inline-flex;
  justify-content: space-between;
  width: 100%;
  > div:nth-child(1) {
    width: 155px;
  }
  > div:nth-child(2) {
    width: 346px;
  }

  @media (max-width: ${style.collapse}px) {
    display:block;
    > div:nth-child(1) {
      width: 100%;
    }
    > div:nth-child(2) {
      width: 100%;
  }
`;

const InputCheckbox = styled.div`
  display: flex;
  cursor: pointer;
  user-select: none;
  margin-top: 0.625rem;
`;

const optional = (facultatif);
const defaultData = {
  displayName: "",
  firstName: "",
  lastName: "",
  phone: "",
  postalCode: "",
  mandates: [],
};
const mandatList = [
  {
    label: "Maire",
    value: "maire",
  },
  {
    label: "Autre mandat municipal",
    value: "municipal",
  },
  {
    label: "Mandat départemental",
    value: "departemental",
  },
  {
    label: "Mandat régional",
    value: "regional",
  },
];

const TellMore = ({ dismiss }) => {
  const [formData, setFormData] = useState(defaultData);
  const [error, setError] = useState({});
  const [showMandate, setShowMandate] = useState(false);
  const [submitted, setSubmitted] = useState(false);
  const [mandat, setMandat] = useState(mandatList[0]);

  const getProfileInfos = async () => {
    const { data } = await getProfile();

    setFormData({
      displayName: data.displayName,
      firstName: data.firstName,
      lastName: data.lastName,
      phone: data.contactPhone,
      postalCode: data.zip,
      mandates: data.mandates,
    });
    setShowMandate(data.mandates?.length > 0);
  };

  useEffect(() => {
    getProfileInfos();
  }, []);

  const handleInputChange = (e) => {
    const newFormData = { ...formData };
    newFormData[e.target.name] = e.target.value;
    setFormData(newFormData);
  };

  const toggleShowMandate = () => setShowMandate(!showMandate);

  const handleMandateChange = (e) => {
    setMandat(e);
    setFormData({ ...formData, mandates: [e.value] });
  };

  const handleSubmit = async () => {
    setSubmitted(true);
    setError({});
    const data = await updateProfile(formData);
    setSubmitted(false);
    if (data.error) {
      setError(data.error);
      return;
    }
    dismiss();
  };

  return (

      <LeftBlock>

      </LeftBlock>
      <MainBlock>

J’en dis plus sur moi

          Nom public (obligatoire)

            Le nom que tout le monde pourra voir. Indiquez par exemple votre
            prénom ou un pseudonyme.

          <TextField
            error={error && error.displayName}
            name="displayName"
            placeholder="Exemple : Marie R."
            onChange={handleInputChange}
            value={formData.displayName}
          />
          <TextField
            label={<>Prénom {optional}</>}
            name="firstName"
            placeholder=""
            onChange={handleInputChange}
            value={formData.firstName}
          />
          <TextField
            label={<>Nom {optional}</>}
            id="lastName"
            name="lastName"
            placeholder=""
            onChange={handleInputChange}
            value={formData.lastName}
          />
          <InputGroup>

              <TextField
                label="Code postal"
                id="postalCode"
                error={error && error.zip}
                name="postalCode"
                placeholder=""
                onChange={handleInputChange}
                value={formData.postalCode}
              />

              <TextField
                label={<>Numéro de téléphone {optional}</>}
                id="phone"
                error={error && error.phone}
                name="phone"
                onChange={handleInputChange}
                value={formData.phone}
              />

          </InputGroup>
          <InputCheckbox onClick={toggleShowMandate}>
            <input
              type="checkbox"
              name="mandat"
              checked={showMandate}
              onChange={() => {}}
            />
              J'ai un mandat
          </InputCheckbox>
          {showMandate && (

              <SelectField
                label="Mandat"
                name="mandat"
                placeholder=""
                value={mandat}
                options={mandatList}
                onChange={handleMandateChange}
              />

          )}
          <Button
            color="primary"
            onClick={handleSubmit}
            disabled={submitted}
            style={{
              width: "356px",
              maxWidth: "100%",
              marginTop: "1rem",
              justifyContent: "center",
            }}
          >
            Enregistrer
          </Button>

      </MainBlock>

  );
};

export default TellMore;
<commit_msg>fix: send empty mandat, styles: replace checkbox with generic ChecboxField<commit_after>import React, { useState, useEffect } from "react";
import Button from "@agir/front/genericComponents/Button";
import TextField from "@agir/front/formComponents/TextField";
import SelectField from "@agir/front/formComponents/SelectField";
import CheckboxField from "@agir/front/formComponents/CheckboxField";
import styled from "styled-components";
import style from "@agir/front/genericComponents/_variables.scss";
import helloDesktop from "@agir/front/genericComponents/images/hello-desktop.svg";
import { updateProfile, getProfile } from "@agir/front/authentication/api";

const LeftBlock = styled.div`
  width: 40%;
  height: 100vh;
  display: flex;
  position: relative;
  align-items: center;
  justify-content: flex-end;
  @media (max-width: ${style.collapse}px) {
    display: none;
  }
`;

const MainBlock = styled.div`
  width: 60%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  font-size: 13px;
  padding: 32px;

  input {
    border-color: #c4c4c4;
  }
  label {
    font-weight: 600;
  }

  h1 {
    margin: 0px;
    margin-bottom: 1.125rem;
    font-weight: 700;
    font-size: 2rem;
  }

  @media (max-width: ${style.collapse}px) {
    width: 100%;
  }
`;

const InputGroup = styled.div`
  display: inline-flex;
  justify-content: space-between;
  width: 100%;
  > div:nth-child(1) {
    width: 155px;
  }
  > div:nth-child(2) {
    width: 346px;
  }

  @media (max-width: ${style.collapse}px) {
    display:block;
    > div:nth-child(1) {
      width: 100%;
    }
    > div:nth-child(2) {
      width: 100%;
  }
`;

const optional = (facultatif);
const defaultData = {
  displayName: "",
  firstName: "",
  lastName: "",
  phone: "",
  postalCode: "",
  mandates: [],
};
const mandatList = [
  {
    label: "Maire",
    value: "maire",
  },
  {
    label: "Autre mandat municipal",
    value: "municipal",
  },
  {
    label: "Mandat départemental",
    value: "departemental",
  },
  {
    label: "Mandat régional",
    value: "regional",
  },
];

const TellMore = ({ dismiss }) => {
  const [formData, setFormData] = useState(defaultData);
  const [showMandat, setShowMandat] = useState(false);
  const [mandat, setMandat] = useState([]);
  const [submitted, setSubmitted] = useState(false);
  const [error, setError] = useState({});

  const getProfileInfos = async () => {
    const { data } = await getProfile();

    setFormData({
      displayName: data.displayName,
      firstName: data.firstName,
      lastName: data.lastName,
      phone: data.contactPhone,
      postalCode: data.zip,
      mandates: data.mandates,
    });
    if (data.mandates?.length > 0) {
      setShowMandat(true);
      setMandat(mandatList[0]);
    }
  };

  useEffect(() => {
    getProfileInfos();
  }, []);

  const handleInputChange = (e) => {
    const newFormData = { ...formData };
    newFormData[e.target.name] = e.target.value;
    setFormData(newFormData);
  };

  const toggleShowMandat = () => {
    const isMandat = !showMandat;
    setShowMandat(isMandat);
    if (isMandat) {
      setMandat(mandatList[0]);
      return;
    }
    setMandat([]);
  };

  const handleMandateChange = (e) => {
    setMandat(e);
    setFormData({ ...formData, mandates: [e.value] });
  };

  const handleSubmit = async () => {
    setSubmitted(true);
    setError({});
    const data = await updateProfile(formData);
    setSubmitted(false);
    if (data.error) {
      setError(data.error);
      return;
    }
    dismiss();
  };

  return (

      <LeftBlock>

      </LeftBlock>
      <MainBlock>

J’en dis plus sur moi

          Nom public (obligatoire)

            Le nom que tout le monde pourra voir. Indiquez par exemple votre
            prénom ou un pseudonyme.

          <TextField
            error={error && error.displayName}
            name="displayName"
            placeholder="Exemple : Marie R."
            onChange={handleInputChange}
            value={formData.displayName}
          />
          <TextField
            label={<>Prénom {optional}</>}
            name="firstName"
            placeholder=""
            onChange={handleInputChange}
            value={formData.firstName}
          />
          <TextField
            label={<>Nom {optional}</>}
            id="lastName"
            name="lastName"
            placeholder=""
            onChange={handleInputChange}
            value={formData.lastName}
          />
          <InputGroup>

              <TextField
                label="Code postal"
                id="postalCode"
                error={error && error.zip}
                name="postalCode"
                placeholder=""
                onChange={handleInputChange}
                value={formData.postalCode}
              />

              <TextField
                label={<>Numéro de téléphone {optional}</>}
                id="phone"
                error={error && error.phone}
                name="phone"
                onChange={handleInputChange}
                value={formData.phone}
              />

          </InputGroup>
          <CheckboxField
            style={{ marginTop: "0.625rem" }}
            name="mandat"
            label="J'ai un mandat"
            value={showMandat}
            onChange={() => toggleShowMandat()}
          />
          {showMandat && (

              <SelectField
                label="Mandat"
                name="mandat"
                value={mandat}
                options={mandatList}
                onChange={handleMandateChange}
              />

          )}
          <Button
            color="primary"
            onClick={handleSubmit}
            disabled={submitted}
            style={{
              width: "356px",
              maxWidth: "100%",
              marginTop: "1rem",
              justifyContent: "center",
            }}
          >
            Enregistrer
          </Button>

      </MainBlock>

  );
};

export default TellMore;
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

require('@babel/polyfill');

const {main} = require('./RelayCompilerMain');
const yargs = require('yargs');

// Collect args
const argv = yargs
  .usage(
    'Create Relay generated files\n\n' +
      '$0 --schema <path> --src <path> [--watch]',
  )
  .options({
    schema: {
      describe: 'Path to schema.graphql or schema.json',
      demandOption: true,
      type: 'string',
    },
    src: {
      describe: 'Root directory of application code',
      demandOption: true,
      type: 'string',
    },
    include: {
      array: true,
      default: ['**'],
      describe: 'Directories to include under src',
      type: 'string',
    },
    exclude: {
      array: true,
      default: [
        '**/node_modules/**',
        '**/__mocks__/**',
        '**/__tests__/**',
        '**/__generated__/**',
      ],
      describe: 'Directories to ignore under src',
      type: 'string',
    },
    extensions: {
      array: true,
      describe:
        'File extensions to compile (defaults to extensions provided by the ' +
        'language plugin)',
      type: 'string',
    },
    verbose: {
      describe: 'More verbose logging',
      type: 'boolean',
    },
    quiet: {
      describe: 'No output to stdout',
      type: 'boolean',
    },
    watchman: {
      describe: 'Use watchman when not in watch mode',
      type: 'boolean',
      default: true,
    },
    watch: {
      describe: 'If specified, watches files and regenerates on changes',
      type: 'boolean',
    },
    validate: {
      describe:
        'Looks for pending changes and exits with non-zero code instead of ' +
        'writing to disk',
      type: 'boolean',
      default: false,
    },
    'persist-output': {
      describe:
        'A path to a .json file where persisted query metadata should be saved',
    },
    noFutureProofEnums: {
      describe:
        'This option controls whether or not a catch-all entry is added to enum type definitions ' +
        'for values that may be added in the future. Enabling this means you will have to update ' +
        'your application whenever the GraphQL server schema adds new enum values to prevent it ' +
        'from breaking.',
      default: false,
    },
    language: {
      describe:
        'The name of the language plugin used for input files and artifacts',
      type: 'string',
      default: 'javascript',
    },
    artifactDirectory: {
      describe:
        'A specific directory to output all artifacts to. When enabling this ' +
        'the babel plugin needs `artifactDirectory` set as well.',
      type: 'string',
      default: null,
    },
  })
  .help().argv;

// Run script with args
// $FlowFixMe: Invalid types for yargs. Please fix this when touching this code.
main(argv).catch(error => {
  console.error(String(error.stack || error));
  process.exit(1);
});
<commit_msg>Add __tests__ to the default compiler configuration<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

require('@babel/polyfill');

const {main} = require('./RelayCompilerMain');
const yargs = require('yargs');

// Collect args
const argv = yargs
  .usage(
    'Create Relay generated files\n\n' +
      '$0 --schema <path> --src <path> [--watch]',
  )
  .options({
    schema: {
      describe: 'Path to schema.graphql or schema.json',
      demandOption: true,
      type: 'string',
    },
    src: {
      describe: 'Root directory of application code',
      demandOption: true,
      type: 'string',
    },
    include: {
      array: true,
      default: ['**'],
      describe: 'Directories to include under src',
      type: 'string',
    },
    exclude: {
      array: true,
      default: ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'],
      describe: 'Directories to ignore under src',
      type: 'string',
    },
    extensions: {
      array: true,
      describe:
        'File extensions to compile (defaults to extensions provided by the ' +
        'language plugin)',
      type: 'string',
    },
    verbose: {
      describe: 'More verbose logging',
      type: 'boolean',
    },
    quiet: {
      describe: 'No output to stdout',
      type: 'boolean',
    },
    watchman: {
      describe: 'Use watchman when not in watch mode',
      type: 'boolean',
      default: true,
    },
    watch: {
      describe: 'If specified, watches files and regenerates on changes',
      type: 'boolean',
    },
    validate: {
      describe:
        'Looks for pending changes and exits with non-zero code instead of ' +
        'writing to disk',
      type: 'boolean',
      default: false,
    },
    'persist-output': {
      describe:
        'A path to a .json file where persisted query metadata should be saved',
    },
    noFutureProofEnums: {
      describe:
        'This option controls whether or not a catch-all entry is added to enum type definitions ' +
        'for values that may be added in the future. Enabling this means you will have to update ' +
        'your application whenever the GraphQL server schema adds new enum values to prevent it ' +
        'from breaking.',
      default: false,
    },
    language: {
      describe:
        'The name of the language plugin used for input files and artifacts',
      type: 'string',
      default: 'javascript',
    },
    artifactDirectory: {
      describe:
        'A specific directory to output all artifacts to. When enabling this ' +
        'the babel plugin needs `artifactDirectory` set as well.',
      type: 'string',
      default: null,
    },
  })
  .help().argv;

// Run script with args
// $FlowFixMe: Invalid types for yargs. Please fix this when touching this code.
main(argv).catch(error => {
  console.error(String(error.stack || error));
  process.exit(1);
});
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { getUserPreference } from 'meteor/rocketchat:utils';
import { callbacks } from 'meteor/rocketchat:callbacks';
import { emoji } from '../lib/rocketchat';
import { isSetNotNull } from './function-isSet';
import s from 'underscore.string';

/*
 * emojiParser is a function that will replace emojis
 * @param {Object} message - The message object
 */
callbacks.add('renderMessage', (message) => {
	if (isSetNotNull(() => getUserPreference(Meteor.userId(), 'useEmojis')) &&
		!getUserPreference(Meteor.userId(), 'useEmojis')) {
		return message;
	}

	if (s.trim(message.html)) {
		// ' to apostrophe (') for emojis such as :')
		message.html = message.html.replace(/'/g, '\'');

		Object.keys(emoji.packages).forEach((emojiPackage) => {
			message.html = emoji.packages[emojiPackage].render(message.html);
		});

		const checkEmojiOnly = $(`<div>${ message.html }</div>`);
		let emojiOnly = true;
		for (const childNode in checkEmojiOnly[0].childNodes) {
			if (checkEmojiOnly[0].childNodes.hasOwnProperty(childNode)) {
				const child = $(checkEmojiOnly[0].childNodes[childNode]);

				if (child.hasClass('emoji') || child.hasClass('emojione')) {
					checkEmojiOnly[0].childNodes[childNode] = child.addClass('big');
					continue;
				}

				if (s.trim(child.text()) === '') {
					continue;
				}

				emojiOnly = false;
				break;
			}
		}

		if (emojiOnly) {
			message.html = checkEmojiOnly.unwrap().html();
		}

		// apostrophe (') back to '
		message.html = message.html.replace(/\'/g, ''');
	}

	return message;
}, callbacks.priority.LOW, 'emoji');
<commit_msg>[FIX] Emoji detection at line breaks (#13447)<commit_after>import { Meteor } from 'meteor/meteor';
import { getUserPreference } from 'meteor/rocketchat:utils';
import { callbacks } from 'meteor/rocketchat:callbacks';
import { emoji } from '../lib/rocketchat';
import { isSetNotNull } from './function-isSet';
import s from 'underscore.string';

/*
 * emojiParser is a function that will replace emojis
 * @param {Object} message - The message object
 */
callbacks.add('renderMessage', (message) => {
	if (isSetNotNull(() => getUserPreference(Meteor.userId(), 'useEmojis')) &&
		!getUserPreference(Meteor.userId(), 'useEmojis')) {
		return message;
	}

	if (s.trim(message.html)) {
		// ' to apostrophe (') for emojis such as :')
		message.html = message.html.replace(/'/g, '\'');

		// '
' to '
 ' for emojis such at line breaks
		message.html = message.html.replace(/
/g, '
 ');

		Object.keys(emoji.packages).forEach((emojiPackage) => {
			message.html = emoji.packages[emojiPackage].render(message.html);
		});

		const checkEmojiOnly = $(`<div>${ message.html }</div>`);
		let emojiOnly = true;
		for (const childNode in checkEmojiOnly[0].childNodes) {
			if (checkEmojiOnly[0].childNodes.hasOwnProperty(childNode)) {
				const child = $(checkEmojiOnly[0].childNodes[childNode]);

				if (child.hasClass('emoji') || child.hasClass('emojione')) {
					checkEmojiOnly[0].childNodes[childNode] = child.addClass('big');
					continue;
				}

				if (s.trim(child.text()) === '') {
					continue;
				}

				emojiOnly = false;
				break;
			}
		}

		if (emojiOnly) {
			message.html = checkEmojiOnly.unwrap().html();
		}

		// apostrophe (') back to '
		message.html = message.html.replace(/\'/g, ''');

		// apostrophe '
 ' back to '
'
		message.html = message.html.replace(/
 /g, '
');
	}

	return message;
}, callbacks.priority.LOW, 'emoji');
<|endoftext|>


<commit_before>// ==========================================================================
// Project:  SproutCore Runtime
// Copyright: ©2011 Strobe Inc. and contributors.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

require('sproutcore-touch/system/gestures');
require('sproutcore-touch/system/gesture_manager');
require('sproutcore-touch/system/touch_list');

var get = SC.get;
var set = SC.set;

var sigFigs = 100;

/**
  @class

  Base class for all gesture recognizers. Handles low-level touch and state
  management, and provides some utility methods and some required methods all
  gesture recognizers are expected to implement.

  ## Overview

  Gestures coalesce multiple touch events to a single higher-level gesture
  event. For example, a tap gesture recognizer takes information about a
  touchstart event, a few touchmove events, and a touchend event and uses
  some heuristics to decide whether or not that sequence of events qualifies
  as a tap event. If it does, then it will notify the view of the higher-level
  tap events.

  Gesture events follow the format:

    * *[GESTURE_NAME]* Start - Sent when a gesture has gathered enough information
        to begin tracking the gesture

    * *[GESTURE_NAME]* Change - Sent when a gesture has already started and has
        received touchmove events that cause its state to change

    * *[GESTURE_NAME]* End - Sent when a touchend event is received and the gesture
        recognizer decides that the gesture is finished.

    * *[GESTURE_NAME]* Cancel - Sent when a touchcancel event is received.

  There are two types of gestures: Discrete and Continuous gestures. In contrast
  to continuous gestures, discrete gestures don't have any change events. Rather,
  the end event is the only one that gets sent to the view.

  ## Usage

  While you wouldn't use SC.Gesture directly, all its subclasses implement the
  same API. For example, to implement pinch on a view, you implement one or more
  of the pinch events. For example:

      var myView = SC.View.create({
        pinchStart: function(recognizer) {
          this.$().css('background','red');
        },

        pinchChange: function(recognizer) {
          var scale = recognizer.get('scale');
          this.$().css('scale',function(index, value) {
            return recognizer.get('scale') * value
          });
        },

        pinchEnd: function(recognizer) {
          this.$().css('background','blue');
        },

        pinchCancel: function(recognizer) {
          this.$().css('background','blue');
        }
      });

  pinchStart(), pinchEnd() and pinchCancel() will only get called once per
  gesture, but pinchChange() will get called repeatedly called every time
  one of the touches moves.

  ## Customizing Gesture Recognizers

  Some of the gesture recognizers include properties that can be customized by
  the user for a specific instance of a view. For example, a pan gesture defaults
  to being a one-finger gesture, but in some scenarios, it must be defined as a
  two-finger gesture. In that case, you can override defaults by specifying an
  Options hash.

      var myView = SC.View.create({
        panOptions: {
          numberOfRequiredTouches: 2
        }
      });

  ## Creating Custom Gesture Recognizers

  SC.Gesture also defines an API which its subclasses can implement to build
  custom gestures. The methods are:

    * **didBecomePossible** - Called when a gesture enters a possible state. This
        means the gesture recognizer has accepted enough touches to match
        the number of required touches. You would usually initialize your state
        in this callback.

    * **eventWasRejected** - Called if a view returns false from a gesture event.
        This callback allows you to reset internal state if the user rejects
        an event.

    * **shouldBegin** - Allows a gesture to block itself from entering a began state.
        This callback will continuously be called as touches move until it begins.

    * **shouldEnd** - Allows a gesture to block itself from entering an ended state.
        This callback gets called whenever a tracked touch gets a touchEnd event.

    * **didBegin** - Called when the gesture enters a began state. Called before the
       view receives the Start event.

    * **didChange** - Called when the gesture enters a began state, and when one of the
        touches moves. Called before the view receives the Change event.

    * **didEnd** - Called when the gesture enters an ended state. Called before the
       view receives the End event.

    * **didCancel** - Called when the gesture enters a cancelled state. Called before the
       view receives the Cancel event.

  In all the callbacks, you can use the `touches` protected property to access the
  touches hash. The touches hash is keyed on the identifiers of the touches, and the
  values are the jQuery.Event objects. You can also access the length property to inspect
  how many touches are active, this is mostly useful in shouldBegin since every other
  callback can assume that there are as many active touches as specified in the
  numberOfRequiredTouches property.

  ## Discrete vs Continuous Gestures

  There are two main classes of gesture recognizers: Discrete and Continuous
  gestures. Discrete gestures do not get Start, Change nor Cancel events sent,
  since they represent a single, instantaneous event, rather than a continuous
  motion. If you are implementing your own discrete gesture recognizer, you must
  set the isDiscreteGesture property to yes, and SC.Gesture will adapt its behavior.

  Discrete gestures use the shouldEnd callback to either accept or decline the gesture
  event. If it is declined, then the gesture will enter a Cancelled state.

  @extends SC.Object
*/

SC.Gesture = SC.Object.extend(
  /** @scope SC.Gesture.prototype */{

  /**
    The current state of the gesture recognizer. This value can be any one
    of the states defined at the end of this file.

    @type Number
  */
  state: null,

  /**
    A string of the gesture recognizer's name. This value is set automatically
    but SC.Gestures when a gesture is registered.

    @type String
  */
  name: null,

  /**
    Specifies whether a gesture is discrete or continuous.

    @type Boolean
    @default false
  */
  gestureIsDiscrete: false,

  /**
    You can use the `touches` protected property to access the touches hash. The touches
    hash is keyed on the identifiers of the touches, and the values are the jQuery.Event
    objects.

    @private
    @type Hash
  */
  touches: null,

  /**
    You can also use the numberOfActiveTouches property to inspect how many touches
    are active, this is mostly useful in shouldBegin since every other callback can
    assume that there are as many active touches as specified in the
    numberOfRequiredTouches property.

    @private
    @type Number
  */
  numberOfActiveTouches: 0,

  /**
    Used to specify the number of touches required for the gesture to enter a possible
    state

    @private
    @type Number
  */
  numberOfRequiredTouches: 1,

  init: function() {
    this._super();
    this.touches = SC.TouchList.create();
  },

  //..............................................
  // Gesture Callbacks

  /** @private */
  didBecomePossible: function() { },

  /** @private */
  shouldBegin: function() {
    return true;
  },

  /** @private */
  didBegin: function() { },

  /** @private */
  didChange: function() { },

  /** @private */
  eventWasRejected: function() { },

  /** @private */
  shouldEnd: function() {
    return true;
  },

  /** @private */
  didEnd: function() { },

  /** @private */
  didCancel: function() { },

  //..............................................
  // Utilities

  /** @private */
  attemptGestureEventDelivery: function(evt, view, eventName) {
    if (this.notifyViewOfGestureEvent(view, eventName) === false) {
      this.eventWasRejected();
    } else {
      evt.preventDefault();
    }
  },

  /**
    Given two Touch objects, this method returns the distance between them.

    @return Number
  */
  distance: function(touches) {

    if (touches.length < 2) {
      return 0;
    }

    var first = touches[0];
    var second = touches[1];

    var x = first.pageX;
    var y = first.pageY;
    var x0 = second.pageX;
    var y0 = second.pageY;

    return Math.sqrt((x -= x0) * x + (y -= y0) * y);
  },

  /**
    Given two Touch objects, this method returns the midpoint between them.

    @return Number
  */
  centerPointForTouches: function(touches) {
    var sumX = 0,
        sumY = 0;

    for (var i=0, l=touches.length; i<l; i++) {
      var touch = touches[i];
      sumX += touch.pageX;
      sumY += touch.pageY;
    }

    var location = {
      x: sumX / touches.length,
      y: sumY / touches.length
    };

    return location;
  },

  /** @private */
  _objectValues: function(object) {
    var ret = [];

    for (var item in object ) {
      if (object.hasOwnProperty(item)) {
        ret.push(object[item]);
      }
    }

    return ret;
  },

  /**
    Allows the gesture to notify the view it's associated with of a gesture
    event.

    @private
  */
  notifyViewOfGestureEvent: function(view, eventName, data) {
    var handler = view[eventName];
    var result = true;

    if (SC.typeOf(handler) === 'function') {
      result = handler.call(view, this, data);
    }

    return result;
  },

  toString: function() {
    return SC.Gesture+'<'+SC.guidFor(this)+'>';
  },

  /** @private */
  _resetState: function() {
    this.touches.removeAllTouches();
  },

  //..............................................
  // Touch event handlers

  /** @private */
  touchStart: function(evt, view, manager) {
    var targetTouches = evt.originalEvent.targetTouches;
    var _touches = this.touches;
    var state = get(this, 'state');

    set(_touches, 'timestamp', Date.now());

    //Collect touches by their identifiers
    for (var i=0, l=targetTouches.length; i<l; i++) {
      var touch = targetTouches[i];

      if(_touches.touchWithId(touch.identifier) === null && _touches.get('length') < get(this, 'numberOfRequiredTouches')) {
        _touches.addTouch(touch);
      }
    }

    if (_touches.get('length') < get(this, 'numberOfRequiredTouches')) {
      set(this ,'state', SC.Gesture.WAITING_FOR_TOUCHES);

    } else {
      // Discrete gestures may skip the possible step if they're ready to begin
      if (get(this, 'gestureIsDiscrete') && this.shouldBegin()) {
        set(this, 'state', SC.Gesture.BEGAN);
        this.didBegin();
        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Start');
      } else {
        set(this, 'state', SC.Gesture.POSSIBLE);
        this.didBecomePossible();
      }
    }

    manager.redispatchEventToView(view,'touchstart', evt);
  },

  /** @private */
  touchMove: function(evt, view, manager) {
    var state = get(this, 'state');

    if (state === SC.Gesture.WAITING_FOR_TOUCHES || state === SC.Gesture.ENDED || state === SC.Gesture.CANCELLED) {
      // Nothing to do here
      manager.redispatchEventToView(view,'touchmove', evt);
      return;
    }

    var changedTouches = evt.originalEvent.changedTouches;
    var _touches = this.touches;

    set(_touches, 'timestamp', Date.now());

    // Update touches hash
    for (var i=0, l=changedTouches.length; i<l; i++) {
      var touch = changedTouches[i];
      _touches.updateTouch(touch);
    }

    if (state === SC.Gesture.POSSIBLE) {
      if (this.shouldBegin()) {
        set(this, 'state', SC.Gesture.BEGAN);
        this.didBegin();

        // Give the gesture a chance to update its state so the view can get
        // updated information in the Start event
        this.didChange();

        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Start');
      }

    // Discrete gestures don't fire changed events
    } else if ((state === SC.Gesture.BEGAN || state === SC.Gesture.CHANGED) && !get(this, 'gestureIsDiscrete')) {
      set(this, 'state', SC.Gesture.CHANGED);
      this.didChange();

      this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Change');

    } else {
      manager.redispatchEventToView(view,'touchmove', evt);
    }
  },

  /** @private */
  touchEnd: function(evt, view, manager) {
    // Discrete gestures need to cancel if they shouldn't end successfully
    if (get(this, 'gestureIsDiscrete')) {

      // Discrete gestures use shouldEnd to either accept or decline the gesture.
      if (this.state === SC.Gesture.BEGAN && this.shouldEnd()) {
        set(this, 'state', SC.Gesture.ENDED);
        this.didEnd();
        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'End');
      } else {
        set(this, 'state', SC.Gesture.CANCELLED);
        this.didCancel();
        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Cancel');
      }
    }
    else {
      if ((this.state === SC.Gesture.BEGAN || this.state === SC.Gesture.CHANGED) && this.shouldEnd()) {
        set(this, 'state', SC.Gesture.ENDED);
        this.didEnd();

        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'End');
      }

      manager.redispatchEventToView(view,'touchend', evt);
    }

    this._resetState();
  },

  /** @private */
  touchCancel: function(evt, view, manager) {
    if (this.state !== SC.Gesture.CANCELLED) {
      this._resetState();
      set(this, 'state', SC.Gesture.CANCELLED);
      this.notifyViewOfGestureEvent(view,get(this, 'name')+'Cancel');
    } else {
      manager.redispatchEventToView(view,'touchcancel', evt);
    }
  }
});

SC.Gesture.WAITING_FOR_TOUCHES = 0;
SC.Gesture.POSSIBLE = 1;
SC.Gesture.BEGAN = 2;
SC.Gesture.CHANGED = 3;
SC.Gesture.ENDED = 4;
SC.Gesture.CANCELLED = 4;
<commit_msg>Fix bug causing tap gesture to eat up scrolling events<commit_after>// ==========================================================================
// Project:  SproutCore Runtime
// Copyright: ©2011 Strobe Inc. and contributors.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

require('sproutcore-touch/system/gestures');
require('sproutcore-touch/system/gesture_manager');
require('sproutcore-touch/system/touch_list');

var get = SC.get;
var set = SC.set;

var sigFigs = 100;

/**
  @class

  Base class for all gesture recognizers. Handles low-level touch and state
  management, and provides some utility methods and some required methods all
  gesture recognizers are expected to implement.

  ## Overview

  Gestures coalesce multiple touch events to a single higher-level gesture
  event. For example, a tap gesture recognizer takes information about a
  touchstart event, a few touchmove events, and a touchend event and uses
  some heuristics to decide whether or not that sequence of events qualifies
  as a tap event. If it does, then it will notify the view of the higher-level
  tap events.

  Gesture events follow the format:

    * *[GESTURE_NAME]* Start - Sent when a gesture has gathered enough information
        to begin tracking the gesture

    * *[GESTURE_NAME]* Change - Sent when a gesture has already started and has
        received touchmove events that cause its state to change

    * *[GESTURE_NAME]* End - Sent when a touchend event is received and the gesture
        recognizer decides that the gesture is finished.

    * *[GESTURE_NAME]* Cancel - Sent when a touchcancel event is received.

  There are two types of gestures: Discrete and Continuous gestures. In contrast
  to continuous gestures, discrete gestures don't have any change events. Rather,
  the end event is the only one that gets sent to the view.

  ## Usage

  While you wouldn't use SC.Gesture directly, all its subclasses implement the
  same API. For example, to implement pinch on a view, you implement one or more
  of the pinch events. For example:

      var myView = SC.View.create({
        pinchStart: function(recognizer) {
          this.$().css('background','red');
        },

        pinchChange: function(recognizer) {
          var scale = recognizer.get('scale');
          this.$().css('scale',function(index, value) {
            return recognizer.get('scale') * value
          });
        },

        pinchEnd: function(recognizer) {
          this.$().css('background','blue');
        },

        pinchCancel: function(recognizer) {
          this.$().css('background','blue');
        }
      });

  pinchStart(), pinchEnd() and pinchCancel() will only get called once per
  gesture, but pinchChange() will get called repeatedly called every time
  one of the touches moves.

  ## Customizing Gesture Recognizers

  Some of the gesture recognizers include properties that can be customized by
  the user for a specific instance of a view. For example, a pan gesture defaults
  to being a one-finger gesture, but in some scenarios, it must be defined as a
  two-finger gesture. In that case, you can override defaults by specifying an
  Options hash.

      var myView = SC.View.create({
        panOptions: {
          numberOfRequiredTouches: 2
        }
      });

  ## Creating Custom Gesture Recognizers

  SC.Gesture also defines an API which its subclasses can implement to build
  custom gestures. The methods are:

    * **didBecomePossible** - Called when a gesture enters a possible state. This
        means the gesture recognizer has accepted enough touches to match
        the number of required touches. You would usually initialize your state
        in this callback.

    * **eventWasRejected** - Called if a view returns false from a gesture event.
        This callback allows you to reset internal state if the user rejects
        an event.

    * **shouldBegin** - Allows a gesture to block itself from entering a began state.
        This callback will continuously be called as touches move until it begins.

    * **shouldEnd** - Allows a gesture to block itself from entering an ended state.
        This callback gets called whenever a tracked touch gets a touchEnd event.

    * **didBegin** - Called when the gesture enters a began state. Called before the
       view receives the Start event.

    * **didChange** - Called when the gesture enters a began state, and when one of the
        touches moves. Called before the view receives the Change event.

    * **didEnd** - Called when the gesture enters an ended state. Called before the
       view receives the End event.

    * **didCancel** - Called when the gesture enters a cancelled state. Called before the
       view receives the Cancel event.

  In all the callbacks, you can use the `touches` protected property to access the
  touches hash. The touches hash is keyed on the identifiers of the touches, and the
  values are the jQuery.Event objects. You can also access the length property to inspect
  how many touches are active, this is mostly useful in shouldBegin since every other
  callback can assume that there are as many active touches as specified in the
  numberOfRequiredTouches property.

  ## Discrete vs Continuous Gestures

  There are two main classes of gesture recognizers: Discrete and Continuous
  gestures. Discrete gestures do not get Start, Change nor Cancel events sent,
  since they represent a single, instantaneous event, rather than a continuous
  motion. If you are implementing your own discrete gesture recognizer, you must
  set the isDiscreteGesture property to yes, and SC.Gesture will adapt its behavior.

  Discrete gestures use the shouldEnd callback to either accept or decline the gesture
  event. If it is declined, then the gesture will enter a Cancelled state.

  @extends SC.Object
*/

SC.Gesture = SC.Object.extend(
  /** @scope SC.Gesture.prototype */{

  /**
    The current state of the gesture recognizer. This value can be any one
    of the states defined at the end of this file.

    @type Number
  */
  state: null,

  /**
    A string of the gesture recognizer's name. This value is set automatically
    but SC.Gestures when a gesture is registered.

    @type String
  */
  name: null,

  /**
    Specifies whether a gesture is discrete or continuous.

    @type Boolean
    @default false
  */
  gestureIsDiscrete: false,

  /**
    You can use the `touches` protected property to access the touches hash. The touches
    hash is keyed on the identifiers of the touches, and the values are the jQuery.Event
    objects.

    @private
    @type Hash
  */
  touches: null,

  /**
    You can also use the numberOfActiveTouches property to inspect how many touches
    are active, this is mostly useful in shouldBegin since every other callback can
    assume that there are as many active touches as specified in the
    numberOfRequiredTouches property.

    @private
    @type Number
  */
  numberOfActiveTouches: 0,

  /**
    Used to specify the number of touches required for the gesture to enter a possible
    state

    @private
    @type Number
  */
  numberOfRequiredTouches: 1,

  init: function() {
    this._super();
    this.touches = SC.TouchList.create();
  },

  //..............................................
  // Gesture Callbacks

  /** @private */
  didBecomePossible: function() { },

  /** @private */
  shouldBegin: function() {
    return true;
  },

  /** @private */
  didBegin: function() { },

  /** @private */
  didChange: function() { },

  /** @private */
  eventWasRejected: function() { },

  /** @private */
  shouldEnd: function() {
    return true;
  },

  /** @private */
  didEnd: function() { },

  /** @private */
  didCancel: function() { },

  //..............................................
  // Utilities

  /** @private */
  attemptGestureEventDelivery: function(evt, view, eventName, stopPropagation) {
    if (stopPropagation === undefined) {
      var stopPropagation = true;
    }

    if (this.notifyViewOfGestureEvent(view, eventName) === false) {
      this.eventWasRejected();
    } else if(stopPropagation) {
      evt.preventDefault();
    }
  },

  /**
    Given two Touch objects, this method returns the distance between them.

    @return Number
  */
  distance: function(touches) {

    if (touches.length < 2) {
      return 0;
    }

    var first = touches[0];
    var second = touches[1];

    var x = first.pageX;
    var y = first.pageY;
    var x0 = second.pageX;
    var y0 = second.pageY;

    return Math.sqrt((x -= x0) * x + (y -= y0) * y);
  },

  /**
    Given two Touch objects, this method returns the midpoint between them.

    @return Number
  */
  centerPointForTouches: function(touches) {
    var sumX = 0,
        sumY = 0;

    for (var i=0, l=touches.length; i<l; i++) {
      var touch = touches[i];
      sumX += touch.pageX;
      sumY += touch.pageY;
    }

    var location = {
      x: sumX / touches.length,
      y: sumY / touches.length
    };

    return location;
  },

  /** @private */
  _objectValues: function(object) {
    var ret = [];

    for (var item in object ) {
      if (object.hasOwnProperty(item)) {
        ret.push(object[item]);
      }
    }

    return ret;
  },

  /**
    Allows the gesture to notify the view it's associated with of a gesture
    event.

    @private
  */
  notifyViewOfGestureEvent: function(view, eventName, data) {
    var handler = view[eventName];
    var result = true;

    if (SC.typeOf(handler) === 'function') {
      result = handler.call(view, this, data);
    }

    return result;
  },

  toString: function() {
    return SC.Gesture+'<'+SC.guidFor(this)+'>';
  },

  /** @private */
  _resetState: function() {
    this.touches.removeAllTouches();
  },

  //..............................................
  // Touch event handlers

  /** @private */
  touchStart: function(evt, view, manager) {
    var targetTouches = evt.originalEvent.targetTouches;
    var _touches = this.touches;
    var state = get(this, 'state');

    set(_touches, 'timestamp', Date.now());

    //Collect touches by their identifiers
    for (var i=0, l=targetTouches.length; i<l; i++) {
      var touch = targetTouches[i];

      if(_touches.touchWithId(touch.identifier) === null && _touches.get('length') < get(this, 'numberOfRequiredTouches')) {
        _touches.addTouch(touch);
      }
    }

    if (_touches.get('length') < get(this, 'numberOfRequiredTouches')) {
      set(this ,'state', SC.Gesture.WAITING_FOR_TOUCHES);

    } else {
      // Discrete gestures may skip the possible step if they're ready to begin
      if (get(this, 'gestureIsDiscrete') && this.shouldBegin()) {
        set(this, 'state', SC.Gesture.BEGAN);
        this.didBegin();
      } else {
        set(this, 'state', SC.Gesture.POSSIBLE);
        this.didBecomePossible();
      }
    }

    manager.redispatchEventToView(view,'touchstart', evt);
  },

  /** @private */
  touchMove: function(evt, view, manager) {
    var state = get(this, 'state');

    if (state === SC.Gesture.WAITING_FOR_TOUCHES || state === SC.Gesture.ENDED || state === SC.Gesture.CANCELLED) {
      // Nothing to do here
      manager.redispatchEventToView(view,'touchmove', evt);
      return;
    }

    var changedTouches = evt.originalEvent.changedTouches;
    var _touches = this.touches;

    set(_touches, 'timestamp', Date.now());

    // Update touches hash
    for (var i=0, l=changedTouches.length; i<l; i++) {
      var touch = changedTouches[i];
      _touches.updateTouch(touch);
    }

    if (state === SC.Gesture.POSSIBLE) {
      if (this.shouldBegin()) {
        set(this, 'state', SC.Gesture.BEGAN);
        this.didBegin();

        // Give the gesture a chance to update its state so the view can get
        // updated information in the Start event
        this.didChange();

        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Start',(this.get('isDiscreteGesture'))? true: false);
      }

    // Discrete gestures don't fire changed events
    } else if ((state === SC.Gesture.BEGAN || state === SC.Gesture.CHANGED) && !get(this, 'gestureIsDiscrete')) {
      set(this, 'state', SC.Gesture.CHANGED);
      this.didChange();

      this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Change');

    } else {
      manager.redispatchEventToView(view,'touchmove', evt);
    }
  },

  /** @private */
  touchEnd: function(evt, view, manager) {
    // Discrete gestures need to cancel if they shouldn't end successfully
    if (get(this, 'gestureIsDiscrete')) {

      // Discrete gestures use shouldEnd to either accept or decline the gesture.
      if (this.state === SC.Gesture.BEGAN && this.shouldEnd()) {
        set(this, 'state', SC.Gesture.ENDED);
        this.didEnd();
        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'End');
      } else {
        set(this, 'state', SC.Gesture.CANCELLED);
        this.didCancel();
        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'Cancel');
      }
    }
    else {
      if ((this.state === SC.Gesture.BEGAN || this.state === SC.Gesture.CHANGED) && this.shouldEnd()) {
        set(this, 'state', SC.Gesture.ENDED);
        this.didEnd();

        this.attemptGestureEventDelivery(evt, view, get(this, 'name')+'End');
      }

      manager.redispatchEventToView(view,'touchend', evt);
    }

    this._resetState();
  },

  /** @private */
  touchCancel: function(evt, view, manager) {
    if (this.state !== SC.Gesture.CANCELLED) {
      this._resetState();
      set(this, 'state', SC.Gesture.CANCELLED);
      this.notifyViewOfGestureEvent(view,get(this, 'name')+'Cancel');
    } else {
      manager.redispatchEventToView(view,'touchcancel', evt);
    }
  }
});

SC.Gesture.WAITING_FOR_TOUCHES = 0;
SC.Gesture.POSSIBLE = 1;
SC.Gesture.BEGAN = 2;
SC.Gesture.CHANGED = 3;
SC.Gesture.ENDED = 4;
SC.Gesture.CANCELLED = 4;
<|endoftext|>


<commit_before>import SettingsModal from 'flarum/components/SettingsModal';

export default class TagSettingsModal extends SettingsModal {
  setMinTags(minTags, maxTags, value) {
    minTags(value);
    maxTags(Math.max(value, maxTags()));
  }

  className() {
    return 'TagSettingsModal Modal--small';
  }

  title() {
    return app.translator.trans('flarum-tags.admin.tag_settings.title');
  }

  form() {
    const minPrimaryTags = this.setting('tags.min_primary_tags', 0);
    const maxPrimaryTags = this.setting('tags.max_primary_tags', 0);

    const minSecondaryTags = this.setting('tags.min_secondary_tags', 0);
    const maxSecondaryTags = this.setting('tags.max_secondary_tags', 0);

    return [

        {app.translator.trans('flarum-tags.admin.tag_settings.required_primary_heading')}

          {app.translator.trans('flarum-tags.admin.tag_settings.required_primary_text')}

          <input className="FormControl"
            type="number"
            min="0"
            value={minPrimaryTags()}
            oninput={m.withAttr('value', this.setMinTags.bind(this, minPrimaryTags, maxPrimaryTags))} />
          {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
          <input className="FormControl"
            type="number"
            min={minPrimaryTags()}
            bidi={maxPrimaryTags} />

,

        {app.translator.trans('flarum-tags.admin.tag_settings.required_secondary_heading')}

          {app.translator.trans('flarum-tags.admin.tag_settings.required_secondary_text')}

          <input className="FormControl"
            type="number"
            min="0"
            value={minSecondaryTags()}
            oninput={m.withAttr('value', this.setMinTags.bind(this, minSecondaryTags, maxSecondaryTags))} />
          {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
          <input className="FormControl"
            type="number"
            min={minSecondaryTags()}
            bidi={maxSecondaryTags} />

    ];
  }
}
<commit_msg>Use correct setting keys<commit_after>import SettingsModal from 'flarum/components/SettingsModal';

export default class TagSettingsModal extends SettingsModal {
  setMinTags(minTags, maxTags, value) {
    minTags(value);
    maxTags(Math.max(value, maxTags()));
  }

  className() {
    return 'TagSettingsModal Modal--small';
  }

  title() {
    return app.translator.trans('flarum-tags.admin.tag_settings.title');
  }

  form() {
    const minPrimaryTags = this.setting('flarum-tags.min_primary_tags', 0);
    const maxPrimaryTags = this.setting('flarum-tags.max_primary_tags', 0);

    const minSecondaryTags = this.setting('flarum-tags.min_secondary_tags', 0);
    const maxSecondaryTags = this.setting('flarum-tags.max_secondary_tags', 0);

    return [

        {app.translator.trans('flarum-tags.admin.tag_settings.required_primary_heading')}

          {app.translator.trans('flarum-tags.admin.tag_settings.required_primary_text')}

          <input className="FormControl"
            type="number"
            min="0"
            value={minPrimaryTags()}
            oninput={m.withAttr('value', this.setMinTags.bind(this, minPrimaryTags, maxPrimaryTags))} />
          {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
          <input className="FormControl"
            type="number"
            min={minPrimaryTags()}
            bidi={maxPrimaryTags} />

,

        {app.translator.trans('flarum-tags.admin.tag_settings.required_secondary_heading')}

          {app.translator.trans('flarum-tags.admin.tag_settings.required_secondary_text')}

          <input className="FormControl"
            type="number"
            min="0"
            value={minSecondaryTags()}
            oninput={m.withAttr('value', this.setMinTags.bind(this, minSecondaryTags, maxSecondaryTags))} />
          {app.translator.trans('flarum-tags.admin.tag_settings.range_separator_text')}
          <input className="FormControl"
            type="number"
            min={minSecondaryTags()}
            bidi={maxSecondaryTags} />

    ];
  }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Ritchie Thai

See the file license.txt for copying permission.
*/

adventure.getConversationManager = function (conversations, sceneFunctions, util, conversationDisplayer, soundManager) {

    var writeDialogLn = conversationDisplayer.writeDialogLn;

    var object = {};

    var isInConversation = false;

    object.isInConversation = function () {
        return isInConversation;
    };

    object.startConversation = function (conversationKey) {
        var conversation = conversations[conversationKey];
        startConversation(conversation);
    };

    var startConversation = function (conversation) {
        isInConversation = true;
        advanceConversation(conversation, 0);
        conversationDisplayer.showDialogBox();
    };

    var advanceConversation = function (conversation, line) {
        if (line === 0 && conversation.onEnter) {
            conversation = applyConversationOnEnter(conversation);
        }
        showConversation(conversation, line);
    };

    var applyConversationOnEnter = function (conversation) {
        var onEnterResult = sceneFunctions[conversation.onEnter](conversation);
        var overrideOptions = onEnterResult ? onEnterResult.overrideOptions : null;
        return (overrideOptions ?
            applyOverrideOptions(conversation, overrideOptions) :
            conversation);
    }

    var applyOverrideOptions = function (conversation, overrideOptions) {
        var overrideConversation = util.clone(conversation);
        overrideConversation.options = overrideOptions;
        return overrideConversation;
    };

    var showConversation = function (conversation, line) {
        soundManager.playClickSound();
        conversationDisplayer.clearDialog();
        if (conversation.dialog) {
            writeDialog(conversation.dialog, line);
        }
        showSpeechBubbleLinks(conversation, line);
    };

    var showSpeechBubbleLinks = function (conversation, line) {
        if (isLastLineOfDialog(conversation.dialog, line)) {
            showOptions(conversation.options);
        } else {
            showAdvanceConversationLink(conversation, line);
        }
    };

    var isLastLineOfDialog = function (dialog, line) {
        return line + 1 === dialog.length / 2;
    };

    var showOptions = function (options) {
        if (!options) { options = [{"description": "Continue"}]; }
        options.forEach(showOption);
        conversationDisplayer.writeOptionLn(''); // TODO: This is hacky. Use actual styling instead of adding an empty option
    };

    var showOption = function (option, i) {
        var description = option.description || option.dialog[1];
        conversationDisplayer.printOptionLink(description, i, function () { chooseOption(option); });
    };

    var chooseOption = function (option) {
        if (option.onEnter) { option.onEnter(); }
        if (!option.next) {
            endConversation();
            return;
        }
        var conversation = conversations[option.next];
        advanceConversation(conversation, 0);
    };

    var showAdvanceConversationLink = function (conversation, line) {
        conversationDisplayer.printProceedConversationLink('Next', function () {
            advanceConversation(conversation, line + 1);
        });
    };

    var writeDialog = function (dialog, line) {
        writeAlternatingArrayDialogLine(dialog, line * 2);
    };

    var writeAlternatingArrayDialogLine = function (dialog, i) {
        var speaker = dialog[i];
        var speech = dialog[i + 1];
        if (speaker === '') {
            writeDialogLn(speech);
        } else {
            writeDialogLn(speaker + ': ' + speech);
        }
    };

    var endConversation = function () {
        // NOTE: This is tricky. We cannot end the conversation immediately,
        // because this gets evaluated before the click handler. If the click handler sees
        // that we are not in a conversation, the character will interact with the clicked
        // spot, even though the click was actually meant to end the conversation.
        conversationDisplayer.hideDialogBox(function () {
            isInConversation = false;
        });
    };

    return object;
};
<commit_msg>conversation-manager: Move the displaly oriented code to bottom below a comment<commit_after>/*
Copyright (c) 2013 Ritchie Thai

See the file license.txt for copying permission.
*/

adventure.getConversationManager = function (conversations, sceneFunctions, util, conversationDisplayer, soundManager) {

    var writeDialogLn = conversationDisplayer.writeDialogLn;

    var object = {};

    var isInConversation = false;

    object.isInConversation = function () {
        return isInConversation;
    };

    object.startConversation = function (conversationKey) {
        var conversation = conversations[conversationKey];
        startConversation(conversation);
    };

    var startConversation = function (conversation) {
        isInConversation = true;
        advanceConversation(conversation, 0);
        conversationDisplayer.showDialogBox();
    };

    var advanceConversation = function (conversation, line) {
        if (line === 0 && conversation.onEnter) {
            conversation = applyConversationOnEnter(conversation);
        }
        showConversation(conversation, line, advanceConversation, chooseOption);
    };

    var applyConversationOnEnter = function (conversation) {
        var onEnterResult = sceneFunctions[conversation.onEnter](conversation);
        var overrideOptions = onEnterResult ? onEnterResult.overrideOptions : null;
        return (overrideOptions ?
            applyOverrideOptions(conversation, overrideOptions) :
            conversation);
    }

    var applyOverrideOptions = function (conversation, overrideOptions) {
        var overrideConversation = util.clone(conversation);
        overrideConversation.options = overrideOptions;
        return overrideConversation;
    };

    var chooseOption = function (option) {
        if (option.onEnter) { option.onEnter(); }
        if (!option.next) {
            endConversation();
            return;
        }
        var conversation = conversations[option.next];
        advanceConversation(conversation, 0);
    };

    var endConversation = function () {
        // NOTE: This is tricky. We cannot end the conversation immediately,
        // because this gets evaluated before the click handler. If the click handler sees
        // that we are not in a conversation, the character will interact with the clicked
        // spot, even though the click was actually meant to end the conversation.
        conversationDisplayer.hideDialogBox(function () {
            isInConversation = false;
        });
    };

    // TODO: Split this out into another module
    // Everything below here is display code

    var showConversation = function (conversation, line, advanceConversation, chooseOption) {
        soundManager.playClickSound();
        conversationDisplayer.clearDialog();
        if (conversation.dialog) {
            writeDialog(conversation.dialog, line);
        }
        if (isLastLineOfDialog(conversation.dialog, line)) {
            showOptions(conversation.options, chooseOption);
        } else {
            showAdvanceConversationLink(conversation, line, advanceConversation);
        }
    };

    var isLastLineOfDialog = function (dialog, line) {
        return line + 1 === dialog.length / 2;
    };

    var showOptions = function (options, chooseOption) {
        if (!options) { options = [{"description": "Continue"}]; }
        options.forEach(function (x, i) {
            showOption(x, i, chooseOption);
        });
        conversationDisplayer.writeOptionLn(''); // TODO: This is hacky. Use actual styling instead of adding an empty option
    };

    var showOption = function (option, i, chooseOption) {
        var description = option.description || option.dialog[1];
        conversationDisplayer.printOptionLink(description, i, function () { chooseOption(option); });
    };

    var showAdvanceConversationLink = function (conversation, line, advanceConversation) {
        conversationDisplayer.printProceedConversationLink('Next', function () {
            advanceConversation(conversation, line + 1);
        });
    };

    var writeDialog = function (dialog, line) {
        writeAlternatingArrayDialogLine(dialog, line * 2);
    };

    var writeAlternatingArrayDialogLine = function (dialog, i) {
        var speaker = dialog[i];
        var speech = dialog[i + 1];
        if (speaker === '') {
            writeDialogLn(speech);
        } else {
            writeDialogLn(speaker + ': ' + speech);
        }
    };

    return object;
};
<|endoftext|>


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

  angular
    .module('vtPortal')
    .controller('ActivationCtrl', ActivationCtrl);

  ActivationCtrl.$inject = ['$location', '$scope', 'APIService', 'AlertService'];

  function ActivationCtrl($location, $scope, APIService, AlertService) {
    var vm = this;

    vm.activateAccount = activateAccount;
    vm.generateCaptcha = generateCaptcha;

    (function init() {
      generateCaptcha();

      vm.form = {};
      vm.form.activation = {};
      vm.form.activation.username = $location.search().username;
      vm.form.activation.code = $location.search().code;
    })();

    function activateAccount() {
      APIService.userCall('usersPut', [{
          username: vm.form.activation.username,
          code: vm.form.activation.code,
          captcha: {
            imageId: vm.form.activation.imageId,
            secretKey: vm.form.activation.secretKey,
            userAnswer: vm.form.activation.captcha
          },
          tenantDomain: 'carbon.super'
        }, '*/*', 'application/json'])
        .then(usersPutResponse);

      function usersPutResponse(response) {
        if (response.data.verified) {
          AlertService.success('Nu kan du logga in", "Ditt konto är aktiverat!', 10000);
          $location.path('/');
          $location.search('username', null);
          $location.search('code', null);
        } else {
          AlertService.error('försök igen", "Problem vid verifiering av konto');
          generateCaptcha();
          vm.form.activation.captcha = '';
          $scope.activateAccountForm.$setPristine();
        }
      }
    }

    function generateCaptcha() {
      APIService.userCall('captchasPost', [])
        .then(captchasPostResponse);

      function captchasPostResponse(response) {
        vm.form.activation.imageId = response.data.imageId;
        vm.form.activation.secretKey = response.data.secretKey;

        vm.captcha = APIService.getUserApiBasePath() + '/captchas/' + response.data.imageId;
      }
    }

  }

})();
<commit_msg>Minor fix<commit_after>(function() {
  'use strict';

  angular
    .module('vtPortal')
    .controller('ActivationCtrl', ActivationCtrl);

  ActivationCtrl.$inject = ['$location', '$scope', 'APIService', 'AlertService'];

  function ActivationCtrl($location, $scope, APIService, AlertService) {
    var vm = this;

    vm.activateAccount = activateAccount;
    vm.generateCaptcha = generateCaptcha;

    (function init() {
      generateCaptcha();

      vm.form = {};
      vm.form.activation = {};
      vm.form.activation.username = $location.search().username;
      vm.form.activation.code = $location.search().code;
    })();

    function activateAccount() {
      APIService.userCall('usersPut', [{
          username: vm.form.activation.username,
          code: vm.form.activation.code,
          captcha: {
            imageId: vm.form.activation.imageId,
            secretKey: vm.form.activation.secretKey,
            userAnswer: vm.form.activation.captcha
          },
          tenantDomain: 'carbon.super'
        }, '*/*', 'application/json'])
        .then(usersPutResponse);

      function usersPutResponse(response) {
        if (response.data.verified) {
          AlertService.success('Nu kan du logga in", "Ditt konto är aktiverat!', 10000);
          $location.path('/');
          $location.search('username', null);
          $location.search('code', null);
        } else {
          AlertService.error('Försök igen', 'Problem vid verifiering av konto');
          generateCaptcha();
          vm.form.activation.captcha = '';
          $scope.activateAccountForm.$setPristine();
        }
      }
    }

    function generateCaptcha() {
      APIService.userCall('captchasPost', [])
        .then(captchasPostResponse);

      function captchasPostResponse(response) {
        vm.form.activation.imageId = response.data.imageId;
        vm.form.activation.secretKey = response.data.secretKey;

        vm.captcha = APIService.getUserApiBasePath() + '/captchas/' + response.data.imageId;
      }
    }

  }

})();
<|endoftext|>


<commit_before>import React from 'react';
import {
	TouchableOpacity,
	Text,
	StyleSheet,
	ListView,
	View
} from 'react-native';

import Icon from 'react-native-vector-icons/FontAwesome';
import css from '../../styles/css';

const resultsDataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });

const ShuttleStopsListView = ({ shuttle_stops, addStop }) => (
	<ListView
		style={[css.main_container, css.scroll_main, css.whitebg]}
		dataSource={resultsDataSource.cloneWithRows(shuttle_stops)}
		renderRow={
			(row) => {
				if (row.saved === true) {
					return null;
				} else {
					return (
						<StopItem
							data={row}
							addStop={addStop}
						/>
					);
				}
			}
		}
	/>
);

const StopItem = ({ data, addStop }) => (
	<View
		style={styles.list_row}
	>
		<TouchableOpacity
			onPress={() => addStop(data.id, data.name.trim())}
			style={styles.touchable}
			disabled={(data.saved === true)}
		>
			<Text style={(data.saved === true) ? (styles.row_name_disabled) : (styles.row_name)}>
				{data.name.trim()}
			</Text>
			<Icon
				style={styles.icon}
				color="rgba(116,118,120,.6)"
				name="chevron-right"
				size={20}
			/>
		</TouchableOpacity>
	</View>
);

const styles = StyleSheet.create({
	icon: { alignSelf: 'flex-end' },
	touchable: { flex: 1, flexDirection: 'row', alignItems: 'center' },
	row_name: { flex: 1, paddingRight: 10 },
	row_name_disabled: { color: '#DDD', flex: 1, paddingRight: 10 },
	list_row: { flex: 1, height: 60, padding: 7, paddingVertical: 14, borderBottomWidth: 1, borderBottomColor: '#EEE', overflow: 'hidden' },
});

export default ShuttleStopsListView;
<commit_msg>unhide added stop<commit_after>import React from 'react';
import {
	TouchableOpacity,
	Text,
	StyleSheet,
	ListView,
	View
} from 'react-native';

import Icon from 'react-native-vector-icons/FontAwesome';
import css from '../../styles/css';

const resultsDataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });

const ShuttleStopsListView = ({ shuttle_stops, addStop }) => (
	<ListView
		style={[css.main_container, css.scroll_main, css.whitebg]}
		dataSource={resultsDataSource.cloneWithRows(shuttle_stops)}
		renderRow={
			(row) => (
				<StopItem
					data={row}
					addStop={addStop}
				/>
			)
		}
	/>
);

const StopItem = ({ data, addStop }) => (
	<View
		style={styles.list_row}
	>
		<TouchableOpacity
			onPress={() => addStop(data.id, data.name.trim())}
			style={styles.touchable}
			disabled={(data.saved === true)}
		>
			<Text style={(data.saved === true) ? (styles.row_name_disabled) : (styles.row_name)}>
				{data.name.trim()}
			</Text>
			<Icon
				style={styles.icon}
				color="rgba(116,118,120,.6)"
				name="chevron-right"
				size={20}
			/>
		</TouchableOpacity>
	</View>
);

const styles = StyleSheet.create({
	icon: { alignSelf: 'flex-end' },
	touchable: { flex: 1, flexDirection: 'row', alignItems: 'center' },
	row_name: { flex: 1, paddingRight: 10 },
	row_name_disabled: { color: '#DDD', flex: 1, paddingRight: 10 },
	list_row: { flex: 1, height: 60, padding: 7, paddingVertical: 14, borderBottomWidth: 1, borderBottomColor: '#EEE', overflow: 'hidden' },
});

export default ShuttleStopsListView;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';

import Textbox from './Textbox';
import { textbox as textboxChange } from 'js/redux/components/core/actions';

const TextboxContainer = React.createClass({

    propTypes: {
        component: PropTypes.object,
        onChange: PropTypes.func,
        path: PropTypes.string,
        root: PropTypes.string
    },

    render() {
        return (
            <Textbox { ...this.props } />
        );
    }

});

const mapStateToProps = (state, props) => {
    return {
        component: state.components[props.root][props.path]
    };
}

const mapDispatchToProps = (dispatch, props) => {
    return {
        onChange: (value) => dispatch(textboxChange({
            root: props.root,
            path: props.path,
            value
        }))
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(TextboxContainer);
<commit_msg>add onchange callback to textbox component<commit_after>import React, { PropTypes } from 'react';
import { connect } from 'react-redux';

import { noop } from 'js/utils';

import Textbox from './Textbox';
import { textbox as textboxChange } from 'js/redux/components/core/actions';

const TextboxContainer = React.createClass({

    propTypes: {
        component: PropTypes.object,
        onChange: PropTypes.func,
        onChangeCallback: PropTypes.func,
        path: PropTypes.string,
        root: PropTypes.string
    },

    getDefaultProps() {
        return {
            onChangeCallback: noop
        };
    },

    handleChange(value) {
        this.props.onChange(value);
        this.props.onChangeCallback(value);
    },

    render() {
        const { onChange, onChangeCallback, ...rest } = this.props;
        return (
            <Textbox { ...rest } onChange={ this.handleChange } />
        );
    }

});

const mapStateToProps = (state, props) => {
    return {
        component: state.components[props.root][props.path]
    };
}

const mapDispatchToProps = (dispatch, props) => {
    return {
        onChange: (value) => dispatch(textboxChange({
            root: props.root,
            path: props.path,
            value
        }))
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(TextboxContainer);
<|endoftext|>