<commit_before>import { graphql } from 'gatsby';
import React from 'react';
import { css } from 'astroturf';

import LinkedHeading from '../../components/LinkedHeading';
import ComponentApi from '../../components/ComponentApi';
import ReactPlayground from '../../components/ReactPlayground';

import Overlay from '../../examples/Overlays/Overlay';
import Disabled from '../../examples/Overlays/Disabled';
import ScheduleUpdate from '../../examples/Overlays/ScheduleUpdate';
import OverlayTrigger from '../../examples/Overlays/OverlayTrigger';
import TooltipInCopy from '../../examples/Overlays/TooltipInCopy';
import TooltipOverlay from '../../examples/Overlays/TooltipOverlay';
import TooltipPositioned from '../../examples/Overlays/TooltipPositioned';

import PopoverBasic from '../../examples/Overlays/PopoverBasic';
import PopoverContained from '../../examples/Overlays/PopoverContained';
import PopoverPositioned from '../../examples/Overlays/PopoverPositioned';

import withLayout from '../../withLayout';

const styles = css`
  .contained {
    height: 200px;
    & > div {
      position: relative;
    }
  }
`;

export default withLayout(function TooltipSection({ data }) {
  return (
    <>
      <LinkedHeading h="1" id="overlays">
        Overlays
      </LinkedHeading>

        A set of components for positioning beautiful overlays, tooltips,
        popovers, and anything else you need.

      <LinkedHeading h="2" id="overlays-overview">
        Overview
      </LinkedHeading>

Things to know about the react-boostrap Overlay components.

          Overlays rely on a 3rd party library{' '}
          react-popper,
          a tiny react wrapper around{' '}
          Popper.js. It's include
          automatically with react-bootstrap, but you should reference the API
          for more advanced use-cases.

          The {'<Tooltip>'} and {'<Popover>'}{' '}
          components do not position themselves. Instead the{' '}
          {'<Overlay>'} (or {'<OverlayTrigger>'})
          components, inject ref and style props.

          Tooltip expects specific props injected by the{' '}
          {'<Overlay>'} component

          Tooltips for disabled elements must be triggered on a
          wrapper element.

      <LinkedHeading h="2" id="overlays">
        Overlay
      </LinkedHeading>

        Overlay is the fundamental component for positioning and
        controlling tooltip visibility. It's a wrapper around react-popper, that
        adds support for transitions, and visibility toggling.

      <LinkedHeading h="3" id="creating-an-overlay">
        Creating an Overlay
      </LinkedHeading>

        Overlays consist of at least two elements, the "overlay", the element to
        be positioned, as well as a "target", the element the overlay is
        positioned in relation to. You can also also have an "arrow" element,
        like the tooltips and popovers, but that is optional. Be sure to{' '}

          check out the{' '}

            react-popper
          {' '}
          documentation for more details about the injected props.

      <ReactPlayground codeText={Overlay} />

      <LinkedHeading h="3" id="overlay-trigger">
        OverlayTrigger
      </LinkedHeading>

        Since the above pattern is pretty common, but verbose, we've included{' '}
        {'<OverlayTrigger>'} component to help with common
        use-cases. It even has functionality to delayed show or hides, and a few
        different "trigger" events you can mix and match.

        Note that triggering components{' '}

          must be able to accept{' '}
          a ref
        {' '}
        since {'<OverlayTrigger>'} will attempt to add one. You can
        use{' '}

          forwardRef()
        {' '}
        for function components.

      <ReactPlayground codeText={OverlayTrigger} />

      <LinkedHeading h="2" id="tooltips">
        Tooltips
      </LinkedHeading>

        A tooltip component for a more stylish alternative to that anchor tag{' '}
        title attribute.

      <LinkedHeading h="3" id="tooltip-examples">
        Examples
      </LinkedHeading>

Hover over the links below to see tooltips.

      <ReactPlayground codeText={TooltipInCopy} showCode={false} />

        You can pass the Overlay injected props directly to the
        Tooltip component.

      <ReactPlayground codeText={TooltipOverlay} />

        Or pass a Tooltip element to OverlayTrigger instead.

      <ReactPlayground codeText={TooltipPositioned} />

      <LinkedHeading h="2" id="popovers">
        Popovers
      </LinkedHeading>

A popover component, like those found in iOS.

      <LinkedHeading h="3" id="popover-examples">
        Examples
      </LinkedHeading>

      <ReactPlayground codeText={PopoverBasic} />

        As with {'<Tooltip>'}s, you can control the placement of
        the Popover.

      <ReactPlayground codeText={PopoverPositioned} />

      <LinkedHeading h="2" id="overlays-disabled">
        Disabled elements
      </LinkedHeading>

        Elements with the disabled attribute aren’t interactive,
        meaning users cannot hover or click them to trigger a popover (or
        tooltip). As a workaround, you’ll want to trigger the overlay from a
        wrapper {'
'} or {''} and override
        the pointer-events on the disabled element.

      <ReactPlayground codeText={Disabled} />

      <LinkedHeading h="2" id="overlays-container">
        Changing containers
      </LinkedHeading>

        You can specify a container to control the DOM element the
        overlay is appended to. This is especially useful when styles conflict
        with your Overlay's.

      <ReactPlayground
        codeText={PopoverContained}
        exampleClassName={styles.contained}
      />

      <LinkedHeading h="2" id="overlays-dynamic-updates">
        Updating position dynamically
      </LinkedHeading>

        Since we can't know every time your overlay changes size, to reposition
        it, you need to take manual action if you want to update the position of
        an Overlay in response to a change.

        For this, the Overlay component also injects a{' '}
        scheduleUpdate() method that an overlay component can use
        to reposition itself.

      <ReactPlayground codeText={ScheduleUpdate} />

      <LinkedHeading h="2" id="overlays-api">
        API
      </LinkedHeading>

      <ComponentApi metadata={data.Overlay} />
      <ComponentApi metadata={data.OverlayTrigger} />
      <ComponentApi metadata={data.Tooltip} />
      <ComponentApi metadata={data.Popover} />
      <ComponentApi metadata={data.PopoverContent} />
      <ComponentApi metadata={data.PopoverTitle} />
    </>
  );
});

export const query = graphql`
  query OverlayQuery {
    Tooltip: componentMetadata(displayName: { eq: "Tooltip" }) {
      ...ComponentApi_metadata
    }
    Popover: componentMetadata(displayName: { eq: "Popover" }) {
      ...ComponentApi_metadata
    }
    PopoverContent: componentMetadata(displayName: { eq: "PopoverContent" }) {
      ...ComponentApi_metadata
    }
    PopoverTitle: componentMetadata(displayName: { eq: "PopoverTitle" }) {
      ...ComponentApi_metadata
    }
    Overlay: componentMetadata(displayName: { eq: "Overlay" }) {
      ...ComponentApi_metadata
    }
    OverlayTrigger: componentMetadata(displayName: { eq: "OverlayTrigger" }) {
      ...ComponentApi_metadata
    }
  }
`;
<commit_msg>Fixed small spelling error (#4808)<commit_after>import { graphql } from 'gatsby';
import React from 'react';
import { css } from 'astroturf';

import LinkedHeading from '../../components/LinkedHeading';
import ComponentApi from '../../components/ComponentApi';
import ReactPlayground from '../../components/ReactPlayground';

import Overlay from '../../examples/Overlays/Overlay';
import Disabled from '../../examples/Overlays/Disabled';
import ScheduleUpdate from '../../examples/Overlays/ScheduleUpdate';
import OverlayTrigger from '../../examples/Overlays/OverlayTrigger';
import TooltipInCopy from '../../examples/Overlays/TooltipInCopy';
import TooltipOverlay from '../../examples/Overlays/TooltipOverlay';
import TooltipPositioned from '../../examples/Overlays/TooltipPositioned';

import PopoverBasic from '../../examples/Overlays/PopoverBasic';
import PopoverContained from '../../examples/Overlays/PopoverContained';
import PopoverPositioned from '../../examples/Overlays/PopoverPositioned';

import withLayout from '../../withLayout';

const styles = css`
  .contained {
    height: 200px;
    & > div {
      position: relative;
    }
  }
`;

export default withLayout(function TooltipSection({ data }) {
  return (
    <>
      <LinkedHeading h="1" id="overlays">
        Overlays
      </LinkedHeading>

        A set of components for positioning beautiful overlays, tooltips,
        popovers, and anything else you need.

      <LinkedHeading h="2" id="overlays-overview">
        Overview
      </LinkedHeading>

Things to know about the React-Boostrap Overlay components.

          Overlays rely on the third-party library{' '}
          react-popper,
          a tiny React wrapper around{' '}
          Popper.js. It's included
          automatically with React-Bootstrap, but you should reference the API
          for more advanced use cases.

          The {'<Tooltip>'} and {'<Popover>'}{' '}
          components do not position themselves. Instead the{' '}
          {'<Overlay>'} (or {'<OverlayTrigger>'})
          components, inject ref and style props.

          Tooltip expects specific props injected by the{' '}
          {'<Overlay>'} component

          Tooltips for disabled elements must be triggered on a
          wrapper element.

      <LinkedHeading h="2" id="overlays">
        Overlay
      </LinkedHeading>

        Overlay is the fundamental component for positioning and
        controlling tooltip visibility. It's a wrapper around react-popper, that
        adds support for transitions, and visibility toggling.

      <LinkedHeading h="3" id="creating-an-overlay">
        Creating an Overlay
      </LinkedHeading>

        Overlays consist of at least two elements, the "overlay", the element to
        be positioned, as well as a "target", the element the overlay is
        positioned in relation to. You can also also have an "arrow" element,
        like the tooltips and popovers, but that is optional. Be sure to{' '}

          check out the{' '}

            react-popper
          {' '}
          documentation for more details about the injected props.

      <ReactPlayground codeText={Overlay} />

      <LinkedHeading h="3" id="overlay-trigger">
        OverlayTrigger
      </LinkedHeading>

        Since the above pattern is pretty common, but verbose, we've included{' '}
        {'<OverlayTrigger>'} component to help with common
        use-cases. It even has functionality to delayed show or hides, and a few
        different "trigger" events you can mix and match.

        Note that triggering components{' '}

          must be able to accept{' '}
          a ref
        {' '}
        since {'<OverlayTrigger>'} will attempt to add one. You can
        use{' '}

          forwardRef()
        {' '}
        for function components.

      <ReactPlayground codeText={OverlayTrigger} />

      <LinkedHeading h="2" id="tooltips">
        Tooltips
      </LinkedHeading>

        A tooltip component for a more stylish alternative to that anchor tag{' '}
        title attribute.

      <LinkedHeading h="3" id="tooltip-examples">
        Examples
      </LinkedHeading>

Hover over the links below to see tooltips.

      <ReactPlayground codeText={TooltipInCopy} showCode={false} />

        You can pass the Overlay injected props directly to the
        Tooltip component.

      <ReactPlayground codeText={TooltipOverlay} />

        Or pass a Tooltip element to OverlayTrigger instead.

      <ReactPlayground codeText={TooltipPositioned} />

      <LinkedHeading h="2" id="popovers">
        Popovers
      </LinkedHeading>

A popover component, like those found in iOS.

      <LinkedHeading h="3" id="popover-examples">
        Examples
      </LinkedHeading>

      <ReactPlayground codeText={PopoverBasic} />

        As with {'<Tooltip>'}s, you can control the placement of
        the Popover.

      <ReactPlayground codeText={PopoverPositioned} />

      <LinkedHeading h="2" id="overlays-disabled">
        Disabled elements
      </LinkedHeading>

        Elements with the disabled attribute aren’t interactive,
        meaning users cannot hover or click them to trigger a popover (or
        tooltip). As a workaround, you’ll want to trigger the overlay from a
        wrapper {'
'} or {''} and override
        the pointer-events on the disabled element.

      <ReactPlayground codeText={Disabled} />

      <LinkedHeading h="2" id="overlays-container">
        Changing containers
      </LinkedHeading>

        You can specify a container to control the DOM element the
        overlay is appended to. This is especially useful when styles conflict
        with your Overlay's.

      <ReactPlayground
        codeText={PopoverContained}
        exampleClassName={styles.contained}
      />

      <LinkedHeading h="2" id="overlays-dynamic-updates">
        Updating position dynamically
      </LinkedHeading>

        Since we can't know every time your overlay changes size, to reposition
        it, you need to take manual action if you want to update the position of
        an Overlay in response to a change.

        For this, the Overlay component also injects a{' '}
        scheduleUpdate() method that an overlay component can use
        to reposition itself.

      <ReactPlayground codeText={ScheduleUpdate} />

      <LinkedHeading h="2" id="overlays-api">
        API
      </LinkedHeading>

      <ComponentApi metadata={data.Overlay} />
      <ComponentApi metadata={data.OverlayTrigger} />
      <ComponentApi metadata={data.Tooltip} />
      <ComponentApi metadata={data.Popover} />
      <ComponentApi metadata={data.PopoverContent} />
      <ComponentApi metadata={data.PopoverTitle} />
    </>
  );
});

export const query = graphql`
  query OverlayQuery {
    Tooltip: componentMetadata(displayName: { eq: "Tooltip" }) {
      ...ComponentApi_metadata
    }
    Popover: componentMetadata(displayName: { eq: "Popover" }) {
      ...ComponentApi_metadata
    }
    PopoverContent: componentMetadata(displayName: { eq: "PopoverContent" }) {
      ...ComponentApi_metadata
    }
    PopoverTitle: componentMetadata(displayName: { eq: "PopoverTitle" }) {
      ...ComponentApi_metadata
    }
    Overlay: componentMetadata(displayName: { eq: "Overlay" }) {
      ...ComponentApi_metadata
    }
    OverlayTrigger: componentMetadata(displayName: { eq: "OverlayTrigger" }) {
      ...ComponentApi_metadata
    }
  }
`;
<|endoftext|>


<commit_before>
describe("Test extend in lib for OOP", function() {

    function Fruit(name,season) {
	this.name = name;
	this.season = season;
	}
	Fruit.prototype.category = "Food";
    function Apple(brand) {
	this.name = "Apple";
	this.brand = brand;
	}

	extend(Apple,Fruit);
	var fuji = new Apple("Fuji");

	it("subclass should extend superclass", function() {
	expect(Apple.prototype.superClass).toEqual(Fruit.prototype);
	});

	it("var in same class should share public property", function() {
	expect(fuji.name).toEqual("Apple");
	});

	it("isA describe instanciation relationship", function(){
	expect(fuji.isA(Fruit)).toBeTruthy();
	});

	it("use extend function to instanciate superclass's property", function(){
	expect(fuji.category).toEqual("Food");
	expect(fuji.superClass.category).toEqual("Food");
	});

	it("superCLass does not extend subclass property by using extend",
	    function(){
	expect(fuji.superClass.brand).toBe(undefined);
	});

});

describe("deepCopy should really create a new Obj", function() {
	var Country = {};
	Country.states = [];

	var China = deepCopy(Country);

	China.states.push('Xian');
	China.states.push('Fuzhou');

	it("the class that deepCopy another class is independent on itself",
	   function() {
	   expect(China.states[0]).toEqual('Xian');
	   expect(China.states[1]).toEqual('Fuzhou');
	});

	it("the class that has been deepCopy should not be influenced",
	   function() {
            expect(Country.states.length).toEqual(0);
	    expect(Country.states[0]).not.toEqual('Xian');
	   });

});
<commit_msg>testlib.js is done<commit_after>
describe("Test extend in lib for OOP", function() {

    function Fruit(name,season) {
	this.name = name;
	this.season = season;
	}
	Fruit.prototype.category = "Food";
    function Apple(brand) {
	this.brand = brand;
	}
        Apple.prototype.name = "Apple";

	extend(Apple,Fruit);
	var fuji = new Apple("Fuji");

	it("subclass should extend superclass", function() {
	expect(Apple.prototype.superClass).toEqual(Fruit.prototype);
	expect(fuji instanceof Fruit).not.toBeTruthy();
	});

	it("var in same class should share public property", function() {
	expect(fuji.name).toEqual("Apple");
	});

	it("isA describe instanciation relationship", function(){
	expect(fuji.isA(Fruit)).toBeTruthy();
	});

	it("use extend function to instanciate superclass's property", function(){
	expect(fuji.category).toEqual("Food");
	expect(fuji.superClass.category).toEqual("Food");
	});

	it("superCLass does not extend subclass property by using extend",
	    function(){
	expect(fuji.superClass.brand).toBe(undefined);
	});

});

describe("deepCopy should really create a new Obj", function() {
	var Country = {};
	Country.states = [];

	var China = deepCopy(Country);

	China.states.push('Xian');
	China.states.push('Fuzhou');

	it("the class that deepCopy another class is independent on itself",
	   function() {
	   expect(China.states[0]).toEqual('Xian');
	   expect(China.states[1]).toEqual('Fuzhou');
	});

	it("the class that has been deepCopy should not be influenced",
	   function() {
            expect(Country.states.length).toEqual(0);
	    expect(Country.states[0]).not.toEqual('Xian');
	   });

});
<|endoftext|>


<commit_before>function ResponseViewHelper() {
	var _ = require('lib/underscore')._;
	var Question = require('models/question');
	var QuestionView = require('ui/common/questions/QuestionView');
  var SeparatorView = require('ui/common/components/SeparatorView');
  var Palette = require('ui/common/components/Palette');

	var PAGE_SIZE = 7;

	var generateLabelTextForQuestion = function(question, errorText) {
		text = '';
		text += question.number() + ') ';
		text += question['content'];
		text += question.mandatory ? ' *' : '';
		text += question.max_length ? ' [' + question.max_length + ']' : '';
		text += question.max_value ? ' (<' + question.max_value + ')' : '';
		text += question.min_value ? ' (>' + question.min_value + ')' : '';
		text += errorText ? '\n' + errorText : '';
		return text;
	};

	var resetErrors = function(questionViews) {
		_(questionViews).each(function(fields, questionID) {
			var question = Question.findOneById(questionID);
			var labelText = generateLabelTextForQuestion(question);
			fields.label.setText(labelText);
			fields.label.setColor('#000000');
		});
	};

	var displayErrors = function(responseErrors, questionViews) {
		resetErrors(questionViews);
		Ti.API.info("All the errors:" + responseErrors);
		for (var answerErrors in responseErrors) {
			Ti.API.info("Answer errors for:" + answerErrors);
			for (var field in responseErrors[answerErrors]) {
				var question_id = answerErrors;
				var question = Question.findOneById(question_id);
				var label = questionViews[question_id].label;
				var labelText = generateLabelTextForQuestion(question, responseErrors[question_id][field]);
				label.setText(labelText);
				label.setColor("red");
				Ti.API.info(responseErrors[question_id][field]);
			}
		}
	};

	var getQuestionViews = function(parent) {
		var foo = {};
		if(_(parent).isArray()) {
		  var views = _.chain(parent).map(function(scrollView) { return scrollView.children; }).flatten().value();
		} else {
		  var views = parent.getChildren() || [];
		}
		_(views).each(function(view) {
			if (view.type == 'question') {
				foo[view.id] = {
					'label' : _(view.children).first(),
					'valueField' : _(view.children).last(),
					'answerID' : view.answerID
				};
				Ti.API.info("label and value" + _(view.children).first() + _(view.children).last());
			}
			_(foo).extend(getQuestionViews(view));
		});
		return foo;
	};

	var paginate = function(questions, scrollableView, buttons, response) {

		var pagedQuestions = _.chain(questions).groupBy(function(a, b) {
			return Math.floor(b / PAGE_SIZE);
		}).toArray().value();

		_(pagedQuestions).each(function(questions, pageNumber) {
			var questionsView = Ti.UI.createScrollView({
				layout : 'vertical'
			});

			_(questions).each(function(question) {
			  var answer = response ? response.answerForQuestion(question.id) : undefined;
				var questionView = new QuestionView(question, answer);
				questionsView.add(questionView);
			})

			if (pageNumber + 1 === pagedQuestions.length) {
				_(buttons).each(function(button){
				  questionsView.add(button);
				  questionsView.add(new SeparatorView(Palette.SECONDARY_COLOR_LIGHT, '5dip'));
				});
			}

			scrollableView.addView(questionsView);
		});
	};

	var scrollToFirstErrorPage = function(scrollableView, errors){
	  var views = scrollableView.getViews();
	  scrollableView.scrollToView(views[0]);
	};

	var self = {
		getQuestionViews : getQuestionViews,
		displayErrors : displayErrors,
		resetErrors : resetErrors,
		generateLabelTextForQuestion : generateLabelTextForQuestion,
		paginate : paginate,
		scrollToFirstErrorPage : scrollToFirstErrorPage
	};
	return self;
}

module.exports = ResponseViewHelper;
<commit_msg>Added a padding between questions and the Save button<commit_after>function ResponseViewHelper() {
	var _ = require('lib/underscore')._;
	var Question = require('models/question');
	var QuestionView = require('ui/common/questions/QuestionView');
  var SeparatorView = require('ui/common/components/SeparatorView');
  var Palette = require('ui/common/components/Palette');

	var PAGE_SIZE = 7;

	var generateLabelTextForQuestion = function(question, errorText) {
		text = '';
		text += question.number() + ') ';
		text += question['content'];
		text += question.mandatory ? ' *' : '';
		text += question.max_length ? ' [' + question.max_length + ']' : '';
		text += question.max_value ? ' (<' + question.max_value + ')' : '';
		text += question.min_value ? ' (>' + question.min_value + ')' : '';
		text += errorText ? '\n' + errorText : '';
		return text;
	};

	var resetErrors = function(questionViews) {
		_(questionViews).each(function(fields, questionID) {
			var question = Question.findOneById(questionID);
			var labelText = generateLabelTextForQuestion(question);
			fields.label.setText(labelText);
			fields.label.setColor('#000000');
		});
	};

	var displayErrors = function(responseErrors, questionViews) {
		resetErrors(questionViews);
		Ti.API.info("All the errors:" + responseErrors);
		for (var answerErrors in responseErrors) {
			Ti.API.info("Answer errors for:" + answerErrors);
			for (var field in responseErrors[answerErrors]) {
				var question_id = answerErrors;
				var question = Question.findOneById(question_id);
				var label = questionViews[question_id].label;
				var labelText = generateLabelTextForQuestion(question, responseErrors[question_id][field]);
				label.setText(labelText);
				label.setColor("red");
				Ti.API.info(responseErrors[question_id][field]);
			}
		}
	};

	var getQuestionViews = function(parent) {
		var foo = {};
		if(_(parent).isArray()) {
		  var views = _.chain(parent).map(function(scrollView) { return scrollView.children; }).flatten().value();
		} else {
		  var views = parent.getChildren() || [];
		}
		_(views).each(function(view) {
			if (view.type == 'question') {
				foo[view.id] = {
					'label' : _(view.children).first(),
					'valueField' : _(view.children).last(),
					'answerID' : view.answerID
				};
				Ti.API.info("label and value" + _(view.children).first() + _(view.children).last());
			}
			_(foo).extend(getQuestionViews(view));
		});
		return foo;
	};

	var paginate = function(questions, scrollableView, buttons, response) {

		var pagedQuestions = _.chain(questions).groupBy(function(a, b) {
			return Math.floor(b / PAGE_SIZE);
		}).toArray().value();

		_(pagedQuestions).each(function(questions, pageNumber) {
			var questionsView = Ti.UI.createScrollView({
				layout : 'vertical'
			});

			_(questions).each(function(question) {
			  var answer = response ? response.answerForQuestion(question.id) : undefined;
				var questionView = new QuestionView(question, answer);
				questionsView.add(questionView);
			})

			if (pageNumber + 1 === pagedQuestions.length) {
			  questionsView.add(new SeparatorView(Palette.SECONDARY_COLOR_LIGHT, '5dip'));
				_(buttons).each(function(button){
				  questionsView.add(new SeparatorView(Palette.SECONDARY_COLOR_LIGHT, '5dip'));
				  questionsView.add(button);
				});
			}

			scrollableView.addView(questionsView);
		});
	};

	var scrollToFirstErrorPage = function(scrollableView, errors){
	  var views = scrollableView.getViews();
	  scrollableView.scrollToView(views[0]);
	};

	var self = {
		getQuestionViews : getQuestionViews,
		displayErrors : displayErrors,
		resetErrors : resetErrors,
		generateLabelTextForQuestion : generateLabelTextForQuestion,
		paginate : paginate,
		scrollToFirstErrorPage : scrollToFirstErrorPage
	};
	return self;
}

module.exports = ResponseViewHelper;
<|endoftext|>


<commit_before>var editor;
var timer;
var prev_params_keys;
var params_keys;
var params_html;

var p = new Plurr();
var param_cache = {};
param_cache['N'] = 5;

$(document).ready(function() {
  editor = CodeMirror.fromTextArea(document.getElementById("source"), {onChange: change_source});

  var html = '';
  for (option in plural_options) {
    var sel = option == 'en' ? ' selected' : ''
    html += '<option value="' + option + '"' + sel + '>' + option + ' — ' + plural_options[option] + '</option>';
  }
  $('#locale').html(html);

  change_source();

  $('#locale').on('change', change_locale);
  $('#auto_plurals').on('change', change_source);
  $('#strict').on('change', change_param);
  $(document).on('change keyup cut paste', '#params input', change_param);
});

function cb(name) {
  var value = param_cache[name] || '';
  params_keys += "\n" + name; // using newline as a delimiter
  params_html += '
' + name + ':	<input id="param_'+name+'" param="'+name+'" value="'+value+'" />
';
  return value;
}

function change_locale() {
  return _change(true);
}

function change_source() {
  return _change(true);
}

function change_param() {
  return _change(false);
}

function _change(rebuild_params) {
  var s = editor.getValue().trim();
  var out, params, options;

  try {
    $('#params input').each(function(idx, elem) {
      var name = $(elem).attr('param');
      var value = $(elem).val().trim();
      if (value != '') {
        param_cache[name] = value;
      } else {
        delete param_cache[name];
      }
    });

    if (rebuild_params) {
      options = {
        'locale': $('#locale').val(),
        'auto_plurals': !!$('#auto_plurals').attr('checked'),
        'strict': true,
        'callback': cb,
      };
      params_keys = '';
      params_html = '';
      p.format(s, {}, options);
      if (prev_params_keys != params_keys) {
        $('#params').html(params_html);
        prev_params_keys = params_keys;
      }
    }

    params = {};
    $('#params input').each(function(idx, elem) {
      var name = $(elem).attr('param');
      var value = $(elem).val().trim();
      if (value != '') {
        params[name] = value;
      }
    });

    options = {
      'locale': $('#locale').val(),
      'auto_plurals': !!$('#auto_plurals').attr('checked'),
      'strict': !!$('#strict').attr('checked'),
    };
    out = p.format(s, params, options);

    $('#error').text('');
    $('#output').text(out);

  } catch (e) {

    $('#error').text('Exception: ' + e);
    $('#output').text('');
  }

  if (!rebuild_params) {
    // do a full rebuild on next step, after DOM is created
    clearTimeout(timer);
    timer = setTimeout(change_source, 0);
  }

  return true;
}
<commit_msg>When gathering placeholder names, do not use strict mode<commit_after>var editor;
var timer;
var prev_params_keys;
var params_keys;
var params_html;

var p = new Plurr();
var param_cache = {};
param_cache['N'] = 5;

$(document).ready(function() {
  editor = CodeMirror.fromTextArea(document.getElementById("source"), {onChange: change_source});

  var html = '';
  for (option in plural_options) {
    var sel = option == 'en' ? ' selected' : ''
    html += '<option value="' + option + '"' + sel + '>' + option + ' — ' + plural_options[option] + '</option>';
  }
  $('#locale').html(html);

  change_source();

  $('#locale').on('change', change_locale);
  $('#auto_plurals').on('change', change_source);
  $('#strict').on('change', change_param);
  $(document).on('change keyup cut paste', '#params input', change_param);
});

function cb(name) {
  var value = param_cache[name] || '';
  params_keys += "\n" + name; // using newline as a delimiter
  params_html += '
' + name + ':	<input id="param_'+name+'" param="'+name+'" value="'+value+'" />
';
  return value;
}

function change_locale() {
  return _change(true);
}

function change_source() {
  return _change(true);
}

function change_param() {
  return _change(false);
}

function _change(rebuild_params) {
  var s = editor.getValue().trim();
  var out, params, options;

  try {
    $('#params input').each(function(idx, elem) {
      var name = $(elem).attr('param');
      var value = $(elem).val().trim();
      if (value != '') {
        param_cache[name] = value;
      } else {
        delete param_cache[name];
      }
    });

    if (rebuild_params) {
      options = {
        'locale': $('#locale').val(),
        'auto_plurals': !!$('#auto_plurals').attr('checked'),
        'strict': false,
        'callback': cb,
      };
      params_keys = '';
      params_html = '';
      p.format(s, {}, options);
      if (prev_params_keys != params_keys) {
        $('#params').html(params_html);
        prev_params_keys = params_keys;
      }
    }

    params = {};
    $('#params input').each(function(idx, elem) {
      var name = $(elem).attr('param');
      var value = $(elem).val().trim();
      if (value != '') {
        params[name] = value;
      }
    });

    options = {
      'locale': $('#locale').val(),
      'auto_plurals': !!$('#auto_plurals').attr('checked'),
      'strict': !!$('#strict').attr('checked'),
    };
    out = p.format(s, params, options);

    $('#error').text('');
    $('#output').text(out);

  } catch (e) {

    $('#error').text('Exception: ' + e);
    $('#output').text('');
  }

  if (!rebuild_params) {
    // do a full rebuild on next step, after DOM is created
    clearTimeout(timer);
    timer = setTimeout(change_source, 0);
  }

  return true;
}
<|endoftext|>


<commit_before>
var _gaq = _gaq || [];  // asynchronous stack used by google analytics

openerp.web_analytics = function(instance) {

    /*
    *  The Web Analytics Module inserts the Google Analytics JS Snippet
    *  at the top of the page, and sends to google an url each time the
    *  openerp url is changed.
    *  The pushes of the urls is made by triggering the 'state_pushed' event in the
    *  web_client.do_push_state() method which is responsible of changing the openerp current url
    */

    // Google Analytics Code snippet
    (function() {
        var ga   = document.createElement('script');
        ga.type  = 'text/javascript';
        ga.async = true;
        ga.src   = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(ga,s);
    })();

    instance.web_analytics.Tracker = instance.web.Class.extend({
        /*
        * This method initializes the tracker
        */
        init: function() {
            /* Comment this lines when going on production, only used for testing on localhost
            _gaq.push(['_setAccount', 'UA-35793871-1']);
            _gaq.push(['_setDomainName', 'none']);
            */

            /* Uncomment this lines when going on production */
            _gaq.push(['_setAccount', 'UA-7333765-1']);
            _gaq.push(['_setDomainName', '.openerp.com']);  // Allow multi-domain
            /**/
        },
        /*
        * This method MUST be overriden by saas_demo and saas_trial in order to
        * set the correct user type. By default, the user connected is local to
        * the DB (like in accounts).
        */
        _get_user_type: function() {
            return 'Local User';
        },
        /*
        * This method gets the user access level, to be used as CV in GA
        */
        _get_user_access_level: function() {
            if (instance.session.uid === 1) {
                return 'Admin User';
            // Make the difference between portal users and anonymous users
            } else if (instance.session.username.indexOf('@') !== -1) {
                if (instance.session.username.indexOf('anonymous') === -1) {
                    return 'Portal User';
                } else {
                    return 'Anonymous User';
                }
            } else if (instance.session.username.indexOf('anonymous') !== -1) {
                return 'Anonymous User';
            } else {
                return 'Normal User';
            }
        },
        /*
        * This method contains the initialization of all user-related custom variables
        * stored in GA. Also other modules can override it to add new custom variables
        */
        initialize_custom: function() {
            var self = this;
            return instance.session.rpc("/web/webclient/version_info", {})
                .done(function(res) {
                    _gaq.push(['_setCustomVar', 5, 'Version', res.server_version, 3]);
                    // Track User Access Level, Custom Variable 4 in GA with visitor level scope
                    // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
                    _gaq.push(['_setCustomVar', 4, 'User Access Level', self.user_access_level, 1]);

                    // Track User Type Conversion, Custom Variable 3 in GA with session level scope
                    // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
                    _gaq.push(['_setCustomVar', 1, 'User Type Conversion', self._get_user_type(), 2]);
                    _gaq.push(['_trackPageview']);
                    return;
                });
        },
        /*
        * Method called in order to send _trackPageview to GA
        */
        _push_pageview: function(url) {
            _gaq.push(['_trackPageview', url]);
        },
        /*
        * Method called in order to send _trackEvent to GA
        */
        _push_event: function(options) {
            _gaq.push(['_trackEvent',
                options.category,
                options.action,
                options.label,
                options.value,
                options.noninteraction
            ]);
        },
        /*
        * Method called in order to send ecommerce transactions to GA
        */
        _push_ecommerce: function(trans_data, item_list) {
            _gaq.push(['_addTrans',
                trans_data.order_id,
                trans_data.store_name,
                trans_data.total,
                trans_data.tax,
                trans_data.shipping,
                trans_data.city,
                trans_data.state,
                trans_data.country,
            ]);
            _.each(item_list, function(item) {
                _gaq.push(['_addItem',
                    item.order_id,
                    item.sku,
                    item.name,
                    item.category,
                    item.price,
                    item.quantity,
                ]);
            });
            _gaq.push(['_trackTrans']);
        },
        /*
        *  This method contains the initialization of the object and view type
        *  as an event in GA.
        */
        on_state_pushed: function(state) {
            // Track only pages corresponding to a 'normal' view of OpenERP, views
            // related to client actions are tracked by the action manager
            if (state.model && state.view_type) {
                // Track the page
                var url = instance.web_analytics.generateUrl({'model': state.model, 'view_type': state.view_type});
                this._push_event({
                    'category': state.model,
                    'action': state.view_type,
                    'label': url,
                });
            }
        },
        /*
        * This method includes the tracker into views and managers. It can be overriden
        * by other modules in order to extend tracking functionalities
        */
        include_tracker: function() {
            var t = this;
            // Track the events related with the creation and the  modification of records,
            // the view type is always form
            instance.web.FormView.include({
                init: function(parent, dataset, view_id, options) {
                    this._super.apply(this, arguments);
                    var self = this;
                    this.on('record_created', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                        });
                    });
                    this.on('record_saved', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                        });
                    });
                }
            });

            // Track client actions
            instance.web.ActionManager.include({
                ir_actions_client: function (action, options) {
                    var url = instance.web_analytics.generateUrl({'action': action.tag});
                    var category = action.res_model || action.type;
                    t._push_event({
                        'category': action.res_model || action.type,
                        'action': action.name || action.tag,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track button events
            instance.web.View.include({
                do_execute_action: function(action_data, dataset, record_id, on_closed) {
                    var category = this.model || dataset.model || '';
                    var action;
                    if (action_data.name && _.isNaN(action_data.name-0)) {
                        action = action_data.name;
                    } else {
                        action = action_data.string || action_data.special || '';
                    }
                    var url = instance.web_analytics.generateUrl({'model': category, 'view_type': this.view_type});
                    t._push_event({
                        'category': category,
                        'action': action,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track error events
            instance.web.CrashManager.include({
                show_error: function(error) {
                    var hash = window.location.hash;
                    var params = $.deparam(hash.substr(hash.indexOf('#')+1));
                    var options = {};
                    if (params.model && params.view_type) {
                        options = {'model': params.model, 'view_type': params.view_type};
                    } else {
                        options = {'action': params.action};
                    }
                    var url = instance.web_analytics.generateUrl(options);
                    if (error.code) {
                        t._push_event({
                            'category': error.message,
                            'action': error.data.fault_code,
                            'label': url,
                            'noninteraction': true,
                        });
                    } else {
                        t._push_event({
                            'category': error.type,
                            'action': error.data.debug,
                            'label': url,
                            'noninteraction': true,
                        });
                    }
                    this._super.apply(this, arguments);
                },
            });
        },
    });

    // ----------------------------------------------------------------
    // utility functions
    // ----------------------------------------------------------------

    instance.web_analytics.generateUrl = function(options) {
        var url = '';
        _.each(options, function(value, key) {
            url += '/' + key + '=' + value;
        });
        return url;
    };

    instance.web_analytics.setupTracker = function(wc) {
        var t = wc.tracker;
        return $.when(t._get_user_access_level()).then(function(r) {
            t.user_access_level = r;
            t.initialize_custom().then(function() {
                wc.on('state_pushed', t, t.on_state_pushed);
                t.include_tracker();
            });
        });
    };

    // Set correctly the tracker in the current instance
    if (instance.client instanceof instance.web.WebClient) {        // not for embedded clients
        instance.webclient.tracker = new instance.web_analytics.Tracker();
        instance.web_analytics.setupTracker(instance.webclient);
    } else if (!instance.client) {
        // client does not already exists, we are in monodb mode
        instance.web.WebClient.include({
            start: function() {
                var d = this._super.apply(this, arguments);
                this.tracker = new instance.web_analytics.Tracker();
                return d;
            },
            show_application: function() {
                var self = this;
                $.when(this.subscribe_deferred).then(function() {
                    instance.web_analytics.setupTracker(self);
                });
                this._super();
            },
        });
    }

};
<commit_msg>[FIX] Don't alter bounce rate when tracking events<commit_after>
var _gaq = _gaq || [];  // asynchronous stack used by google analytics

openerp.web_analytics = function(instance) {

    /*
    *  The Web Analytics Module inserts the Google Analytics JS Snippet
    *  at the top of the page, and sends to google an url each time the
    *  openerp url is changed.
    *  The pushes of the urls is made by triggering the 'state_pushed' event in the
    *  web_client.do_push_state() method which is responsible of changing the openerp current url
    */

    // Google Analytics Code snippet
    (function() {
        var ga   = document.createElement('script');
        ga.type  = 'text/javascript';
        ga.async = true;
        ga.src   = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(ga,s);
    })();

    instance.web_analytics.Tracker = instance.web.Class.extend({
        /*
        * This method initializes the tracker
        */
        init: function() {
            /* Comment this lines when going on production, only used for testing on localhost
            _gaq.push(['_setAccount', 'UA-35793871-1']);
            _gaq.push(['_setDomainName', 'none']);
            */

            /* Uncomment this lines when going on production */
            _gaq.push(['_setAccount', 'UA-7333765-1']);
            _gaq.push(['_setDomainName', '.openerp.com']);  // Allow multi-domain
            /**/
        },
        /*
        * This method MUST be overriden by saas_demo and saas_trial in order to
        * set the correct user type. By default, the user connected is local to
        * the DB (like in accounts).
        */
        _get_user_type: function() {
            return 'Local User';
        },
        /*
        * This method gets the user access level, to be used as CV in GA
        */
        _get_user_access_level: function() {
            if (instance.session.uid === 1) {
                return 'Admin User';
            // Make the difference between portal users and anonymous users
            } else if (instance.session.username.indexOf('@') !== -1) {
                if (instance.session.username.indexOf('anonymous') === -1) {
                    return 'Portal User';
                } else {
                    return 'Anonymous User';
                }
            } else if (instance.session.username.indexOf('anonymous') !== -1) {
                return 'Anonymous User';
            } else {
                return 'Normal User';
            }
        },
        /*
        * This method contains the initialization of all user-related custom variables
        * stored in GA. Also other modules can override it to add new custom variables
        */
        initialize_custom: function() {
            var self = this;
            return instance.session.rpc("/web/webclient/version_info", {})
                .done(function(res) {
                    _gaq.push(['_setCustomVar', 5, 'Version', res.server_version, 3]);
                    // Track User Access Level, Custom Variable 4 in GA with visitor level scope
                    // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
                    _gaq.push(['_setCustomVar', 4, 'User Access Level', self.user_access_level, 1]);

                    // Track User Type Conversion, Custom Variable 3 in GA with session level scope
                    // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
                    _gaq.push(['_setCustomVar', 1, 'User Type Conversion', self._get_user_type(), 2]);
                    _gaq.push(['_trackPageview']);
                    return;
                });
        },
        /*
        * Method called in order to send _trackPageview to GA
        */
        _push_pageview: function(url) {
            _gaq.push(['_trackPageview', url]);
        },
        /*
        * Method called in order to send _trackEvent to GA
        */
        _push_event: function(options) {
            _gaq.push(['_trackEvent',
                options.category,
                options.action,
                options.label,
                options.value,
                options.noninteraction
            ]);
        },
        /*
        * Method called in order to send ecommerce transactions to GA
        */
        _push_ecommerce: function(trans_data, item_list) {
            _gaq.push(['_addTrans',
                trans_data.order_id,
                trans_data.store_name,
                trans_data.total,
                trans_data.tax,
                trans_data.shipping,
                trans_data.city,
                trans_data.state,
                trans_data.country,
            ]);
            _.each(item_list, function(item) {
                _gaq.push(['_addItem',
                    item.order_id,
                    item.sku,
                    item.name,
                    item.category,
                    item.price,
                    item.quantity,
                ]);
            });
            _gaq.push(['_trackTrans']);
        },
        /*
        *  This method contains the initialization of the object and view type
        *  as an event in GA.
        */
        on_state_pushed: function(state) {
            // Track only pages corresponding to a 'normal' view of OpenERP, views
            // related to client actions are tracked by the action manager
            if (state.model && state.view_type) {
                // Track the page
                var url = instance.web_analytics.generateUrl({'model': state.model, 'view_type': state.view_type});
                this._push_event({
                    'category': state.model,
                    'action': state.view_type,
                    'label': url,
                });
            }
        },
        /*
        * This method includes the tracker into views and managers. It can be overriden
        * by other modules in order to extend tracking functionalities
        */
        include_tracker: function() {
            var t = this;
            // Track the events related with the creation and the  modification of records,
            // the view type is always form
            instance.web.FormView.include({
                init: function(parent, dataset, view_id, options) {
                    this._super.apply(this, arguments);
                    var self = this;
                    this.on('record_created', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                            'noninteraction': true,
                        });
                    });
                    this.on('record_saved', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                            'noninteraction': true,
                        });
                    });
                }
            });

            // Track client actions
            instance.web.ActionManager.include({
                ir_actions_client: function (action, options) {
                    var url = instance.web_analytics.generateUrl({'action': action.tag});
                    var category = action.res_model || action.type;
                    t._push_event({
                        'category': action.res_model || action.type,
                        'action': action.name || action.tag,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track button events
            instance.web.View.include({
                do_execute_action: function(action_data, dataset, record_id, on_closed) {
                    var category = this.model || dataset.model || '';
                    var action;
                    if (action_data.name && _.isNaN(action_data.name-0)) {
                        action = action_data.name;
                    } else {
                        action = action_data.string || action_data.special || '';
                    }
                    var url = instance.web_analytics.generateUrl({'model': category, 'view_type': this.view_type});
                    t._push_event({
                        'category': category,
                        'action': action,
                        'label': url,
                        'noninteraction': true,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track error events
            instance.web.CrashManager.include({
                show_error: function(error) {
                    var hash = window.location.hash;
                    var params = $.deparam(hash.substr(hash.indexOf('#')+1));
                    var options = {};
                    if (params.model && params.view_type) {
                        options = {'model': params.model, 'view_type': params.view_type};
                    } else {
                        options = {'action': params.action};
                    }
                    var url = instance.web_analytics.generateUrl(options);
                    if (error.code) {
                        t._push_event({
                            'category': error.message,
                            'action': error.data.fault_code,
                            'label': url,
                            'noninteraction': true,
                        });
                    } else {
                        t._push_event({
                            'category': error.type,
                            'action': error.data.debug,
                            'label': url,
                            'noninteraction': true,
                        });
                    }
                    this._super.apply(this, arguments);
                },
            });
        },
    });

    // ----------------------------------------------------------------
    // utility functions
    // ----------------------------------------------------------------

    instance.web_analytics.generateUrl = function(options) {
        var url = '';
        _.each(options, function(value, key) {
            url += '/' + key + '=' + value;
        });
        return url;
    };

    instance.web_analytics.setupTracker = function(wc) {
        var t = wc.tracker;
        return $.when(t._get_user_access_level()).then(function(r) {
            t.user_access_level = r;
            t.initialize_custom().then(function() {
                wc.on('state_pushed', t, t.on_state_pushed);
                t.include_tracker();
            });
        });
    };

    // Set correctly the tracker in the current instance
    if (instance.client instanceof instance.web.WebClient) {        // not for embedded clients
        instance.webclient.tracker = new instance.web_analytics.Tracker();
        instance.web_analytics.setupTracker(instance.webclient);
    } else if (!instance.client) {
        // client does not already exists, we are in monodb mode
        instance.web.WebClient.include({
            start: function() {
                var d = this._super.apply(this, arguments);
                this.tracker = new instance.web_analytics.Tracker();
                return d;
            },
            show_application: function() {
                var self = this;
                $.when(this.subscribe_deferred).then(function() {
                    instance.web_analytics.setupTracker(self);
                });
                this._super();
            },
        });
    }

};
<|endoftext|>


<commit_before>MusicXMLAnalyzer.PatternModel = function(){

	var that = {},
	noteElements = [],
	noteElements4VexFlow = [],

	curMode = 2,
	curName = "c",
	curAccidential = "none",
	curDuration = "quarter",
	curClef = "G",
	curRythSpec = "none",
	curOctave = "4",
	VEXFLOW_REST_SIGN = "r",
	// completeDurationIn64th = 0,
	first = true,

	// in this app a triplet must consist of 3 notes
	tripletCurrentAmount = 0,
	tripletEndPositions = [],
	tupletArray = [],
	beamArray = [],

	// val for noteElements: -1,0,1
	noteElementAccidential = 0,
	// val for dot: true, false
	isDot = false,
	// val for beam: false, begin, continue, end
	beamVal = false,

	init = function() {

	},

	setCurrentMode = function(mode) {
		curMode = mode;
		//set variables to default vals when there is mode 1 or 0
		switch(curMode) {
			//sound sequence
			case 0:
				setDefaultValsForSoundSequenceMode();
				break;
			//rhythm
			case 1:
				setDefaultValsForRhythmMode();
				break;
			case 2:
				setDefaultValsForMelodyMode();
				break;
		}
		//update view
		$(that).trigger('changeViewToCurrentMode', [curMode]);
	},

	getCurrentMode = function() {
		return curMode;
	},

	setCurrentNoteName = function(noteName) {
		console.log("model " + noteName);
		curName = noteName;
	},

	getCurrentNoteName = function() {
		return curName;
	},

	setCurrentAccidential = function(accidential) {
		console.log("model " + accidential);
		curAccidential = accidential;
	},

	getCurrentAccidential = function() {
		return curAccidential;
	},

	setCurrentNoteDuration = function(noteDuration) {
		console.log("model " + noteDuration);
		curDuration = noteDuration;
	},

	//duration like written on button
	getCurrentNoteDuration = function() {
		return curDuration;
	},

	setCurrentClef = function(clef) {
		console.log("model " + clef);
		curClef = clef;
	},

	getCurrentClef = function() {
		return curClef;
	},

	setCurrentNoteRythSpecial = function(rythSpec) {
		console.log("model " + rythSpec);
		curRythSpec = rythSpec;
	},

	getCurrentNoteRythSpecial = function() {
		return curRythSpec;
	},

	setCurrentOctave = function(octave) {
		console.log("model " + octave);
		curOctave = octave;
	},

	getCurrentOctave = function() {
		return curOctave;
	},

	/*
	This method sets vals for accidentials, dots and beams
	for noteElements-Array
	*/
	setValuesForNoteElement = function() {

		//accidential
		if (curAccidential == "#") {
			noteElementAccidential = 1;
		} else if (curAccidential == "b") {
			noteElementAccidential = -1;
		} else {
			noteElementAccidential = 0;
		}

		//dot
		if(curRythSpec == "dotted") {
			isDot = true;
		} else {
			isDot = false;
		}

		//beam
		if(curRythSpec == "triplet") {
			tripletCurrentAmount++;
		}

		switch(tripletCurrentAmount) {
		    case 1:
		        beamVal = "begin";
		        break;
	        case 2:
		        beamVal = "continue";
		        break;
		    case 3:
		        beamVal = "end";
		        break;
		    default:
		        beamVal = false;
		}
	},

	addNoteElement = function() {

		setValuesForNoteElement();

		if (curMode == 2) {
			if(first){
				first = false;
				if (curName != "break") {
					noteElements.push(
					{
					type: curMode,
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									type: curDuration,
									octave: curOctave,
									dot: isDot,
									beam: beamVal
								}
							}
						]
					});
				} else {
					//break
					noteElements.push(
					{
						notes:
						[
							{
							type: "rest",
							duration: curDuration
							}
						]
					});
				}
			} else {
				if (curName != "break") {
					noteElements.push(
					{
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									type: curDuration,
									octave: curOctave,
									dot: isDot,
									beam: beamVal
								}
							}
						]

					});
				} else {
					//break
					noteElements.push(
					{
						notes:
						[
							{
								type: "rest",
								duration: curDuration
							}
						]
					});
				}
			}
		} else if (curMode == 1) {
		// rhythm mode
			if(first){
				first = false;
				if (curName != "break") {
					noteElements.push(
					{
					type: curMode,
						notes:
						[
							{
								type: "note",
								pitch: {
									type: curDuration,
									dot: isDot,
									beam: beamVal
								}
							}
						]
					});
				} else {
					//break
					noteElements.push(
					{
						notes:
						[
							{
								type: "rest",
								duration: curDuration
							}
						]
					});
				}
			} else {
				if (curName != "break") {
					noteElements.push(
					{
						notes:
						[
							{
								type: "note",
								pitch: {
									type: curDuration,
									dot: isDot,
									beam: beamVal
								}
							}
						]
					});
				} else {
					//break
					noteElements.push(
					{
						notes:
						[
							{
								type: "rest",
								duration: curDuration
							}
						]
					});
				}
			}
		} else if (curMode == 0) {
			if(first){
				first = false;
				if (curName != "break") {
					noteElements.push(
					{
					type: curMode,
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									octave: curOctave
								}
							}
						]
					});
				}
			} else {
				if (curName != "break") {
					noteElements.push(
					{
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									octave: curOctave
								}
							}
						]
					});
				}
			}
		}

		console.log("noteELements: ", noteElements);

		//check if break or normal note or note with accidential
		//then adapt values for vexflow an put them into an array
		var note;
		var keyContent = getKeyContent4Vexflow(curName);
		var durationContent = getDuration4Vexflow(curDuration);

		//check if break or normal note or note with accidential
		//then adapt values for vexflow an put them into an array
		if (curName == "break") {
			note = new Vex.Flow.StaveNote({ keys: ["b/4"],
	    						duration: durationContent + VEXFLOW_REST_SIGN,
	    						auto_stem: true });
		} else {
			note = new Vex.Flow.StaveNote({ keys: [keyContent + "/" + curOctave],
	    						duration: durationContent,
	    						auto_stem: true });
		}

		if (curAccidential == "#" || curAccidential == "b") {
			note.addAccidental(0, new Vex.Flow.Accidental(curAccidential));
		}

		if (curRythSpec == "dotted") {
			note.addDotToAll();
		}

		noteElements4VexFlow.push(note);

		//check if triplet
		if (curRythSpec == "triplet") {
			console.log("tripletCurrentAmount: " + tripletCurrentAmount);
			if (tripletCurrentAmount == 3) {
				tripletCurrentAmount = 0;
				//store all end positions of the triplets
				tripletEndPositions.push(noteElements4VexFlow.length);
				//create tuplet and beam and push it into corresponding array
				var tuplet = new Vex.Flow.Tuplet(noteElements4VexFlow.slice(noteElements4VexFlow.length-3, noteElements4VexFlow.length))
				var beam = new Vex.Flow.Tuplet(noteElements4VexFlow.slice(noteElements4VexFlow.length-3, noteElements4VexFlow.length))
				tupletArray.push(tuplet);
				beamArray.push(beam);
				console.log("tripletEndPositions: ",tripletEndPositions)
			}
		} else {
			//when user changes from triplet into different rythSpec
			//when there are already 1 or 2 triplets, they will be deleted and removed from the note and vexflow array
			if (tripletCurrentAmount > 0) {
				//splice -> (position in array, number of elements to be removed)
				noteElements4VexFlow.splice(
					// +1 because of array pos begins with 0
					noteElements4VexFlow.length - (tripletCurrentAmount + 1), tripletCurrentAmount);
				noteElements.slice(
					noteElements.length - (tripletCurrentAmount + 1), tripletCurrentAmount);
				tripletCurrentAmount = 0;
			}
		}

		$(that).trigger('patternChange', [noteElements]);
		// send vexflow note elements to controller and then back to view
		$(that).trigger('updateNotationView', [getAllVexFlowNoteElements()]);

	},

	setDefaultValsForSoundSequenceMode = function() {
		curDuration = "quarter";
		curRythSpec = "none";
	},

	setDefaultValsForRhythmMode = function() {
		curName = "b";
		curOctave = "4";
		curAccidential = "none";
		curClef = "G";
	},

	setDefaultValsForMelodyMode = function() {
		curMode = 2;
		curName = "c";
		curOctave = "4";
		curAccidential = "none";
		curDuration = "quarter";
		curClef = "G";
		curRythSpec = "none";

		//TODO
		//update view to this default vals
		$(that).trigger('changeSelectedNoteName', "c");
		$(that).trigger('changeSelectedOctave', "4");
		$(that).trigger('changeSelectedAccidential', "none");
		$(that).trigger('changeSelectedDuration', "quarter");
		$(that).trigger('changeSelectedClef', "G");
		$(that).trigger('changeSelectedSpecRyth', "none");
	},

	getTripletEndPositions = function() {
		return tripletEndPositions;
	},

	getTupletArray = function() {
		return tupletArray;
	},

	getBeamArray = function() {
		return beamArray;
	},

	getKeyContent4Vexflow = function(noteName) {
		var keyContent = noteName;
		switch (curAccidential) {
			case "#":
				keyContent += "#";
				break;
			case "b":
				keyContent += "b";
				break;
			default:
				//...
		}
		return keyContent;
	},

	getDuration4Vexflow = function(duration) {
		var duration4Vexflow = null;

			if ( duration == "whole") {
				duration4Vexflow = "w";
			} else if ( duration == "half") {
				duration4Vexflow = "h";
			} else if ( duration == "quarter") {
				duration4Vexflow = "q";
			} else if ( duration == "eighth") {
				duration4Vexflow = "8";
			} else if ( duration == "16th") {
				duration4Vexflow = "16";
			} else if ( duration == "32nd") {
				duration4Vexflow = "32";
			} else if ( duration == "64th") {
				duration4Vexflow = "64";
			}

			if (curRythSpec == "dotted") {
				duration4Vexflow += "d";
			}

		return duration4Vexflow;
	},

	/*
	This method gets called when your click on the canvas
	to add a note element.
	The paramter note looks like "c/4".
	It updates the model values curName and curOctave and calls addNoteElement
	*/
	addNoteElementByCanvasClick = function(note) {
		//split string at "/" to get noteName and ovtave
		//and saves it into array noteContainer
		var noteContainer = note.split("/");

		curName = noteContainer[0];
		curOctave = noteContainer[1];

		// updates selected btns for note name and view in pattern view
		$(that).trigger('changeSelectedNoteName', [curName]);
		$(that).trigger('changeSelectedOctave', [curOctave]);

		addNoteElement();

	},

	removeLastNoteElement = function() {
		//ToDo: do "first = true;"" if LastNoteElement equals first note element
		//and remove this element
	    console.log("model: remove last note button; function missing");
	    console.log(noteElements4VexFlow);
	},

	getAllNoteElements = function() {
		return noteElements;
	},

	getAllVexFlowNoteElements = function() {
		return noteElements4VexFlow;
	};

	that.init = init;
	that.getKeyContent4Vexflow = getKeyContent4Vexflow;
	that.getCurrentNoteName = getCurrentNoteName;
	that.getCurrentAccidential = getCurrentAccidential;
	that.getCurrentNoteDuration = getCurrentNoteDuration;
	that.getCurrentClef = getCurrentClef;
	that.getCurrentNoteRythSpecial = getCurrentNoteRythSpecial;
	that.getCurrentOctave = getCurrentOctave;
	that.setCurrentMode = setCurrentMode;
	that.setCurrentNoteName = setCurrentNoteName;
	that.setCurrentAccidential = setCurrentAccidential;
	that.setCurrentNoteDuration = setCurrentNoteDuration;
	that.setCurrentClef = setCurrentClef;
	that.setCurrentNoteRythSpecial = setCurrentNoteRythSpecial;
	that.setCurrentOctave = setCurrentOctave;
	that.addNoteElement = addNoteElement;
	that.addNoteElementByCanvasClick = addNoteElementByCanvasClick;
	that.removeLastNoteElement = removeLastNoteElement;
	that.getCurrentMode = getCurrentMode;
	that.getAllNoteElements = getAllNoteElements;
	that.getAllVexFlowNoteElements = getAllVexFlowNoteElements;
	that.getDuration4Vexflow = getDuration4Vexflow;
	that.getTupletArray = getTupletArray;
	that.getBeamArray = getBeamArray;

	return that;
}
<commit_msg>bugfix pattern array (note elements)<commit_after>MusicXMLAnalyzer.PatternModel = function(){

	var that = {},
	noteElements = [],
	noteElements4VexFlow = [],

	curMode = 2,
	curName = "c",
	curAccidential = "none",
	curDuration = "quarter",
	curClef = "G",
	curRythSpec = "none",
	curOctave = "4",
	VEXFLOW_REST_SIGN = "r",
	// completeDurationIn64th = 0,
	first = true,

	// in this app a triplet must consist of 3 notes
	tripletCurrentAmount = 0,
	tripletEndPositions = [],
	tupletArray = [],
	beamArray = [],

	// val for noteElements: -1,0,1
	noteElementAccidential = 0,
	// val for dot: true, false
	isDot = false,
	// val for beam: false, begin, continue, end
	beamVal = false,

	init = function() {

	},

	setCurrentMode = function(mode) {
		curMode = mode;
		//set variables to default vals when there is mode 1 or 0
		switch(curMode) {
			//sound sequence
			case 0:
				setDefaultValsForSoundSequenceMode();
				break;
			//rhythm
			case 1:
				setDefaultValsForRhythmMode();
				break;
			case 2:
				setDefaultValsForMelodyMode();
				break;
		}
		//update view
		$(that).trigger('changeViewToCurrentMode', [curMode]);
	},

	getCurrentMode = function() {
		return curMode;
	},

	setCurrentNoteName = function(noteName) {
		console.log("model " + noteName);
		curName = noteName;
	},

	getCurrentNoteName = function() {
		return curName;
	},

	setCurrentAccidential = function(accidential) {
		console.log("model " + accidential);
		curAccidential = accidential;
	},

	getCurrentAccidential = function() {
		return curAccidential;
	},

	setCurrentNoteDuration = function(noteDuration) {
		console.log("model " + noteDuration);
		curDuration = noteDuration;
	},

	//duration like written on button
	getCurrentNoteDuration = function() {
		return curDuration;
	},

	setCurrentClef = function(clef) {
		console.log("model " + clef);
		curClef = clef;
	},

	getCurrentClef = function() {
		return curClef;
	},

	setCurrentNoteRythSpecial = function(rythSpec) {
		console.log("model " + rythSpec);
		curRythSpec = rythSpec;
	},

	getCurrentNoteRythSpecial = function() {
		return curRythSpec;
	},

	setCurrentOctave = function(octave) {
		console.log("model " + octave);
		curOctave = octave;
	},

	getCurrentOctave = function() {
		return curOctave;
	},

	/*
	This method sets vals for accidentials, dots and beams
	for noteElements-Array
	*/
	setValuesForNoteElement = function() {

		//accidential
		if (curAccidential == "#") {
			noteElementAccidential = 1;
		} else if (curAccidential == "b") {
			noteElementAccidential = -1;
		} else {
			noteElementAccidential = 0;
		}

		//dot
		if(curRythSpec == "dotted") {
			isDot = true;
		} else {
			isDot = false;
		}

		//beam
		if(curRythSpec == "triplet") {
			tripletCurrentAmount++;
		}

		switch(tripletCurrentAmount) {
		    case 1:
		        beamVal = "begin";
		        break;
	        case 2:
		        beamVal = "continue";
		        break;
		    case 3:
		        beamVal = "end";
		        break;
		    default:
		        beamVal = false;
		}
	},

	addNoteElement = function() {

		setValuesForNoteElement();

		if (curMode == 2) {
			if(first){
				first = false;
				if (curName != "break") {
					noteElements.push(
					{
					type: curMode,
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									type: curDuration,
									octave: curOctave,
									dot: isDot,
									beam: beamVal
								}
							}
						]
					});
				} else {
					//break
					noteElements.push(
					{
						notes:
						[
							{
							type: "rest",
							duration: curDuration
							}
						]
					});
				}
			} else {
				if (curName != "break") {
					noteElements[0].notes.push(
					{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									type: curDuration,
									octave: curOctave,
									dot: isDot,
									beam: beamVal
								}
					});
				} else {
					//break
					noteElements[0].notes.push(
					{
						type: "rest",
						duration: curDuration
					});
				}
			}
		} else if (curMode == 1) {
		// rhythm mode
			if(first){
				first = false;
				if (curName != "break") {
					noteElements.push(
					{
					type: curMode,
						notes:
						[
							{
								type: "note",
								pitch: {
									type: curDuration,
									dot: isDot,
									beam: beamVal
								}
							}
						]
					});
				} else {
					//break
					noteElements.push(
					{
						notes:
						[
							{
								type: "rest",
								duration: curDuration
							}
						]
					});
				}
			} else {
				if (curName != "break") {
					noteElements[0].notes.push(
					{
						notes:
						[
							{
								type: "note",
								pitch: {
									type: curDuration,
									dot: isDot,
									beam: beamVal
								}
							}
						]
					});
				} else {
					//break
					noteElements[0].notes.push(
					{
						notes:
						[
							{
								type: "rest",
								duration: curDuration
							}
						]
					});
				}
			}
		} else if (curMode == 0) {
			if(first){
				first = false;
				if (curName != "break") {
					noteElements.push(
					{
					type: curMode,
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									octave: curOctave
								}
							}
						]
					});
				}
			} else {
				if (curName != "break") {
					noteElements[0].notes.push(
					{
						notes:
						[
							{
								type: "note",
								pitch: {
									step: curName.toUpperCase(),
									alter: noteElementAccidential,
									octave: curOctave
								}
							}
						]
					});
				}
			}
		}

		console.log("noteELements: ", noteElements);

		//check if break or normal note or note with accidential
		//then adapt values for vexflow an put them into an array
		var note;
		var keyContent = getKeyContent4Vexflow(curName);
		var durationContent = getDuration4Vexflow(curDuration);

		//check if break or normal note or note with accidential
		//then adapt values for vexflow an put them into an array
		if (curName == "break") {
			note = new Vex.Flow.StaveNote({ keys: ["b/4"],
	    						duration: durationContent + VEXFLOW_REST_SIGN,
	    						auto_stem: true });
		} else {
			note = new Vex.Flow.StaveNote({ keys: [keyContent + "/" + curOctave],
	    						duration: durationContent,
	    						auto_stem: true });
		}

		if (curAccidential == "#" || curAccidential == "b") {
			note.addAccidental(0, new Vex.Flow.Accidental(curAccidential));
		}

		if (curRythSpec == "dotted") {
			note.addDotToAll();
		}

		noteElements4VexFlow.push(note);

		//check if triplet
		if (curRythSpec == "triplet") {
			console.log("tripletCurrentAmount: " + tripletCurrentAmount);
			if (tripletCurrentAmount == 3) {
				tripletCurrentAmount = 0;
				//store all end positions of the triplets
				tripletEndPositions.push(noteElements4VexFlow.length);
				//create tuplet and beam and push it into corresponding array
				var tuplet = new Vex.Flow.Tuplet(noteElements4VexFlow.slice(noteElements4VexFlow.length-3, noteElements4VexFlow.length))
				var beam = new Vex.Flow.Tuplet(noteElements4VexFlow.slice(noteElements4VexFlow.length-3, noteElements4VexFlow.length))
				tupletArray.push(tuplet);
				beamArray.push(beam);
				console.log("tripletEndPositions: ",tripletEndPositions)
			}
		} else {
			//when user changes from triplet into different rythSpec
			//when there are already 1 or 2 triplets, they will be deleted and removed from the note and vexflow array
			if (tripletCurrentAmount > 0) {
				//splice -> (position in array, number of elements to be removed)
				noteElements4VexFlow.splice(
					// +1 because of array pos begins with 0
					noteElements4VexFlow.length - (tripletCurrentAmount + 1), tripletCurrentAmount);
				noteElements.slice(
					noteElements.length - (tripletCurrentAmount + 1), tripletCurrentAmount);
				tripletCurrentAmount = 0;
			}
		}

		$(that).trigger('patternChange', [noteElements]);
		// send vexflow note elements to controller and then back to view
		$(that).trigger('updateNotationView', [getAllVexFlowNoteElements()]);

	},

	setDefaultValsForSoundSequenceMode = function() {
		curDuration = "quarter";
		curRythSpec = "none";
	},

	setDefaultValsForRhythmMode = function() {
		curName = "b";
		curOctave = "4";
		curAccidential = "none";
		curClef = "G";
	},

	setDefaultValsForMelodyMode = function() {
		curMode = 2;
		curName = "c";
		curOctave = "4";
		curAccidential = "none";
		curDuration = "quarter";
		curClef = "G";
		curRythSpec = "none";

		//TODO
		//update view to this default vals
		$(that).trigger('changeSelectedNoteName', "c");
		$(that).trigger('changeSelectedOctave', "4");
		$(that).trigger('changeSelectedAccidential', "none");
		$(that).trigger('changeSelectedDuration', "quarter");
		$(that).trigger('changeSelectedClef', "G");
		$(that).trigger('changeSelectedSpecRyth', "none");
	},

	getTripletEndPositions = function() {
		return tripletEndPositions;
	},

	getTupletArray = function() {
		return tupletArray;
	},

	getBeamArray = function() {
		return beamArray;
	},

	getKeyContent4Vexflow = function(noteName) {
		var keyContent = noteName;
		switch (curAccidential) {
			case "#":
				keyContent += "#";
				break;
			case "b":
				keyContent += "b";
				break;
			default:
				//...
		}
		return keyContent;
	},

	getDuration4Vexflow = function(duration) {
		var duration4Vexflow = null;

			if ( duration == "whole") {
				duration4Vexflow = "w";
			} else if ( duration == "half") {
				duration4Vexflow = "h";
			} else if ( duration == "quarter") {
				duration4Vexflow = "q";
			} else if ( duration == "eighth") {
				duration4Vexflow = "8";
			} else if ( duration == "16th") {
				duration4Vexflow = "16";
			} else if ( duration == "32nd") {
				duration4Vexflow = "32";
			} else if ( duration == "64th") {
				duration4Vexflow = "64";
			}

			if (curRythSpec == "dotted") {
				duration4Vexflow += "d";
			}

		return duration4Vexflow;
	},

	/*
	This method gets called when your click on the canvas
	to add a note element.
	The paramter note looks like "c/4".
	It updates the model values curName and curOctave and calls addNoteElement
	*/
	addNoteElementByCanvasClick = function(note) {
		//split string at "/" to get noteName and ovtave
		//and saves it into array noteContainer
		var noteContainer = note.split("/");

		curName = noteContainer[0];
		curOctave = noteContainer[1];

		// updates selected btns for note name and view in pattern view
		$(that).trigger('changeSelectedNoteName', [curName]);
		$(that).trigger('changeSelectedOctave', [curOctave]);

		addNoteElement();

	},

	removeLastNoteElement = function() {
		//ToDo: do "first = true;"" if LastNoteElement equals first note element
		//and remove this element
	    console.log("model: remove last note button; function missing");
	    console.log(noteElements4VexFlow);
	},

	getAllNoteElements = function() {
		return noteElements;
	},

	getAllVexFlowNoteElements = function() {
		return noteElements4VexFlow;
	};

	that.init = init;
	that.getKeyContent4Vexflow = getKeyContent4Vexflow;
	that.getCurrentNoteName = getCurrentNoteName;
	that.getCurrentAccidential = getCurrentAccidential;
	that.getCurrentNoteDuration = getCurrentNoteDuration;
	that.getCurrentClef = getCurrentClef;
	that.getCurrentNoteRythSpecial = getCurrentNoteRythSpecial;
	that.getCurrentOctave = getCurrentOctave;
	that.setCurrentMode = setCurrentMode;
	that.setCurrentNoteName = setCurrentNoteName;
	that.setCurrentAccidential = setCurrentAccidential;
	that.setCurrentNoteDuration = setCurrentNoteDuration;
	that.setCurrentClef = setCurrentClef;
	that.setCurrentNoteRythSpecial = setCurrentNoteRythSpecial;
	that.setCurrentOctave = setCurrentOctave;
	that.addNoteElement = addNoteElement;
	that.addNoteElementByCanvasClick = addNoteElementByCanvasClick;
	that.removeLastNoteElement = removeLastNoteElement;
	that.getCurrentMode = getCurrentMode;
	that.getAllNoteElements = getAllNoteElements;
	that.getAllVexFlowNoteElements = getAllVexFlowNoteElements;
	that.getDuration4Vexflow = getDuration4Vexflow;
	that.getTupletArray = getTupletArray;
	that.getBeamArray = getBeamArray;

	return that;
}
<|endoftext|>


