<commit_before>import Ember from 'ember';

import I18nService from 'ember-i18n/services/i18n';
import I18nRuLocale from 'ember-flexberry/locales/ru/translations';
import I18nEnLocale from 'ember-flexberry/locales/en/translations';

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('flexberry-textarea', 'Integration | Component | flexberry-textarea', {
  integration: true,

  beforeEach: function () {
    this.register('locale:ru/translations', I18nRuLocale);
    this.register('locale:en/translations', I18nEnLocale);
    this.register('service:i18n', I18nService);

    this.inject.service('i18n', { as: 'i18n' });
    Ember.Component.reopen({
      i18n: Ember.inject.service('i18n')
    });

    // Set 'ru' as initial locale.
    this.set('i18n.locale', 'ru');
  }
});

test('it renders properly', function(assert) {
  assert.expect(10);

  // Render component.
  this.render(hbs`{{flexberry-textarea
    class=class
  }}`);

  // Retrieve component.
  let $component = this.$().children();

  // Check wrapper <div>.
  assert.strictEqual($component.prop('tagName'), 'DIV', 'Component\'s wrapper is a <div>');
  assert.strictEqual($component.hasClass('flexberry-textarea'), true, 'Component\'s wrapper has \' flexberry-textarea\' css-class');
  assert.strictEqual($component.hasClass('ui'), true, 'Component\'s wrapper has \'ui\' css-class');
  assert.strictEqual($component.hasClass('input'), true, 'Component\'s wrapper has \'input\' css-class');

  // Check wrapper's additional CSS-classes.
  let additioanlCssClasses = 'fluid mini huge';
  this.set('class', additioanlCssClasses);
  Ember.A(additioanlCssClasses.split(' ')).forEach((cssClassName, index) => {
    assert.strictEqual(
    $component.hasClass(cssClassName),
    true,
    'Component\'s wrapper has additional css class \'' + cssClassName + '\'');
  });

  // Clean up wrapper's additional CSS-classes.
  this.set('class', '');
  Ember.A(additioanlCssClasses.split(' ')).forEach((cssClassName, index) => {
    assert.strictEqual(
    $component.hasClass(cssClassName),
    false,
    'Component\'s wrapper hasn\'t additional css class \'' + cssClassName + '\'');
  });
});