<commit_before>import { Confirm, Modal } from "reactjs-components";
import { routerShape } from "react-router";
import PureRender from "react-addons-pure-render-mixin";
import React, { PropTypes } from "react";
import { injectIntl, intlShape } from "react-intl";

import ModalHeading from "#SRC/js/components/modals/ModalHeading";
import StringUtil from "#SRC/js/utils/StringUtil";
import UserActions from "#SRC/js/constants/UserActions";
import ClickToSelect from "#SRC/js/components/ClickToSelect";

import AppLockedMessage from "./AppLockedMessage";
import Framework from "../../structs/Framework";
import Pod from "../../structs/Pod";
import Service from "../../structs/Service";
import ServiceTree from "../../structs/ServiceTree";

// This needs to be at least equal to @modal-animation-duration
const REDIRECT_DELAY = 300;
const METHODS_TO_BIND = [
  "handleChangeInputFieldDestroy",
  "handleModalClose",
  "handleRightButtonClick"
];

class ServiceDestroyModal extends React.Component {
  constructor() {
    super(...arguments);

    this.state = {
      errorMsg: null,
      serviceNameConfirmationValue: ""
    };

    this.shouldComponentUpdate = PureRender.shouldComponentUpdate.bind(this);

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillUpdate(nextProps) {
    const requestCompleted = this.props.isPending && !nextProps.isPending;

    const shouldClose = requestCompleted && !nextProps.errors;

    if (shouldClose) {
      this.redirectToServices();
    }
  }

  componentWillReceiveProps(nextProps) {
    const { errors } = nextProps;
    if (!errors) {
      this.setState({ errorMsg: null });

      return;
    }

    if (typeof errors === "string") {
      this.setState({ errorMsg: errors });

      return;
    }

    let { message: errorMsg = "", details } = errors;
    const hasDetails = details && details.length !== 0;

    if (hasDetails) {
      errorMsg = details.reduce(function(memo, error) {
        return `${memo} ${error.errors.join(" ")}`;
      }, "");
    }

    if (!errorMsg || !errorMsg.length) {
      errorMsg = null;
    }

    this.setState({ errorMsg });
  }

  shouldForceUpdate() {
    return this.state.errorMsg && /force=true/.test(this.state.errorMsg);
  }

  handleModalClose() {
    this.setState({ serviceNameConfirmationValue: "" });
    this.props.onClose();
  }

  handleRightButtonClick() {
    if (!this.getIsRightButtonDisabled()) {
      this.props.deleteItem(this.shouldForceUpdate());
      this.setState({ serviceNameConfirmationValue: "" });
    }
  }

  handleChangeInputFieldDestroy(event) {
    this.setState({
      serviceNameConfirmationValue: event.target.value
    });
  }

  getIsRightButtonDisabled() {
    return (
      this.props.service.getId() !== this.state.serviceNameConfirmationValue
    );
  }

  getErrorMessage() {
    const { errorMsg = null } = this.state;

    if (!errorMsg) {
      return null;
    }

    if (this.shouldForceUpdate()) {
      return <AppLockedMessage service={this.props.service} />;
    }

    return (

{errorMsg}

    );
  }

  redirectToServices() {
    const { router } = this.context;

    // Close the modal and redirect after the close animation has completed
    this.props.onClose();
    setTimeout(() => {
      router.push({ pathname: "/services/overview" });
    }, REDIRECT_DELAY);
  }

  getCloseButton() {
    return (

        <button
          className="button button-primary button-medium"
          onClick={this.handleModalClose}
        >
          Close
        </button>

    );
  }

  getDestroyFrameworkModal() {
    const { open, service, intl } = this.props;
    const serviceName = service.getId();

    return (
      <Modal
        header={this.getModalHeading()}
        footer={this.getCloseButton()}
        modalClass="modal"
        onClose={this.handleModalClose}
        open={open}
        showHeader={true}
        showFooter={true}
        subHeader={this.getSubHeader()}
      >

          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE_FRAMEWORK"
          })}

            {intl.formatMessage({
              id: "COMMON.DOCUMENTATION"
            })}

          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE_FRAMEWORK_2"
          })}

          <ClickToSelect>

              dcos packages uninstall --app-id={serviceName}

          </ClickToSelect>

        {this.getErrorMessage()}
      </Modal>
    );
  }

  getDestroyServiceModal() {
    const { open, service, intl } = this.props;
    const serviceName = service.getId();

    let itemText = `${StringUtil.capitalize(UserActions.DELETE)}`;

    if (service instanceof Pod) {
      itemText += " Pod";
    }

    if (service instanceof ServiceTree) {
      itemText += " Group";
    }

    return (
      <Confirm
        disabled={this.getIsRightButtonDisabled()}
        header={this.getModalHeading()}
        open={open}
        onClose={this.handleModalClose}
        leftButtonText="Cancel"
        leftButtonCallback={this.handleModalClose}
        rightButtonText={itemText}
        rightButtonClassName="button button-danger"
        rightButtonCallback={this.handleRightButtonClick}
        showHeader={true}
      >

          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE"
          })}
          {serviceName}
          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE_2"
          })}

        <input
          className="form-control filter-input-text"
          onChange={this.handleChangeInputFieldDestroy}
          type="text"
          value={this.state.serviceNameConfirmationValue}
        />
        {this.getErrorMessage()}
      </Confirm>
    );
  }

  getModalHeading() {
    return (
      <ModalHeading className="text-danger">
        {StringUtil.capitalize(UserActions.DELETE)}
      </ModalHeading>
    );
  }

  getSubHeader() {
    if (!this.props.subHeaderContent) {
      return null;
    }

    return (

        {this.props.subHeaderContent}

    );
  }

  render() {
    const { service } = this.props;

    if (service instanceof Framework) {
      return this.getDestroyFrameworkModal();
    }

    return this.getDestroyServiceModal();
  }
}