test('readonly mode works properly', function(assert) {
  assert.expect(3);

  // Render component.
  this.render(hbs`{{flexberry-textarea
    class=class
    readonly=readonly
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('input');

  // Check that <input>'s readonly attribute doesn't exist yet.
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('readonly')),
    '',
    'Component\'s inner <input> hasn\'t readonly attribute');

  // Activate readonly mode & check that <input>'s readonly attribute exists now & has value equals to 'readonly'.
  this.set('readonly', true);
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('readonly')),
    'readonly',
    'Component\'s inner <input> has readonly attribute with value equals to \'readonly\'');

  // Check that <input>'s readonly attribute doesn't exist now.
  this.set('readonly', false);
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('readonly')),
    '',
    'Component\'s inner <input> hasn\'t readonly attribute');
});

test('readonly mode works properly with value', function(assert) {
  assert.expect(2);

  // Set <input>'s value' & render component.
  this.set('value', null);
  this.set('readonly', true);
  this.render(hbs`{{flexberry-textarea
    readonly=readonly
    value=value
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('input');

  $textareaInput.on('change', (e) => {
    if (this.get('readonly')) {
      e.stopPropagation();
      $textareaInput.val(null);
    }
  });

  let newValue = 'New value';
  $textareaInput.val(newValue);
  $textareaInput.change();

  // Check <input>'s value not chenged.
  assert.strictEqual(
    Ember.$.trim($textareaInput.val()),
    '',
    'Component\'s inner <input>\'s value not chenged');
  assert.strictEqual(
    this.get('value'),
    null,
    'Component\'s property binded to unchanged \'value\'');
});

test('it renders i18n-ed placeholder', function(assert) {
  assert.expect(2);

  // Render component.
  this.render(hbs`{{flexberry-textarea}}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('input');

  // Check <input>'s placeholder.
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    Ember.get(I18nRuLocale, 'components.flexberry-textarea.placeholder'),
    'Component\'s inner <input>\'s placeholder is equals to it\'s default value from i18n locales/ru/translations');

  // Change current locale to 'en' & check <input>'s placeholder again.
  this.set('i18n.locale', 'en');
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    Ember.get(I18nEnLocale, 'components.flexberry-textarea.placeholder'),
    'Component\'s inner <input>\'s placeholder is equals to it\'s value from i18n locales/en/translations');
});

test('it renders manually defined placeholder', function(assert) {
  assert.expect(2);

  // Set <input>'s placeholder' & render component.
  let placeholder = 'Input is empty, please type some text';
  this.set('placeholder', placeholder);
  this.render(hbs`{{flexberry-textarea
    placeholder=placeholder
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('input');

  // Check <input>'s placeholder.
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    placeholder,
    'Component\'s inner <input>\'s placeholder is equals to manually defined value \'' + placeholder + '\'');

  // Change placeholder's value & check <input>'s placeholder again.
  placeholder = 'Input has no value';
  this.set('placeholder', placeholder);
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    placeholder,
    'Component\'s inner <input>\'s placeholder is equals to manually updated value \'' + placeholder + '\'');
});
<commit_msg>Fix test.<commit_after>import Ember from 'ember';

import I18nService from 'ember-i18n/services/i18n';
import I18nRuLocale from 'ember-flexberry/locales/ru/translations';
import I18nEnLocale from 'ember-flexberry/locales/en/translations';

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('flexberry-textarea', 'Integration | Component | flexberry-textarea', {
  integration: true,

  beforeEach: function () {
    this.register('locale:ru/translations', I18nRuLocale);
    this.register('locale:en/translations', I18nEnLocale);
    this.register('service:i18n', I18nService);

    this.inject.service('i18n', { as: 'i18n' });
    Ember.Component.reopen({
      i18n: Ember.inject.service('i18n')
    });

    // Set 'ru' as initial locale.
    this.set('i18n.locale', 'ru');
  }
});

test('it renders properly', function(assert) {
  assert.expect(10);

  // Render component.
  this.render(hbs`{{flexberry-textarea
    class=class
  }}`);

  // Retrieve component.
  let $component = this.$().children();

  // Check wrapper <div>.
  assert.strictEqual($component.prop('tagName'), 'DIV', 'Component\'s wrapper is a <div>');
  assert.strictEqual($component.hasClass('flexberry-textarea'), true, 'Component\'s wrapper has \' flexberry-textarea\' css-class');
  assert.strictEqual($component.hasClass('ui'), true, 'Component\'s wrapper has \'ui\' css-class');
  assert.strictEqual($component.hasClass('input'), true, 'Component\'s wrapper has \'input\' css-class');

  // Check wrapper's additional CSS-classes.
  let additioanlCssClasses = 'fluid mini huge';
  this.set('class', additioanlCssClasses);
  Ember.A(additioanlCssClasses.split(' ')).forEach((cssClassName, index) => {
    assert.strictEqual(
    $component.hasClass(cssClassName),
    true,
    'Component\'s wrapper has additional css class \'' + cssClassName + '\'');
  });

  // Clean up wrapper's additional CSS-classes.
  this.set('class', '');
  Ember.A(additioanlCssClasses.split(' ')).forEach((cssClassName, index) => {
    assert.strictEqual(
    $component.hasClass(cssClassName),
    false,
    'Component\'s wrapper hasn\'t additional css class \'' + cssClassName + '\'');
  });
});

test('readonly mode works properly', function(assert) {
  assert.expect(3);

  // Render component.
  this.render(hbs`{{flexberry-textarea
    class=class
    readonly=readonly
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('textarea');

  // Check that <textarea>'s readonly attribute doesn't exist yet.
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('readonly')),
    '',
    'Component\'s inner <textarea> hasn\'t readonly attribute');

  // Activate readonly mode & check that <textarea>'s readonly attribute exists now & has value equals to 'readonly'.
  this.set('readonly', true);
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('readonly')),
    'readonly',
    'Component\'s inner <textarea> has readonly attribute with value equals to \'readonly\'');

  // Check that <textarea>'s readonly attribute doesn't exist now.
  this.set('readonly', false);
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('readonly')),
    '',
    'Component\'s inner <textarea> hasn\'t readonly attribute');
});

test('readonly mode works properly with value', function(assert) {
  assert.expect(2);

  // Set <textarea>'s value' & render component.
  this.set('value', null);
  this.set('readonly', true);
  this.render(hbs`{{flexberry-textarea
    readonly=readonly
    value=value
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('textarea');

  $textareaInput.on('change', (e) => {
    if (this.get('readonly')) {
      e.stopPropagation();
      $textareaInput.val(null);
    }
  });

  let newValue = 'New value';
  $textareaInput.val(newValue);
  $textareaInput.change();

  // Check <textarea>'s value not chenged.
  assert.strictEqual(
    Ember.$.trim($textareaInput.val()),
    '',
    'Component\'s inner <textarea>\'s value not chenged');
  assert.strictEqual(
    this.get('value'),
    null,
    'Component\'s property binded to unchanged \'value\'');
});

test('it renders i18n-ed placeholder', function(assert) {
  assert.expect(2);

  // Render component.
  this.render(hbs`{{flexberry-textarea}}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('textarea');

  // Check <textarea>'s placeholder.
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    Ember.get(I18nRuLocale, 'components.flexberry-textarea.placeholder'),
    'Component\'s inner <textarea>\'s placeholder is equals to it\'s default value from i18n locales/ru/translations');

  // Change current locale to 'en' & check <textarea>'s placeholder again.
  this.set('i18n.locale', 'en');
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    Ember.get(I18nEnLocale, 'components.flexberry-textarea.placeholder'),
    'Component\'s inner <textarea>\'s placeholder is equals to it\'s value from i18n locales/en/translations');
});

test('it renders manually defined placeholder', function(assert) {
  assert.expect(2);

  // Set <textarea>'s placeholder' & render component.
  let placeholder = 'textarea is empty, please type some text';
  this.set('placeholder', placeholder);
  this.render(hbs`{{flexberry-textarea
    placeholder=placeholder
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('textarea');

  // Check <textarea>'s placeholder.
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    placeholder,
    'Component\'s inner <textarea>\'s placeholder is equals to manually defined value \'' + placeholder + '\'');

  // Change placeholder's value & check <textarea>'s placeholder again.
  placeholder = 'textarea has no value';
  this.set('placeholder', placeholder);
  assert.strictEqual(
    Ember.$.trim($textareaInput.attr('placeholder')),
    placeholder,
    'Component\'s inner <textarea>\'s placeholder is equals to manually updated value \'' + placeholder + '\'');
});

test('changes in inner <textarea> causes changes in property binded to \'value\'', function(assert) {
  assert.expect(4);

  // Set <textarea>'s value' & render component.
  this.set('value', null);
  this.render(hbs`{{flexberry-textarea
    value=value
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('textarea');

  // Check <textarea>'s value & binded value for initial emptyness.
  assert.strictEqual(
    Ember.$.trim($textareaInput.val()),
    '',
    'Component\'s inner <textarea>\'s value is equals to \'\'');
  assert.strictEqual(
    this.get('value'),
    null,
    'Component\'s property binded to \'value\' is equals to null');

  // Change <textarea>'s value (imitate situation when user typed something into component's <textarea>)
  // & check them again ('change' event is needed to force bindings work).
  let newValue = 'Some text typed into textboxes inner <textarea>';
  $textareaInput.val(newValue);
  $textareaInput.change();

  assert.strictEqual(
    Ember.$.trim($textareaInput.val()),
    newValue,
    'Component\'s inner <textarea>\'s value is equals to \'' + newValue + '\'');
  assert.strictEqual(
    this.get('value'),
    newValue,
    'Component\'s property binded to \'value\' is equals to \'' + newValue + '\'');
});

test('changes in property binded to \'value\' causes changes in inner <textarea>', function(assert) {
  assert.expect(4);

  // Set <textarea>'s value' & render component.
  this.set('value', null);
  this.render(hbs`{{flexberry-textarea
    value=value
  }}`);

  // Retrieve component.
  let $component = this.$().children();
  let $textareaInput = $component.children('textarea');

  // Check <textarea>'s value & binded value for initial emptyness.
  assert.strictEqual(
    Ember.$.trim($textareaInput.val()),
    '',
    'Component\'s inner <textarea>\'s value is equals to \'\'');
  assert.strictEqual(
    this.get('value'),
    null,
    'Component\'s property binded to \'value\' is equals to null');

  // Change property binded to 'value' & check them again.
  let newValue = 'Some text typed into textboxes inner <textarea>';
  this.set('value', newValue);

  assert.strictEqual(
    Ember.$.trim($textareaInput.val()),
    newValue,
    'Component\'s inner <textarea>\'s value is equals to \'' + newValue + '\'');
  assert.strictEqual(
    this.get('value'),
    newValue,
    'Component\'s property binded to \'value\' is equals to \'' + newValue + '\'');
});
<|endoftext|>


<commit_before>// the default function to determine whether to instrument a file.
// this function assumes that inside an instrumented module, relative
// file paths will be used that are outside the REQUIRE_PATH, and
// that those are precisely the interesting files to instrument.
// thus:
//   require('./config.js'); /* instrument me! */
//   require('request'); /* don't instrument me */
//
// Because blanket is built on require.extensions, and because require
// extensions does not provide raw require arguments to the extender,
// we have to do unnatural things to get this natural behavior.

var path = require('path');
// XXX: a better way to determine node module paths?  Is this windows safe?
var myPaths = require.main.paths.slice(0, require.main.paths.indexOf(path.join('/', 'node_modules')) + 1);

module.exports = function(filename) {
  var inc = true;
  myPaths.forEach(function(p) {
    if (filename.indexOf(p) === 0) inc = false;
  });
  console.log(myPaths);
  return inc;
};
<commit_msg>remove console noise<commit_after>// the default function to determine whether to instrument a file.
// this function assumes that inside an instrumented module, relative
// file paths will be used that are outside the REQUIRE_PATH, and
// that those are precisely the interesting files to instrument.
// thus:
//   require('./config.js'); /* instrument me! */
//   require('request'); /* don't instrument me */
//
// Because blanket is built on require.extensions, and because require
// extensions does not provide raw require arguments to the extender,
// we have to do unnatural things to get this natural behavior.

var path = require('path');
// XXX: a better way to determine node module paths?  Is this windows safe?
var myPaths = require.main.paths.slice(0, require.main.paths.indexOf(path.join('/', 'node_modules')) + 1);

module.exports = function(filename) {
  var inc = true;
  myPaths.forEach(function(p) {
    if (filename.indexOf(p) === 0) inc = false;
  });
  return inc;
};
<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, click, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import emberVersionGTE from 'ember-test-helpers/has-ember-version';
import $ from 'jquery';

module('Integration | Component | x toggle', function(hooks) {
  setupRenderingTest(hooks);

  test('it renders', async function(assert) {
    await render(hbs`{{x-toggle}}`);

    assert.dom('div.x-toggle-btn').exists();
  });

  test('changing disabled property disables component', async function(assert) {
    this.setProperties({
      value: false,
      disabled: true
    });

    await render(hbs`{{x-toggle
      value=this.value
      disabled=this.disabled
    }}`);

    assert.dom('input.x-toggle').isDisabled();
    assert.equal(this.value, false);

    await click('div.x-toggle-btn');
    assert.dom('input.x-toggle').isDisabled();
    assert.equal(this.value, false);
  });

  test('clicking component triggers onToggle action', async function(assert) {
    this.setProperties({
      myValue: false,
      onToggle(val) {
        this.set('myValue', val)
      }
    })

    await render(hbs`{{x-toggle
      value=this.myValue
      onToggle=(action this.onToggle)
    }}`);

    await click('div.x-toggle-btn');
    assert.equal(this.myValue, true, 'new value set');
  });

  test('clicking component labels triggers onToggle action', async function(assert) {
    let onTrue = true;

    this.setProperties({
      value: false,
      onToggle(val) {
        assert.equal(val, onTrue, 'new value set');
        onTrue = false;
        this.set('value', val);
      }
    });

    await render(hbs`{{x-toggle
      value=this.value
      showLabels=true
      onToggle=(action this.onToggle)
    }}`);

    await click('.on-label');
    assert.equal(this.value, true, 'clicking on label toggles value true');

    await click('.off-label');
    assert.equal(this.value, false, 'clicking off label toggles value to false');

    await click('.off-label');
    assert.equal(this.value, false, 'clicking off label again, value stays false');
  });

  test('clicking disabled component labels does not trigger onToggle action', async function(assert) {
    this.setProperties({
      value: false,
      disabled: true,
      onToggle(val) {
        this.set('value', val);
      }
    });

    await render(hbs`{{x-toggle
      value=this.value
      showLabels=true
      disabled=disabled
      onToggle=(action this.onToggle)
    }}`);

    await click('.on-label');
    assert.equal(this.value, false, 'clicking on label does not change the value');

    await click('.off-label');
    assert.equal(this.value, false, 'clicking off label does not change the value');
  });

  if (emberVersionGTE(2, 0)) {
    test('clicking component works with bespoke values and mut helper', async function(assert) {
      this.set('value', false);

      await render(hbs`{{x-toggle
        offLabel='Foo'
        onLabel='Bar'
        showLabels=true
        value=this.value
        onToggle=(action (mut this.value))
      }}`);

      assert.equal(this.value, false);
      assert.equal(find('.off-label').textContent.trim(), 'Foo', '"off" property set on toggle');
      assert.equal(find('.on-label').textContent.trim(), 'Bar', '"on" property set on toggle');

      await click('div.x-toggle-btn');
      assert.equal(this.value, true, 'click toggles value');
    });

    test('clicking component works with boolean true/false', async function(assert) {
      this.set('value', false);

      await render(hbs`{{x-toggle
        onLabel=true
        offLabel=false
        value=this.value
        onToggle=(action (mut this.value))
      }}`);

      assert.equal(this.value, false);

      await click('div.x-toggle-btn');
      assert.equal(this.value, true);
    });

    test('clicking component works with boolean true/false and discrete labels', async function(assert) {
      this.set('value', false);

      await render(hbs`{{x-toggle
        onLabel='Yes'
        offLabel='No'
        value=this.value
        onToggle=(action (mut this.value))
      }}`);

      assert.equal(this.value, false);

      await click('div.x-toggle-btn');
      assert.equal(this.value, true);
    });

    test('value can be set by changing the value property', async function(assert) {
      this.setProperties({
        value: false,
        show: false
      });

      await render(hbs`
        {{x-toggle
          value=this.value
          onToggle=(action (mut this.value))
        }}
      `);

      this.set('value', true);
      assert.dom('.x-toggle-container').hasClass('x-toggle-container-checked');

      this.set('value', false);
      assert.dom('.x-toggle-container').doesNotHaveClass('x-toggle-container-checked');
    });

    test('can render in block form', async function(assert) {
      this.setProperties({
        value: false,
        show: false
      });

      await render(hbs`
        {{#x-toggle
          showLabels=true
          value=this.value
          onToggle=(action (mut this.value))
        as |toggle|}}
          {{toggle.offLabel}}
          {{toggle.onLabel}}
          {{toggle.switch}}
        {{/x-toggle}}
      `);

      this.set('value', true);
      assert.dom('.x-toggle-container').hasClass('x-toggle-container-checked');

      this.set('value', false);
      assert.dom('.x-toggle-container').doesNotHaveClass('x-toggle-container-checked');
    });

    test('onToggle not called unless value changes', async function(assert) {
      this.setProperties({
        timesCalled: 0,
        value: false,
        show: false,
        onToggle(value) {
          const timesCalled = this.get('timesCalled') + 1;
          this.set('timesCalled', timesCalled);
          this.set('value', value);
        }
      });

      await render(hbs`
        {{#x-toggle
          showLabels=true
          value=this.value
          onToggle=(action this.onToggle)
        as |toggle|}}
          {{toggle.offLabel}}
          {{toggle.onLabel}}
          {{toggle.switch}}
        {{/x-toggle}}
      `);

      await click('.on-label');
      assert.equal(this.value, true, 'clicking on label toggles value true');
      assert.equal(this.timesCalled, 1, 'should call onToggle once');

      await click('.on-label');
      assert.equal(this.value, true, 'clicking on label again stays true');
      assert.equal(this.timesCalled, 1, 'should not call onToggle again if value does not change');
    });

    test('swipe gestures', async function(assert) {
      this.set('value', false);

      await render(hbs`{{x-toggle
        value=this.value
        onToggle=(action (mut this.value))
      }}`);

      const $toggle = $('.x-toggle-container');

      $toggle.trigger('panright');
      assert.equal(this.value, true, 'panning right should enable');

      $toggle.trigger('panleft');
      assert.equal(this.value, false, 'panning left should disable');
    });

    test('swipe gesture while disabled', async function(assert) {
      this.set('value', false);

      await render(hbs`{{x-toggle
        disabled=true
        value=this.value
        onToggle=(action (mut this.value))
      }}`);

      const $toggle = $('.x-toggle-container');

      $toggle.trigger('panright');
      assert.equal(this.value, false, 'panning right should not enable');
    });

    test('clicking should not enable when the action does not update the value', async function(assert) {
      this.setProperties({
        value: false,
        toggleAction() {}
      });

      await render(hbs`
        {{x-toggle
          value=this.value
          onToggle=(action this.toggleAction)
        }}
      `);
      await click('div.x-toggle-btn');

      assert.equal(this.value, false);
      assert.dom('.x-toggle').isNotChecked();
    });

    test('panning should not enable when the action does not update the value', async function(assert) {
      this.setProperties({
        value: false,
        toggleAction() {}
      });

      await render(hbs`
        {{x-toggle
          value=this.value
          onToggle=(action this.toggleAction)
        }}
      `);

      const $toggle = $('.x-toggle-container');

      $toggle.trigger('panright');

      assert.equal(this.value, false);
      assert.dom('.x-toggle').isNotChecked();
    });
  }
});
<commit_msg>tests: use AB component syntax<commit_after>import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, click, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import emberVersionGTE from 'ember-test-helpers/has-ember-version';
import $ from 'jquery';

module('Integration | Component | x toggle', function(hooks) {
  setupRenderingTest(hooks);

  test('it renders', async function(assert) {
    await render(hbs`
      <XToggle/>
    `);

    assert.dom('div.x-toggle-btn').exists();
  });

  test('changing disabled property disables component', async function(assert) {
    this.setProperties({
      value: false,
      disabled: true
    });

    await render(hbs`
      <XToggle
        @value={{this.value}}
        @disabled={{this.disabled}}
      />
    `);

    assert.dom('input.x-toggle').isDisabled();
    assert.equal(this.value, false);

    await click('div.x-toggle-btn');
    assert.dom('input.x-toggle').isDisabled();
    assert.equal(this.value, false);
  });

  test('clicking component triggers onToggle action', async function(assert) {
    this.setProperties({
      myValue: false,
      onToggle(val) {
        this.set('myValue', val)
      }
    })

    await render(hbs`
      <XToggle
        @value={{this.myValue}}
        @onToggle={{action this.onToggle}}
      />
    `);

    await click('div.x-toggle-btn');
    assert.equal(this.myValue, true, 'new value set');
  });

  test('clicking component labels triggers onToggle action', async function(assert) {
    let onTrue = true;

    this.setProperties({
      value: false,
      onToggle(val) {
        assert.equal(val, onTrue, 'new value set');
        onTrue = false;
        this.set('value', val);
      }
    });

    await render(hbs`
      <XToggle
        @value={{this.value}}
        @showLabels={{true}}
        @onToggle={{action this.onToggle}}
      />
    `);

    await click('.on-label');
    assert.equal(this.value, true, 'clicking on label toggles value true');

    await click('.off-label');
    assert.equal(this.value, false, 'clicking off label toggles value to false');

    await click('.off-label');
    assert.equal(this.value, false, 'clicking off label again, value stays false');
  });

  test('clicking disabled component labels does not trigger onToggle action', async function(assert) {
    this.setProperties({
      value: false,
      disabled: true,
      onToggle(val) {
        this.set('value', val);
      }
    });

    await render(hbs`
      <XToggle
        @showLabels={{true}}
        @disabled={{this.disabled}}
        @value={{this.value}}
        @onToggle={{action this.onToggle}}
      />
    `);

    await click('.on-label');
    assert.equal(this.value, false, 'clicking on label does not change the value');

    await click('.off-label');
    assert.equal(this.value, false, 'clicking off label does not change the value');
  });

  if (emberVersionGTE(2, 0)) {
    test('clicking component works with bespoke values and mut helper', async function(assert) {
      this.set('value', false);

      await render(hbs`
        <XToggle
          @offLabel='Foo'
          @onLabel='Bar'
          @showLabels={{true}}
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        />
      `);

      assert.equal(this.value, false);
      assert.equal(find('.off-label').textContent.trim(), 'Foo', '"off" property set on toggle');
      assert.equal(find('.on-label').textContent.trim(), 'Bar', '"on" property set on toggle');

      await click('div.x-toggle-btn');
      assert.equal(this.value, true, 'click toggles value');
    });

    test('clicking component works with boolean true/false', async function(assert) {
      this.set('value', false);

      await render(hbs`
        <XToggle
          @onLabel={{true}}
          @offLabel={{false}}
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        />
      `);

      assert.equal(this.value, false);

      await click('div.x-toggle-btn');
      assert.equal(this.value, true);
    });

    test('clicking component works with boolean true/false and discrete labels', async function(assert) {
      this.set('value', false);

      await render(hbs`
        <XToggle
          @onLabel='Yes'
          @offLabel='No'
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        />
      `);

      assert.equal(this.value, false);

      await click('div.x-toggle-btn');
      assert.equal(this.value, true);
    });

    test('value can be set by changing the value property', async function(assert) {
      this.setProperties({
        value: false,
        show: false
      });

      await render(hbs`
        <XToggle
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        />
      `);

      this.set('value', true);
      assert.dom('.x-toggle-container').hasClass('x-toggle-container-checked');

      this.set('value', false);
      assert.dom('.x-toggle-container').doesNotHaveClass('x-toggle-container-checked');
    });

    test('can render in block form', async function(assert) {
      this.setProperties({
        value: false,
        show: false
      });

      await render(hbs`
        <XToggle
          @showLabels={{true}}
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        as |toggle|>
          <toggle.offLabel/>
          <toggle.onLabel/>
          <toggle.switch/>
        </XToggle>
      `);

      this.set('value', true);
      assert.dom('.x-toggle-container').hasClass('x-toggle-container-checked');

      this.set('value', false);
      assert.dom('.x-toggle-container').doesNotHaveClass('x-toggle-container-checked');
    });

    test('onToggle not called unless value changes', async function(assert) {
      this.setProperties({
        timesCalled: 0,
        value: false,
        show: false,
        onToggle(value) {
          const timesCalled = this.get('timesCalled') + 1;
          this.set('timesCalled', timesCalled);
          this.set('value', value);
        }
      });

      await render(hbs`
        <XToggle
          @showLabels={{true}}
          @value={{this.value}}
          @onToggle={{action this.onToggle}}
        as |toggle|>
          <toggle.offLabel/>
          <toggle.onLabel/>
          <toggle.switch/>
        </XToggle>
      `);

      await click('.on-label');
      assert.equal(this.value, true, 'clicking on label toggles value true');
      assert.equal(this.timesCalled, 1, 'should call onToggle once');

      await click('.on-label');
      assert.equal(this.value, true, 'clicking on label again stays true');
      assert.equal(this.timesCalled, 1, 'should not call onToggle again if value does not change');
    });

    test('swipe gestures', async function(assert) {
      this.set('value', false);

      await render(hbs`
        <XToggle
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        />
      `);

      const $toggle = $('.x-toggle-container');

      $toggle.trigger('panright');
      assert.equal(this.value, true, 'panning right should enable');

      $toggle.trigger('panleft');
      assert.equal(this.value, false, 'panning left should disable');
    });

    test('swipe gesture while disabled', async function(assert) {
      this.set('value', false);

      await render(hbs`
        <XToggle
          @disabled={{true}}
          @value={{this.value}}
          @onToggle={{action (mut this.value)}}
        />
      `);

      const $toggle = $('.x-toggle-container');

      $toggle.trigger('panright');
      assert.equal(this.value, false, 'panning right should not enable');
    });

    test('clicking should not enable when the action does not update the value', async function(assert) {
      this.setProperties({
        value: false,
        toggleAction() {}
      });

      await render(hbs`
        <XToggle
          @value={{this.value}}
          @onToggle={{action this.toggleAction}}
        />
      `);
      await click('div.x-toggle-btn');

      assert.equal(this.value, false);
      assert.dom('.x-toggle').isNotChecked();
    });

    test('panning should not enable when the action does not update the value', async function(assert) {
      this.setProperties({
        value: false,
        toggleAction() {}
      });

      await render(hbs`
        <XToggle
          @value={{this.value}}
          @onToggle={{action this.toggleAction}}
        />
      `);

      const $toggle = $('.x-toggle-container');

      $toggle.trigger('panright');

      assert.equal(this.value, false);
      assert.dom('.x-toggle').isNotChecked();
    });
  }
});
<|endoftext|>


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

const
    Demangler = require("./demangler").Demangler;

const LabelMetadata = [
    {ident: 'C1Ev', description: 'complete object constructor'},
    {ident: 'C2Ev', description: 'base object constructor'},
    {ident: 'C3Ev', description: 'complete object allocating constructor'},
    {ident: 'D0Ev', description: 'deleting destructor'},
    {ident: 'D1Ev', description: 'complete object destructor'},
    {ident: 'D2Ev', description: 'base object destructor'}
];

class DemanglerCPP extends Demangler {
    getMetadata(symbol) {
        let metadata = [];

        for (let i = 0; i < LabelMetadata.length; ++i) {
            if (symbol.endsWith(LabelMetadata[i].ident)) {
                metadata.push(LabelMetadata[i]);
            }
        }

        return metadata;
    }
}

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

const
    Demangler = require("./demangler").Demangler;

const LabelMetadata = [
    {ident: 'C1Ev', description: 'complete object constructor'},
    {ident: 'C2Ev', description: 'base object constructor'},
    {ident: 'C3Ev', description: 'complete object allocating constructor'},
    {ident: 'D0Ev', description: 'deleting destructor'},
    {ident: 'D1Ev', description: 'complete object destructor'},
    {ident: 'D2Ev', description: 'base object destructor'}
];

class DemanglerCPP extends Demangler {
    getMetadata(symbol) {
        return LabelMetadata.filter(metadata => symbol.endsWith(metadata.ident));
    }
}

exports.Demangler = DemanglerCPP;
<|endoftext|>


<commit_before>module.exports = deployTargets;
deployTargets.create = createDeployTarget;
deployTargets.update = updateDeployTarget;
deployTargets.read = readDeployTarget;
deployTargets.list = listDeployTargets;
deployTargets['delete'] = deleteDeployTarget;
deployTargets.listforapp = listAvailableDeployTargets;
deployTargets.getapptarget = getDeployTargetForApp;
deployTargets.setapptarget = setDeployTargetForApp;

deployTargets.usage = "\nfhc deploy-target create name=<the name of the deploy target> platform=<feedhenry/cloudfoundry/stackato> env=<dev/live/all> conf_url=<deploy url> conf_username=<user for the deploy> conf_password=<user password for the deploy> ..."
                    + "\nfhc deploy-target update id=<id of the deploy target> name=<the name of the deploy target> platform=<feedhenry/cloudfoundry/stackato> env=<dev/live/all> conf_url=<deploy url> conf_username=<user for the deploy> conf_password=<user password for the deploy> ... "
                    + "\nfhc deploy-target read <id of the deployment target>"
                    + "\nfhc deploy-target list"
                    + "\nfhc deploy-target delete <id of the deployment target>"
                    + "\nfhc deploy-target listforapp <appid> <dev/live> [<platform>]"
                    + "\nfhc deploy-target getapptarget <appid> <dev/live>"
                    + "\nfhc deploy-target setapptarget <appid> <id of the deploy target> <dev/live>";

var log = require("./utils/log");
var fhc = require("./fhc");
var fhreq = require("./utils/request");
var common = require("./common");
var util = require('util');
var async = require('async');
var path = require('path');

function deployTargets(args, cb){
  if(args.length == 0){
    return listDeployTargets(cb);
  }
  var action = args[0];
  var params;
  if(args.length > 1){
    params = args.slice(1);
  }
  if(action === "list"){
    return listDeployTargets(cb);
  } else if(action === "create"){
    if(args.length < 7) return cb("Invalid arguments for 'create':" + deployTargets.usage);
    return createDeployTarget(params, cb);
  } else if(action === "update"){
    if(args.length < 2) return cb("Invalid arguments for 'update':" + deployTargets.usage);
    return updateDeployTarget(params, cb);
  } else if(action === "read"){
    if(args.length < 2) return cb("Invalid arguments for 'read':" + deployTargets.usage);
    return readDeployTarget(params, cb);
  } else if(action === "delete"){
    if(args.length < 2) return cb("Invalid arguments for 'delete':" + deployTargets.usage);
    return deleteDeployTarget(params, cb);
  } else if(action === "listforapp"){
    if(args.length < 2) return cb("Invalid arguments for 'listforapp':" + deployTargets.usage);
    return listAvailableDeployTargets(params, cb);
  } else if(action === "getapptarget"){
    if(args.length < 3) return cb("Invalid arguments for 'getapptarget':" + deployTargets.usage);
    return getDeployTargetForApp(params, cb);
  } else if(action === "setapptarget"){
    if(args.length < 3) return cb("Invalid arguments for 'setapptarget':" + deployTargets.usage);
    return setDeployTargetForApp(params, cb);
  } else if(args.length == 1){
    return readDeployTarget(args, cb);
  } else {
    return cb(deployTargets.usage);
  }
}

function listDeployTargets(cb){
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/listeditable", {}, "Error listing deploy targets: ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  });
}

function parseParams(args){
  var paramNameMap = {'name': 'policyId', 'platform':'target', 'env':'env', 'id':'guid'};
  var data = {};
  var conf = {};
  args.forEach(function(arg){
    var pair = arg.split("=");
    var key = pair[0];
    var val = pair[1];
    if(key.indexOf('conf_') > -1){
      var confName = key.replace("conf_", "");
      conf[confName] = val;
    } else {
      if(paramNameMap[key]){
        data[paramNameMap[key]] = val;
      }
    }
  });
  data['configurations'] = conf;
  var envval = data['env'];
  if("all" == envval){
    data['env'] = "dev,live";
  }
  return data;
}

function createDeployTarget(args, cb){
  var data = parseParams(args);
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/create", data, "Error creating deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function updateDeployTarget(args, cb){
  var data = parseParams(args);
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/update", data, "Error updating deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function readDeployTarget(args, cb){
  var guid = args[0];
  var data = {'guid': guid};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/read", data, "Error reading deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function deleteDeployTarget(args, cb){
  var guid = args[0];
  var data = {'guid': guid};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/delete", data, "Error deleting deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function listAvailableDeployTargets(args, cb){
  var appid = fhc.appId(args[0]);
  var env = args[1];
  var platform = undefined;
  if(args.length == 3){
    platform = args[2];
  }

  var data = {"app":appid, "target": platform, "env":env};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/list", data, "Error listing available deploy targets for app : ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  })
}

function getDeployTargetForApp(args, cb){
  var appId = fhc.appId(args[0]);
  var env = args[1];
  var data = {"app": appId, "env": env};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/getpolicy", data, "Error getting deploy target for app : ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  })
}

function setDeployTargetForApp(args, cb){
  var appId = fhc.appId(args[0]);
  var guid = args[1];
  var env = args[2];
  var data = {"app": appId, "policyGuid":guid, "env": env};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/setpolicy", data, "Error setting deploy target for app : ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  })
}

<commit_msg>add infrastructure support when creating deployment targets<commit_after>module.exports = deployTargets;
deployTargets.create = createDeployTarget;
deployTargets.update = updateDeployTarget;
deployTargets.read = readDeployTarget;
deployTargets.list = listDeployTargets;
deployTargets['delete'] = deleteDeployTarget;
deployTargets.listforapp = listAvailableDeployTargets;
deployTargets.getapptarget = getDeployTargetForApp;
deployTargets.setapptarget = setDeployTargetForApp;

deployTargets.usage = "\nfhc deploy-target create name=<the name of the deploy target> platform=<feedhenry/cloudfoundry/stackato/appfog/ironfoundry> env=<dev/live/all> conf_url=<deploy url> conf_username=<user for the deploy> conf_password=<user password for the deploy> [conf_infrastructure=<infrastructure providers>] ..."
                    + "\nfhc deploy-target update id=<id of the deploy target> name=<the name of the deploy target> platform=<feedhenry/cloudfoundry/stackato> env=<dev/live/all> conf_url=<deploy url> conf_username=<user for the deploy> conf_password=<user password for the deploy> ... "
                    + "\nfhc deploy-target read <id of the deployment target>"
                    + "\nfhc deploy-target list"
                    + "\nfhc deploy-target delete <id of the deployment target>"
                    + "\nfhc deploy-target listforapp <appid> <dev/live> [<platform>]"
                    + "\nfhc deploy-target getapptarget <appid> <dev/live>"
                    + "\nfhc deploy-target setapptarget <appid> <id of the deploy target> <dev/live>"
                    + "\n[conf_infrastructure] parameter is required if platform is appfog and possible values are: aws, eu-aws, ap-aws, rs, hp";

var log = require("./utils/log");
var fhc = require("./fhc");
var fhreq = require("./utils/request");
var common = require("./common");
var util = require('util');
var async = require('async');
var path = require('path');

function deployTargets(args, cb){
  if(args.length == 0){
    return listDeployTargets(cb);
  }
  var action = args[0];
  var params;
  if(args.length > 1){
    params = args.slice(1);
  }
  if(action === "list"){
    return listDeployTargets(cb);
  } else if(action === "create"){
    if(args.length < 7) return cb("Invalid arguments for 'create':" + deployTargets.usage);
    return createDeployTarget(params, cb);
  } else if(action === "update"){
    if(args.length < 2) return cb("Invalid arguments for 'update':" + deployTargets.usage);
    return updateDeployTarget(params, cb);
  } else if(action === "read"){
    if(args.length < 2) return cb("Invalid arguments for 'read':" + deployTargets.usage);
    return readDeployTarget(params, cb);
  } else if(action === "delete"){
    if(args.length < 2) return cb("Invalid arguments for 'delete':" + deployTargets.usage);
    return deleteDeployTarget(params, cb);
  } else if(action === "listforapp"){
    if(args.length < 2) return cb("Invalid arguments for 'listforapp':" + deployTargets.usage);
    return listAvailableDeployTargets(params, cb);
  } else if(action === "getapptarget"){
    if(args.length < 3) return cb("Invalid arguments for 'getapptarget':" + deployTargets.usage);
    return getDeployTargetForApp(params, cb);
  } else if(action === "setapptarget"){
    if(args.length < 3) return cb("Invalid arguments for 'setapptarget':" + deployTargets.usage);
    return setDeployTargetForApp(params, cb);
  } else if(args.length == 1){
    return readDeployTarget(args, cb);
  } else {
    return cb(deployTargets.usage);
  }
}

function listDeployTargets(cb){
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/listeditable", {}, "Error listing deploy targets: ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  });
}

function parseParams(args){
  var paramNameMap = {'name': 'policyId', 'platform':'target', 'env':'env', 'id':'guid'};
  var validInfrastructures = {'aws':'aws.af.cm', 'eu-aws':'eu01.aws.af.cm', 'ap-aws':'ap01.aws.af.cm', 'rs':'rs.af.cm', 'hp':'hp.af.cm'};
  var data = {};
  var conf = {};
  args.forEach(function(arg){
    var pair = arg.split("=");
    var key = pair[0];
    var val = pair[1];
    if(key.indexOf('conf_') > -1){
      var confName = key.replace("conf_", "");
      if(confName === "infrastructure"){
        if(validInfrastructures[val]){
          conf[confName] = validInfrastructures[val];
        } else {
          throw new Error("Invalid infrastructure value : " + val);
        }
      } else {
        conf[confName] = val;
      }
    } else {
      if(paramNameMap[key]){
        data[paramNameMap[key]] = val;
      }
    }
  });
  data['configurations'] = conf;
  var envval = data['env'];
  if("all" == envval){
    data['env'] = "dev,live";
  }
  return data;
}

function createDeployTarget(args, cb){
  var data = parseParams(args);
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/create", data, "Error creating deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function updateDeployTarget(args, cb){
  var data = parseParams(args);
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/update", data, "Error updating deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function readDeployTarget(args, cb){
  var guid = args[0];
  var data = {'guid': guid};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/read", data, "Error reading deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function deleteDeployTarget(args, cb){
  var guid = args[0];
  var data = {'guid': guid};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/delete", data, "Error deleting deploy target: ", function(err, target){
    if(err) return cb(err);
    return cb(undefined, target);
  })
}

function listAvailableDeployTargets(args, cb){
  var appid = fhc.appId(args[0]);
  var env = args[1];
  var platform = undefined;
  if(args.length == 3){
    platform = args[2];
  }

  var data = {"app":appid, "target": platform, "env":env};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/list", data, "Error listing available deploy targets for app : ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  })
}

function getDeployTargetForApp(args, cb){
  var appId = fhc.appId(args[0]);
  var env = args[1];
  var data = {"app": appId, "env": env};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/getpolicy", data, "Error getting deploy target for app : ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  })
}

function setDeployTargetForApp(args, cb){
  var appId = fhc.appId(args[0]);
  var guid = args[1];
  var env = args[2];
  var data = {"app": appId, "policyGuid":guid, "env": env};
  common.doApiCall(fhreq.getFeedHenryUrl(), "/box/srv/1.1/cm/deploy/policy/setpolicy", data, "Error setting deploy target for app : ", function(err, targets){
    if(err) return cb(err);
    return cb(undefined, targets);
  })
}

<|endoftext|>


<commit_before>var jsface = require("jsface"),
	color  = require("cli-color");

/**
 * @name Logger
 * @namespace
 * @classdef Logger class, used for all logging inside newman
 */
var Logger = jsface.Class({
	$singleton: true,
	/**
	 * Logger Method
	 * @param  {String} log Logs success.
	 * @memberOf Logger
	 */
	success: function(log) {
		process.stdout.write(color.green(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs errors.
	 * @memberOf Logger
	 */
	error: function(log) {
		process.stdout.write(color.red(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs notice messages.
	 * @memberOf Logger
	 */
	notice: function(log) {
		process.stdout.write(color.yellow(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs warning messages.
	 * @memberOf Logger
	 */
	warn: function(log) {
		process.stdout.write(color.yellow(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs normal messages.
	 * @memberOf Logger
	 */
	normal: function(log) {
		process.stdout.write(color.cyan(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs light grey messages.
	 * @memberOf Logger
	 */
	light: function(log) {
		process.stdout.write(color.underline.xterm(245)(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs orange notes.
	 * @memberOf Logger
	 */
	note: function(log) {
		process.stdout.write(color.xterm(202)(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a test case success
	 * @memberOf Logger
	 */
	testCaseSuccess: function(log) {
		process.stdout.write("    " + color.green("✔ " + log) + "\n");
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a test case error
	 * @memberOf Logger
	 */
	testCaseError: function(log) {
		process.stdout.write("    " + color.red("✗ " + log) + "\n");
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a node error in red
	 * @memberOf Logger
	 */
	throwError: function(msg) {
		var err = new Error(msg);
		process.stdout.write(color.red(err.message));
		throw err;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a node exception error in red
	 * @memberOf Logger
	 */
	exceptionError: function(err) {
		process.stdout.write("    " + color.bold.red("EXCEPTION: " + err) + "\n");
	}
});

module.exports = Logger;
<commit_msg>Made the logger DRYer<commit_after>var jsface = require("jsface"),
	color  = require("cli-color");

/**
 * @name Logger
 * @namespace
 * @classdef Logger class, used for all logging inside newman
 */
var Logger = jsface.Class({
	$singleton: true,
	/**
	 * Logger Method
	 * @param  {String} log Logs success.
	 * @memberOf Logger
	 */
	success: function(log) {
		process.stdout.write(color.green(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs errors.
	 * @memberOf Logger
	 */
	error: function(log) {
		process.stdout.write(color.red(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs notice messages.
	 * @memberOf Logger
	 */
	notice: function(log) {
		process.stdout.write(color.yellow(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs warning messages.
	 * @memberOf Logger
	 */
	warn: function(log) {
		process.stdout.write(color.yellow(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs normal messages.
	 * @memberOf Logger
	 */
	normal: function(log) {
		process.stdout.write(color.cyan(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs light grey messages.
	 * @memberOf Logger
	 */
	light: function(log) {
		process.stdout.write(color.underline.xterm(245)(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs orange notes.
	 * @memberOf Logger
	 */
	note: function(log) {
		process.stdout.write(color.xterm(202)(log));
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a test case success
	 * @memberOf Logger
	 */
	testCaseSuccess: function(log) {
		this.success("    " + color.green("✔ " + log) + "\n");
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a test case error
	 * @memberOf Logger
	 */
	testCaseError: function(log) {
		process.stdout.write("    " + color.red("✗ " + log) + "\n");
		return this;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a node error in red
	 * @memberOf Logger
	 */
	throwError: function(msg) {
		var err = new Error(msg);
		this.error(color.red(err.message));
		throw err;
	},
	/**
	 * Logger Method
	 * @param  {String} log Logs a node exception error in red
	 * @memberOf Logger
	 */
	exceptionError: function(err) {
		this.error("    " + color.bold.red("EXCEPTION - " + err) + "\n");
	}
});

module.exports = Logger;
<|endoftext|>


<commit_before>/**
 * Created by nathandunn on 6/10/17.
 */
import {AnnotationCommand, request, SelectionState} from "substance";

class MarkupApp {

    constructor() {
        this.words = [];
    }

    render(data, callback) {

        // let words = ['organism','unc-5','elegans','epidermal'];
        // alert('rendering with dat: ' + JSON.stringify(data));
        // alert('rendering with words: ' + data.length);

        let cmd = new ToggleStrongCommand();
        let documentSession = window.app.state.documentSession;
        let selectionState = documentSession.getSelectionState();
        let nodes = window.doc.getNodes();

        document.getElementById('message').innerHTML = "Running markup...";
        // n.startsWith('article') // article junk
        // || n.startsWith('ext-link') // what we are tring to create
        // n.startsWith('body') // this is just the intro
        // || n.startsWith('heading') // this is the heading for each paragraph
        let numErrors = 0;
        let totalWordsFound = 0;
        let wordsFound = [];
        let totalWordHits = 0;

        for (let n in nodes) {
            // console.log(n);
            if (n.startsWith('paragraph')
            ) {
                let p = window.doc.get(n);
                // just find the first one
                for (let w in data) {
                    let wordHits = 0;
                    let word = data[w];
                    let found = 0;
                    var reWord = word.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
                    var re = new RegExp("\\W" + reWord + "\\W", "g");
                    var hits;
                    while (hits = re.exec(p.content)) {

                        let sel = documentSession.createSelection({
                            type: 'property',
                            path: [p.id, 'content'],
                            startOffset: hits.index + 1,
                            endOffset: hits.index + 1 + word.length
                        });
                        selectionState.setSelection(sel);
                        let cmdState = cmd.getCommandState({
                            selectionState: selectionState,
                            documentSession: documentSession
                        });
                        if (cmdState.mode == "create") {
                            cmd.execute({
                                commandState: {
                                    mode: 'create'
                                },
                                documentSession: documentSession,
                                selectionState: documentSession.getSelectionState()
                            });
                            console.log('Found ' + word);

                        } else {
                            console.log("Annotated words: " + p.content.substring(selectionState.getAnnotationsForType(cmd.getAnnotationType())[0].startOffset, selectionState.getAnnotationsForType(cmd.getAnnotationType())[0].endOffset));
                            if (cmdState.mode == "delete") {
                                console.log('Error trying to annotate: ' + word + ' because it is already linked.');
                            } else if (cmdState.mode == "expand") {
                                console.log('Error trying to annotate: ' + word + ' because part of the word is already linked.');
                            } else if (cmdState.mode == "truncate") {
                                console.log('Error trying to annotate: ' + word + ' because it is part of the linked word.');
                            }
                            ++numErrors;
                        }

                        //found = p.content.indexOf(word,found+1);
                        ++wordHits;
                    }
                    if (wordHits > 0) {
                        ++totalWordsFound;
                        totalWordHits += wordHits;
                        wordsFound[word] = wordHits;
                        document.getElementById('message').innerHTML = "Searching: found " + totalWordsFound + " words, hits: " + totalWordHits;
                    }
                }
            }
        }
        let finalMessage = "Total words " + totalWordsFound + " Total links: " + totalWordHits;
        let detailButton = "<input style='display: inline;' type='button' onclick='var e = document.getElementById(\"hitDetails\"); e.style.display = (e.style.display == \"block\") ? \"none\" : \"block\";'\ value='Toggle details'>";
        // finalMessage += "
";
        finalMessage += detailButton ;
        finalMessage += "
";
        finalMessage += "
";
        for (let word in wordsFound) {
            finalMessage += "
" + word ;
            if(wordsFound[word]>1){
                finalMessage += " (" + wordsFound[word] + ")";
            }
            finalMessage += ";
 ";
        }
        finalMessage += "
";

        // finalMessage += "
";
        document.getElementById('message').innerHTML = finalMessage;
        console.log('total found: ' + totalWordsFound);
        console.log('total errors: ' + numErrors);

        if (callback) callback();
    }

    getWords(callback) {
        let serverURL = window.location.protocol + '//' + window.location.hostname + ':8080/keyWordSet/sampleKeyWordSet';
        console.log('server URL: ' + serverURL);
        request('GET', serverURL, null, function (err, data) {
            if (err) {
                console.error(err);
                this.setState({
                    error: new Error('Loading failed')
                });
                return
            }
            if (data) {
                this.words = [];
                for (let d in data) {
                    this.words.push(data[d].value);
                }
                console.log('finished processing with words: ' + this.words.length);
                // this.render(this.words, cb);
                if (callback) callback(this.words);

                return this.words;
            }
        });
    }

}

class ToggleStrongCommand extends AnnotationCommand {

    // type = 'bold';
    // tagName = 'bold';

    constructor() {
        // super({name: 'bold', nodeType: 'bold'})
        super({name: 'markup', nodeType: 'ext-link'})
    }
}

// ToggleStrongCommand.define({
//     attributes: { type: 'object', default: {} }
// });

// export default ToggleStrongCommand

export default MarkupApp
<commit_msg>added a toggle button<commit_after>/**
 * Created by nathandunn on 6/10/17.
 */
import {AnnotationCommand, request, SelectionState} from "substance";

class MarkupApp {

    constructor() {
        this.words = [];
    }

    render(data, callback) {

        // let words = ['organism','unc-5','elegans','epidermal'];
        // alert('rendering with dat: ' + JSON.stringify(data));
        // alert('rendering with words: ' + data.length);

        let cmd = new ToggleStrongCommand();
        let documentSession = window.app.state.documentSession;
        let selectionState = documentSession.getSelectionState();
        let nodes = window.doc.getNodes();

        document.getElementById('message').innerHTML = "Running markup...";
        // n.startsWith('article') // article junk
        // || n.startsWith('ext-link') // what we are tring to create
        // n.startsWith('body') // this is just the intro
        // || n.startsWith('heading') // this is the heading for each paragraph
        let numErrors = 0;
        let totalWordsFound = 0;
        let wordsFound = [];
        let totalWordHits = 0;

        for (let n in nodes) {
            // console.log(n);
            if (n.startsWith('paragraph')
            ) {
                let p = window.doc.get(n);
                // just find the first one
                for (let w in data) {
                    let wordHits = 0;
                    let word = data[w];
                    let found = 0;
                    var reWord = word.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
                    var re = new RegExp("\\W" + reWord + "\\W", "g");
                    var hits;
                    while (hits = re.exec(p.content)) {

                        let sel = documentSession.createSelection({
                            type: 'property',
                            path: [p.id, 'content'],
                            startOffset: hits.index + 1,
                            endOffset: hits.index + 1 + word.length
                        });
                        selectionState.setSelection(sel);
                        let cmdState = cmd.getCommandState({
                            selectionState: selectionState,
                            documentSession: documentSession
                        });
                        if (cmdState.mode == "create") {
                            cmd.execute({
                                commandState: {
                                    mode: 'create'
                                },
                                documentSession: documentSession,
                                selectionState: documentSession.getSelectionState()
                            });
                            console.log('Found ' + word);

                        } else {
                            console.log("Annotated words: " + p.content.substring(selectionState.getAnnotationsForType(cmd.getAnnotationType())[0].startOffset, selectionState.getAnnotationsForType(cmd.getAnnotationType())[0].endOffset));
                            if (cmdState.mode == "delete") {
                                console.log('Error trying to annotate: ' + word + ' because it is already linked.');
                            } else if (cmdState.mode == "expand") {
                                console.log('Error trying to annotate: ' + word + ' because part of the word is already linked.');
                            } else if (cmdState.mode == "truncate") {
                                console.log('Error trying to annotate: ' + word + ' because it is part of the linked word.');
                            }
                            ++numErrors;
                        }

                        //found = p.content.indexOf(word,found+1);
                        ++wordHits;
                    }
                    if (wordHits > 0) {
                        ++totalWordsFound;
                        totalWordHits += wordHits;
                        wordsFound[word] = wordHits;
                        document.getElementById('message').innerHTML = "Searching: found " + totalWordsFound + " words, hits: " + totalWordHits;
                    }
                }
            }
        }
        let finalMessage = "Total words " + totalWordsFound + " Total links: " + totalWordHits;
        let detailButton = "<button style='display: inline;' type='button' onclick='var e = document.getElementById(\"hitDetails\"); e.style.display = (e.style.display == \"block\") ? \"none\" : \"block\";'\>Toggle details</button>";
        // finalMessage += "
";
        finalMessage += detailButton ;
        finalMessage += "
";
        finalMessage += "
";
        for (let word in wordsFound) {
            finalMessage += "
" + word ;
            if(wordsFound[word]>1){
                finalMessage += " (" + wordsFound[word] + ")";
            }
            finalMessage += ";
 ";
        }
        finalMessage += "
";

        // finalMessage += "
";
        document.getElementById('message').innerHTML = finalMessage;
        console.log('total found: ' + totalWordsFound);
        console.log('total errors: ' + numErrors);

        if (callback) callback();
    }

    getWords(callback) {
        let serverURL = window.location.protocol + '//' + window.location.hostname + ':8080/keyWordSet/sampleKeyWordSet';
        console.log('server URL: ' + serverURL);
        request('GET', serverURL, null, function (err, data) {
            if (err) {
                console.error(err);
                this.setState({
                    error: new Error('Loading failed')
                });
                return
            }
            if (data) {
                this.words = [];
                for (let d in data) {
                    this.words.push(data[d].value);
                }
                console.log('finished processing with words: ' + this.words.length);
                // this.render(this.words, cb);
                if (callback) callback(this.words);

                return this.words;
            }
        });
    }

}

class ToggleStrongCommand extends AnnotationCommand {

    // type = 'bold';
    // tagName = 'bold';

    constructor() {
        // super({name: 'bold', nodeType: 'bold'})
        super({name: 'markup', nodeType: 'ext-link'})
    }
}

// ToggleStrongCommand.define({
//     attributes: { type: 'object', default: {} }
// });

// export default ToggleStrongCommand

export default MarkupApp
<|endoftext|>


<commit_before>var $selects,
    defaultChartOptions;

defaultChartOptions = {
  chart: {},
  title: {
    x: -20 //center
  },
  subtitle: {
    x: -20
  },
  xAxis: {
    type: 'datetime',
    dateTimeLabelFormats: { // don't display the year
      minute: '%H:%M'
    }
  },
  yAxis: {
    min: 0,
    plotLines: [{
      value: 0,
      width: 1,
      color: '#808080'
    }]
  },
  legend: {
    layout: 'vertical',
    align: 'right',
    verticalAlign: 'middle',
    borderWidth: 0
  },
  plotOptions: {
    series: {
      events: {

        // Allow filtering shown series in chart
        legendItemClick: function(event) {
          var selected = this.index,
          allSeries = this.chart.series,
          state = this.toggleState || 'visible',
          othersAction;

          if (state === 'visible') {
            othersAction = 'hide';
            this.toggleState = 'solo';
          } else {
            othersAction = 'show';
            this.toggleState = 'visible';
          }

          // Hold shift, ctrl, or cmd to toggle just the clicked series
          if (event.browserEvent.metaKey || event.browserEvent.shiftKey || event.browserEvent.ctrlKey) {
            if (state === 'solo') {
              allSeries[selected].hide();
            } else {
              allSeries[selected].show();
            }

            // Otherwise, toggle between showing only the clicked series or all series
          } else {
            var i = 0,
            len = allSeries.length;

            // No idea why highcharts takes so long to loop through and hide/show series,
            // so for now, we need to use setTimeout to show the user something is happening
            // and not lock up the UI.
            function loopSeries() {
              if (selected === i) {
                allSeries[selected].show();
              } else {
                allSeries[i][othersAction]();
                delete allSeries[i]['toggle'];
              }

              i++;

              if (i < len) {
                setTimeout(loopSeries, 0.5);
              }
            }

            loopSeries();
          }

          return false;
        }
      }
    }
  }
};

var ChartOptions = function($el, response) {
  // Normally, this would be handle with prototypal inheritence:
  // E.g. ChartOptions.prototype = defaultChartOptions
  // But Highcharts won't recognize the properties in the prototype
  for (key in defaultChartOptions) {
    if (defaultChartOptions.hasOwnProperty(key)) {
      this[key] = $.extend(true, {}, defaultChartOptions[key]);
    }
  }
  this.title.text = subWithResponse($el.data('title'), response);
  this.subtitle.text = subWithResponse($el.data('subtitle'), response);
  this.yAxis.title = subWithResponse($el.data('y-axis-label'), response);

  this.series = normalizeData(response);

  // Only display legend when more than one series is present
  // and there are series labels to show.
  var showLegend = this.series.length > 1 && this.series.some( function(el) {
    return typeof(el.name != 'undefined');
  });
  this.legend.enabled = showLegend;

  if (this.series.length == 1) {
    this.chart.type = 'area';
  }

  if ($el.data('y-axis-max')) {
    this.yAxis.max = parseFloat($el.data('y-axis-max'));
  }
}

// Access nested values in a hash by passing a string,
// where nested keys are denoted by a period.
// E.g.
//     var myObj = {hi: {there: {whats: 'up'}}};
//     getKey(myObj, 'hi.there.whats'); //=> 'up'
var getKey = function(o, k) {
  var a = k.split('.');
  while (a.length) {
    var n = a.shift();
    if (n in o) {
      o = o[n];
    } else {
      return;
    }
  }
  return o;
};

// Replace mustache-style string variables in text with corresponding property in response object
// E.g.
//     response = {name: "you"};
//     subWithResponse("hi {{ name }}", response); //=> "hi you"
var subWithResponse = function(text, response) {
  return text && text.replace(/{{\s*([\w\.]+)\s*}}/g, function (match, capture) { return response[capture];});
}

var normalizeData = function(response) {
  var range = response.range,
      keys = response.lookup_keys,
      series = [],
      dateStart = range[0]*1000,
      dateInterval = (range[1] - range[0])*1000;

  // Loop through results
  for (var i = 0, ilen = response.results.length; i < ilen; i++) {
    var record = response.results[i];

    // Loop through keys for each record (events, count, total, etc.)
    for (var k = 0, klen = keys.length; k < klen; k++) {
      var timeKey = keys[k],
          recordName = record.name,
          s = {
            data: [],
            pointInterval: dateInterval,
            pointStart: dateStart
          };

      // If record contains multiple aggregate keys, add key to series label
      if (klen > 1) {
        var timeKeyArray = timeKey.split('.'),
            index = timeKeyArray.indexOf('{{t}}');

        // But don't count the different timestamps as multiple keys
        timeKeyArray.splice(index, 1);

        if (timeKeyArray.length) {
          // Don't know if recordName is defined or not,
          // and don't want a separator if it's undefined.
          recordName = recordName ? recordName + ' - ' : '';
          recordName += timeKeyArray.slice(-1)[0];
        }
      }
      s.name = recordName;

      // Build the array of plot values
      for (var t = 0, tlen = range.length; t < tlen; t++) {
        var x = range[t],
            y = getKey(record, timeKey.replace('{{t}}', response.granularity + '.' + x)) || 0;
        s.data.push( y );
      }

      series.push(s);
    }
  }
  return series;
}

var refreshAnalytics = function() {
  var $this = $(this),
      chartType = $this.data('chart'),
      $thisSelects = $selects.filter('[data-for-chart="' + this.id + '"]'),
      $granularity = $thisSelects.filter('[data-select="granularity"]'),
      $range = $thisSelects.filter('[data-select="range"]'),
      requestOptions = {},
      $refresh = $('[data-refresh-chart="' + this.id + '"]');

  if ($granularity.length) {
    requestOptions.granularity = $granularity.val();
  }
  if ($range.length) {
    requestOptions.range = $range.val();
  }

  $.ajax({
    dataType: "json",
    url: $this.data('url'),
    data: requestOptions,
    beforeSend: function() {
      $refresh.html('Loading...').removeClass('btn-success').addClass('analytics-loading');
    },
    complete: function() {
      $refresh.html('Refresh').removeClass('analytics-loading');
    },
    success: function(response) {
      if (chartType === 'timeseries') {
        $this.highcharts( new ChartOptions($this, response) );
      }
      $refresh.html('Refresh').removeClass('analytics-loading');
    }
  });
}

var loadAnalytics = function() {
  $('[data-chart]').each( function() {
    refreshAnalytics.call(this);
  });
};

$(document)
  .delegate('[data-refresh-chart]', 'click', function(e) {
    var chart = $(this).data('refresh-chart');
    refreshAnalytics.call( document.getElementById(chart) );
    e.preventDefault();
  })
  .delegate('[data-for-chart]', 'change', function() {
    var chart = $(this).data('for-chart');
    $('[data-refresh-chart="' + chart + '"]').addClass('btn-success');
  });

$(function () {
  // Show charts in browser's timezone instead of UTC as they are stored
  Highcharts.setOptions({
    global: {
      useUTC: false
    }
  });
  $selects = $('[data-for-chart]');
  loadAnalytics();
});
<commit_msg>Refactored analytics timeseries js, added new timeseries-table to display analytics in table using dynatable. Switched AssignmentPredictorScore and PagePageview to use timeseries-table.<commit_after>var $selects;

//------------------------------------------------------------
// Utility functions
//------------------------------------------------------------

// Access nested values in a hash by passing a string,
// where nested keys are denoted by a period.
// E.g.
//     var myObj = {hi: {there: {whats: 'up'}}};
//     getKey(myObj, 'hi.there.whats'); //=> 'up'
var getKey = function(o, k) {
  var a = k.split('.');
  while (a.length) {
    var n = a.shift();
    if (n in o) {
      o = o[n];
    } else {
      return;
    }
  }
  return o;
};

// Replace mustache-style string variables in text with corresponding property in response object
// E.g.
//     response = {name: "you"};
//     subWithResponse("hi {{ name }}", response); //=> "hi you"
var subWithResponse = function(text, response) {
  return text && text.replace(/{{\s*([\w\.]+)\s*}}/g, function (match, capture) { return response[capture];});
};

//------------------------------------------------------------
// Build HighCharts options
//------------------------------------------------------------

var defaultChartOptions = {
  chart: {},
  title: {
    x: -20 //center
  },
  subtitle: {
    x: -20
  },
  xAxis: {
    type: 'datetime',
    dateTimeLabelFormats: { // don't display the year
      minute: '%H:%M'
    }
  },
  yAxis: {
    min: 0,
    plotLines: [{
      value: 0,
      width: 1,
      color: '#808080'
    }]
  },
  legend: {
    layout: 'vertical',
    align: 'right',
    verticalAlign: 'middle',
    borderWidth: 0
  },
  plotOptions: {
    series: {
      events: {

        // Allow filtering shown series in chart
        legendItemClick: function(event) {
          var selected = this.index,
          allSeries = this.chart.series,
          state = this.toggleState || 'visible',
          othersAction;

          if (state === 'visible') {
            othersAction = 'hide';
            this.toggleState = 'solo';
          } else {
            othersAction = 'show';
            this.toggleState = 'visible';
          }

          // Hold shift, ctrl, or cmd to toggle just the clicked series
          if (event.browserEvent.metaKey || event.browserEvent.shiftKey || event.browserEvent.ctrlKey) {
            if (state === 'solo') {
              allSeries[selected].hide();
            } else {
              allSeries[selected].show();
            }

            // Otherwise, toggle between showing only the clicked series or all series
          } else {
            var i = 0,
            len = allSeries.length;

            // No idea why highcharts takes so long to loop through and hide/show series,
            // so for now, we need to use setTimeout to show the user something is happening
            // and not lock up the UI.
            function loopSeries() {
              if (selected === i) {
                allSeries[selected].show();
              } else {
                allSeries[i][othersAction]();
                delete allSeries[i]['toggle'];
              }

              i++;

              if (i < len) {
                setTimeout(loopSeries, 0.5);
              }
            }

            loopSeries();
          }

          return false;
        }
      }
    }
  }
};

var defaultTableOptions = {
  features: {
    search: false,
    perPageSelect: false,
    pushState: false
  },
  dataset: {
  }
};

var TimeLineOptions = function($el, response) {
  // Normally, this would be handle with prototypal inheritence:
  // E.g. ChartOptions.prototype = defaultChartOptions
  // But Highcharts won't recognize the properties in the prototype
  for (key in defaultChartOptions) {
    if (defaultChartOptions.hasOwnProperty(key)) {
      this[key] = $.extend(true, {}, defaultChartOptions[key]);
    }
  }
  this.title.text = subWithResponse($el.data('title'), response);
  this.subtitle.text = subWithResponse($el.data('subtitle'), response);
  this.yAxis.title = subWithResponse($el.data('y-axis-label'), response);

  this.series = timeLineSeries(response);

  // Only display legend when more than one series is present
  // and there are series labels to show.
  var showLegend = this.series.length > 1 && this.series.some( function(el) {
    return typeof(el.name != 'undefined');
  });
  this.legend.enabled = showLegend;

  if (this.series.length == 1) {
    this.chart.type = 'area';
  }

  if ($el.data('y-axis-max')) {
    this.yAxis.max = parseFloat($el.data('y-axis-max'));
  }
};

var TimeSummaryOptions = function($el, response) {
  // Normally, this would be handle with prototypal inheritence:
  // E.g. ChartOptions.prototype = defaultChartOptions
  // But Highcharts won't recognize the properties in the prototype
  for (key in defaultTableOptions) {
    if (defaultTableOptions.hasOwnProperty(key)) {
      this[key] = $.extend(true, {}, defaultTableOptions[key]);
    }
  }
  this.dataset.records = timeSummarySeries(response);
};

//------------------------------------------------------------
// AnalyticsData
// (create normalized data object from API responses)
//------------------------------------------------------------

var AnalyticsData = function(response) {
  this.range = response.range;
  this.keys = response.lookup_keys;
  this.dateStart = this.range[0]*1000;
  this.dateInterval = (this.range[1] - this.range[0])*1000;
  this.results = response.results;
  this.granularity = response.granularity;
};

// Builds time series collection matching format:
// series = [
//   {
//     name: 'blah',
//     pointInterval: 24 * 3600 * 1000,
//     pointStart: Date.UTC(2013, 8, 02),
//     data: [
//       50, 75, 64, 32
//     ]
//   }
// ]
//
// See: http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/line-time-series/

var timeLineSeries = function(response) {
  var data = new AnalyticsData(response),
      series = [];

  // Loop through results
  for (var i = 0, ilen = data.results.length; i < ilen; i++) {
    var record = data.results[i];

    // Loop through keys for each record (events, count, total, etc.)
    for (var k = 0, klen = data.keys.length; k < klen; k++) {
      var timeKey = data.keys[k],
          recordName = record.name,
          s = {
            data: [],
            pointInterval: data.dateInterval,
            pointStart: data.dateStart
          };

      // If record contains multiple aggregate keys, add key to series label
      if (klen > 1) {
        var timeKeyArray = timeKey.split('.'),
            index = timeKeyArray.indexOf('{{t}}');

        // But don't count the different timestamps as multiple keys
        timeKeyArray.splice(index, 1);

        if (timeKeyArray.length) {
          // Don't know if recordName is defined or not,
          // and don't want a separator if it's undefined.
          recordName = recordName ? recordName + ' - ' : '';
          recordName += timeKeyArray.slice(-1)[0];
        }
      }
      s.name = recordName;

      // Build the array of plot values
      for (var t = 0, tlen = data.range.length; t < tlen; t++) {
        var x = data.range[t],
            y = getKey(record, timeKey.replace('{{t}}', data.granularity + '.' + x)) || 0;
        s.data.push( y );
      }

      series.push(s);
    }
  }
  return series;
};

// Builds summary series for time data in format:
// series = [
//   {
//     name: 'blah',
//     total: 432
//   }
// ]

var timeSummarySeries = function(response) {
  var data = new AnalyticsData(response),
      series = [];

  // Loop through results
  for (var i = 0, ilen = data.results.length; i < ilen; i++) {
    var record = data.results[i],
        s = {
          name: record.name || 'Total',
        };

    // Loop through keys for each record (events, count, total, etc.)
    for (var k = 0, klen = data.keys.length; k < klen; k++) {
      var timeKey = data.keys[k],
          propertyName = 'total';

      // Set series properties from key names
      var timeKeyArray = timeKey.split('.'),
          index = timeKeyArray.indexOf('{{t}}');

      // But don't count the timestamp as part of the name
      timeKeyArray.splice(index, 1);

      if (timeKeyArray.length) {
        propertyName = timeKeyArray.slice(-1)[0];
      }
      s[propertyName] = 0;

      // Build total of all values in range
      for (var t = 0, tlen = data.range.length; t < tlen; t++) {
        var x = data.range[t],
            y = getKey(record, timeKey.replace('{{t}}', data.granularity + '.' + x)) || 0;
        s[propertyName] += y;
      }
    }

    if (s.total && s.count) {
      s.average = Math.round( s.total*10000 / s.count, 2 )/100;
    }
    series.push(s);
  }
  console.log(series);
  return series;
};

// Request analytics data for this chart element via ajax and bind callbacks
var refreshAnalytics = function() {
  var $this = $(this),
      chartType = $this.data('chart'),
      $thisSelects = $selects.filter('[data-for-chart="' + this.id + '"]'),
      $granularity = $thisSelects.filter('[data-select="granularity"]'),
      $range = $thisSelects.filter('[data-select="range"]'),
      requestOptions = {},
      $refresh = $('[data-refresh-chart="' + this.id + '"]');

  if ($granularity.length) {
    requestOptions.granularity = $granularity.val();
  }
  if ($range.length) {
    requestOptions.range = $range.val();
  }

  $.ajax({
    dataType: "json",
    url: $this.data('url'),
    data: requestOptions,
    beforeSend: function() {
      $refresh.html('Loading...').removeClass('btn-success').addClass('analytics-loading');
    },
    complete: function() {
      $refresh.html('Refresh').removeClass('analytics-loading');
    },
    success: function(response) {
      if (chartType === 'timeseries') {
        $this.highcharts( new TimeLineOptions($this, response) );
      } else if (chartType === 'timeseries-table') {
        $this.removeData('dynatable');
        $this.find('tbody').html('');
        $this.siblings('.dynatable-pagination-links,.dynatable-record-count').remove();
        $this.dynatable( new TimeSummaryOptions($this, response) );
      }
      $refresh.html('Refresh').removeClass('analytics-loading');
    }
  });
}

// Loop through [data-chart] elements and call refreshAnalytics function for each
var loadAnalytics = function() {
  $('[data-chart]').each( function() {
    refreshAnalytics.call(this);
  });
};

// Bind handlers for refresh buttons for each chart
$(document)
  .delegate('[data-refresh-chart]', 'click', function(e) {
    var chart = $(this).data('refresh-chart');
    refreshAnalytics.call( document.getElementById(chart) );
    e.preventDefault();
  })
  .delegate('[data-for-chart]', 'change', function() {
    var chart = $(this).data('for-chart');
    $('[data-refresh-chart="' + chart + '"]').addClass('btn-success');
  });

$(function () {
  // Show charts in browser's timezone instead of UTC as they are stored
  Highcharts.setOptions({
    global: {
      useUTC: false
    }
  });
  $selects = $('[data-for-chart]');
  loadAnalytics();
});
<|endoftext|>