ServiceDestroyModal.contextTypes = {
  router: routerShape
};

ServiceDestroyModal.propTypes = {
  deleteItem: PropTypes.func.isRequired,
  errors: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
  intl: intlShape.isRequired,
  isPending: PropTypes.bool.isRequired,
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  service: PropTypes.oneOfType([
    PropTypes.instanceOf(Framework),
    PropTypes.instanceOf(Pod),
    PropTypes.instanceOf(ServiceTree),
    PropTypes.instanceOf(Service)
  ]).isRequired
};

module.exports = injectIntl(ServiceDestroyModal);
<commit_msg>feat(DCOS-15159): Fix package command to remove package<commit_after>import { Confirm, Modal } from "reactjs-components";
import { routerShape } from "react-router";
import PureRender from "react-addons-pure-render-mixin";
import React, { PropTypes } from "react";
import { injectIntl, intlShape } from "react-intl";

import ModalHeading from "#SRC/js/components/modals/ModalHeading";
import StringUtil from "#SRC/js/utils/StringUtil";
import UserActions from "#SRC/js/constants/UserActions";
import ClickToSelect from "#SRC/js/components/ClickToSelect";

import AppLockedMessage from "./AppLockedMessage";
import Framework from "../../structs/Framework";
import Pod from "../../structs/Pod";
import Service from "../../structs/Service";
import ServiceTree from "../../structs/ServiceTree";

// This needs to be at least equal to @modal-animation-duration
const REDIRECT_DELAY = 300;
const METHODS_TO_BIND = [
  "handleChangeInputFieldDestroy",
  "handleModalClose",
  "handleRightButtonClick"
];

class ServiceDestroyModal extends React.Component {
  constructor() {
    super(...arguments);

    this.state = {
      errorMsg: null,
      serviceNameConfirmationValue: ""
    };

    this.shouldComponentUpdate = PureRender.shouldComponentUpdate.bind(this);

    METHODS_TO_BIND.forEach(method => {
      this[method] = this[method].bind(this);
    });
  }

  componentWillUpdate(nextProps) {
    const requestCompleted = this.props.isPending && !nextProps.isPending;

    const shouldClose = requestCompleted && !nextProps.errors;

    if (shouldClose) {
      this.redirectToServices();
    }
  }

  componentWillReceiveProps(nextProps) {
    const { errors } = nextProps;
    if (!errors) {
      this.setState({ errorMsg: null });

      return;
    }

    if (typeof errors === "string") {
      this.setState({ errorMsg: errors });

      return;
    }

    let { message: errorMsg = "", details } = errors;
    const hasDetails = details && details.length !== 0;

    if (hasDetails) {
      errorMsg = details.reduce(function(memo, error) {
        return `${memo} ${error.errors.join(" ")}`;
      }, "");
    }

    if (!errorMsg || !errorMsg.length) {
      errorMsg = null;
    }

    this.setState({ errorMsg });
  }

  shouldForceUpdate() {
    return this.state.errorMsg && /force=true/.test(this.state.errorMsg);
  }

  handleModalClose() {
    this.setState({ serviceNameConfirmationValue: "" });
    this.props.onClose();
  }

  handleRightButtonClick() {
    if (!this.getIsRightButtonDisabled()) {
      this.props.deleteItem(this.shouldForceUpdate());
      this.setState({ serviceNameConfirmationValue: "" });
    }
  }

  handleChangeInputFieldDestroy(event) {
    this.setState({
      serviceNameConfirmationValue: event.target.value
    });
  }

  getIsRightButtonDisabled() {
    return (
      this.props.service.getId() !== this.state.serviceNameConfirmationValue
    );
  }

  getErrorMessage() {
    const { errorMsg = null } = this.state;

    if (!errorMsg) {
      return null;
    }

    if (this.shouldForceUpdate()) {
      return <AppLockedMessage service={this.props.service} />;
    }

    return (

{errorMsg}

    );
  }

  redirectToServices() {
    const { router } = this.context;

    // Close the modal and redirect after the close animation has completed
    this.props.onClose();
    setTimeout(() => {
      router.push({ pathname: "/services/overview" });
    }, REDIRECT_DELAY);
  }

  getCloseButton() {
    return (

        <button
          className="button button-primary button-medium"
          onClick={this.handleModalClose}
        >
          Close
        </button>

    );
  }

  getDestroyFrameworkModal() {
    const { open, service, intl } = this.props;
    const serviceName = service.getId();

    return (
      <Modal
        header={this.getModalHeading()}
        footer={this.getCloseButton()}
        modalClass="modal"
        onClose={this.handleModalClose}
        open={open}
        showHeader={true}
        showFooter={true}
        subHeader={this.getSubHeader()}
      >

          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE_FRAMEWORK"
          })}

            {intl.formatMessage({
              id: "COMMON.DOCUMENTATION"
            })}

          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE_FRAMEWORK_2"
          })}

          <ClickToSelect>

              dcos package uninstall
              {" "}
              {serviceName.replace("/", "")} --app-id={serviceName}

          </ClickToSelect>

        {this.getErrorMessage()}
      </Modal>
    );
  }

  getDestroyServiceModal() {
    const { open, service, intl } = this.props;
    const serviceName = service.getId();

    let itemText = `${StringUtil.capitalize(UserActions.DELETE)}`;

    if (service instanceof Pod) {
      itemText += " Pod";
    }

    if (service instanceof ServiceTree) {
      itemText += " Group";
    }

    return (
      <Confirm
        disabled={this.getIsRightButtonDisabled()}
        header={this.getModalHeading()}
        open={open}
        onClose={this.handleModalClose}
        leftButtonText="Cancel"
        leftButtonCallback={this.handleModalClose}
        rightButtonText={itemText}
        rightButtonClassName="button button-danger"
        rightButtonCallback={this.handleRightButtonClick}
        showHeader={true}
      >

          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE"
          })}
          {serviceName}
          {intl.formatMessage({
            id: "SERVICE_ACTIONS.DELETE_SERVICE_2"
          })}

        <input
          className="form-control filter-input-text"
          onChange={this.handleChangeInputFieldDestroy}
          type="text"
          value={this.state.serviceNameConfirmationValue}
        />
        {this.getErrorMessage()}
      </Confirm>
    );
  }

  getModalHeading() {
    return (
      <ModalHeading className="text-danger">
        {StringUtil.capitalize(UserActions.DELETE)}
      </ModalHeading>
    );
  }

  getSubHeader() {
    if (!this.props.subHeaderContent) {
      return null;
    }

    return (

        {this.props.subHeaderContent}

    );
  }

  render() {
    const { service } = this.props;

    if (service instanceof Framework) {
      return this.getDestroyFrameworkModal();
    }

    return this.getDestroyServiceModal();
  }
}

ServiceDestroyModal.contextTypes = {
  router: routerShape
};

ServiceDestroyModal.propTypes = {
  deleteItem: PropTypes.func.isRequired,
  errors: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
  intl: intlShape.isRequired,
  isPending: PropTypes.bool.isRequired,
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  service: PropTypes.oneOfType([
    PropTypes.instanceOf(Framework),
    PropTypes.instanceOf(Pod),
    PropTypes.instanceOf(ServiceTree),
    PropTypes.instanceOf(Service)
  ]).isRequired
};

module.exports = injectIntl(ServiceDestroyModal);
<|endoftext|>


<commit_before>'use strict';

/**
 * Get an accurate type check for the given Object.
 *
 * @param {Mixed} obj The object that needs to be detected.
 * @returns {String} The object type
 * @api private
 */
function type(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

/**
 * Iterate over a collection.
 *
 * @param {Mixed} collection The object we want to iterate over.
 * @param {Function} iterator The function that's called for each iteration.
 * @param {Mixed} context The context of the function.
 * @api private
 */
function each(collection, iterator, context) {
  if ('function' === typeof collection.forEach) {
    return collection.forEach(iterator, context);
  }

  var i = 0;

  if ('array' === type(collection)) {
    for (; i < collection.length; i++) {
      iterator.call(context, collection[i], i, collection);
    }
  } else {
    for (i in collection) {
      iterator.call(context, i, collection[i]);
    }
  }
}

/**
 * Checks if the given object is empty. The only edge case here would be
 * objects. Most object's have a `length` attribute that indicate if there's
 * anything inside the object.
 *
 * @param {Mixed} collection The collection that needs to be checked.
 * @returns {Boolean}
 * @api private
 */
function empty(obj) {
  if (!obj) return false;
  return size(obj) === 0;
}

/**
 * Determin the size of a collection.
 *
 * @param {Mixed} collection The object we want to know the size of.
 * @returns {Number} The size of the collection.
 * @api private
 */
function size(collection) {
  var x, i = 0;

  if ('object' === type(collection)) {
    for (x in collection) i++;
    return i;
  }

  return +collection.length;
}

exports.empty = empty;
exports.size = size;
exports.type = type;
exports.each = each;
<commit_msg>[fix] The first argument of a `each` call should always be value. [minor] Added a collection#array method to transform values in arrays.<commit_after>'use strict';

/**
 * Get an accurate type check for the given Object.
 *
 * @param {Mixed} obj The object that needs to be detected.
 * @returns {String} The object type
 * @api private
 */
function type(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

/**
 * Iterate over a collection.
 *
 * @param {Mixed} collection The object we want to iterate over.
 * @param {Function} iterator The function that's called for each iteration.
 * @param {Mixed} context The context of the function.
 * @api private
 */
function each(collection, iterator, context) {
  if ('function' === typeof collection.forEach) {
    return collection.forEach(iterator, context);
  }

  var i = 0;

  if ('array' === type(collection)) {
    for (; i < collection.length; i++) {
      iterator.call(context, collection[i], i, collection);
    }
  } else {
    for (i in collection) {
      iterator.call(context, collection[i], i);
    }
  }
}

/**
 * Checks if the given object is empty. The only edge case here would be
 * objects. Most object's have a `length` attribute that indicate if there's
 * anything inside the object.
 *
 * @param {Mixed} collection The collection that needs to be checked.
 * @returns {Boolean}
 * @api private
 */
function empty(obj) {
  if (!obj) return false;
  return size(obj) === 0;
}

/**
 * Determin the size of a collection.
 *
 * @param {Mixed} collection The object we want to know the size of.
 * @returns {Number} The size of the collection.
 * @api private
 */
function size(collection) {
  var x, i = 0;

  if ('object' === type(collection)) {
    for (x in collection) i++;
    return i;
  }

  return +collection.length;
}

/**
 * Wrap the given object in an array if it's not an array allready.
 *
 * @param {Mixed} obj The thing we might need to wrap.
 * @returns {Array} We promise!
 * @api private
 */
function array(obj) {
  if ('array' === type(obj)) return obj;

  return obj  // Only transform objects in to an array when they exist.
    ? [ obj ]
    : [];
}

//
// Expose the collection utilities.
//
exports.array = array;
exports.empty = empty;
exports.size = size;
exports.type = type;
exports.each = each;
<|endoftext|>