<commit_before>import Ember from 'ember';
import { moduleForComponent, test } from 'ember-qunit';
import InputBasedMixin from 'sl-ember-components/mixins/sl-input-based';
import TooltipEnabledMixin from 'sl-ember-components/mixins/sl-tooltip-enabled';
import ComponentInputId from 'sl-ember-components/mixins/sl-component-input-id';

moduleForComponent( 'sl-input', 'Unit | Component | sl input', {
    unit: true
});

test( 'Expected Mixins are present', function( assert ) {
    assert.ok(
        InputBasedMixin.detect( this.subject() ),
        'InputBased Mixin is present'
    );

    assert.ok(
        TooltipEnabledMixin.detect( this.subject() ),
        'TooltipEnabled Mixin is present'
    );

    assert.ok(
        ComponentInputId.detect( this.subject() ),
        'ComponentInputId Mixin is present'
    );
});

test( 'getInput() returns correct element', function( assert ) {
    const component = this.subject();

    assert.ok(
        this.$( 'input' ).get( 0 ) ===
        component.getInput().get( 0 )
    );
});

test( 'Event handlers are registered and unregistered', function( assert ) {
    const component = this.subject({
        blur: 'blur'
    });
    const inputElement = this.$( 'input' ).get( 0 );
    const jQueryData = Ember.get( Ember.$, '_data' );
    const events = jQueryData( inputElement, 'events' );

    assert.ok(
        'blur' in events,
        'Blur event handler is registered after didInsertElement'
    );

    Ember.run( () => {
        component.trigger( 'willClearRender' );

        assert.notOk(
            'blur' in events,
            'Blur event handler is unregistered after willClearRender'
        );
    });
});

test( 'Blur action is triggered when input loses focus', function( assert ) {
    assert.expect( 1 );

    const done = assert.async();

    this.subject({
        blur: 'blur',
        targetObject: {
            blur() {
                assert.ok(
                    'blur was triggered'
                );

                done();
            }
        }
    });

    this.$( 'input' ).trigger( 'blur' );
});

test( 'Default property values', function( assert ) {
    const component = this.subject();

    assert.strictEqual(
        component.get( 'clickToEdit' ),
        false,
        'clickToEdit property false by default'
    );

    assert.equal(
        component.get( 'type' ),
        'text',
        'type property is text by default'
    );

    assert.strictEqual(
        component.get( 'isTypeaheadSetup' ),
        false,
        'isTypeaheadSetup property false by default'
    );

    assert.equal(
        component.get( 'suggestionNamePath' ),
        'name',
        'suggestionNamePath property is "name" by default'
    );

    assert.strictEqual(
        component.get( 'value' ),
        null,
        'value property is null by default'
    );
});

test( 'Click to edit input has the correct class', function( assert ) {
    this.subject({
        clickToEdit: true
    });

    assert.ok(
        this.$( 'input' ).hasClass( 'click-to-edit' )
    );
});

test( 'Input can be disabled', function( assert ) {
    this.subject({
        disabled: true
    });

    assert.ok(
        this.$( 'input' ).prop( 'disabled' )
    );
});

test( 'Help text is displayed', function( assert ) {
    const helpText = 'Testing help text is displayed';

    this.subject({
        helpText: helpText
    });

    assert.equal(
        this.$( '.help-block' ).text().trim(),
        helpText
    );
});

test( 'Label text is displayed', function( assert ) {
    const labelText = 'Test label text';

    this.subject({
        label: labelText
    });

    assert.equal(
        this.$( '.control-label' ).text().trim(),
        labelText
    );
});

test( 'Label text is not displayed', function( assert ) {
    this.subject();

    assert.equal(
        this.$( '.control-label' ).length,
        0
    );
});

test( 'Optional property displays optional label', function( assert ) {
    this.subject({
        label: 'Optional input',
        optional: true
    });

    assert.equal(
        this.$( '.text-info' ).text().trim(),
        'Optional'
    );
});

test( 'Required property displays required label', function( assert ) {
    this.subject({
        label: 'Required input',
        required: true
    });

    assert.equal(
        this.$( '.text-danger' ).text().trim(),
        'Required'
    );
});

test( 'Required property does not display required label', function( assert ) {
    this.subject({
        label: 'Required input',
        required: false
    });

    assert.equal(
        this.$( '.text-danger' ).length,
        0
    );
});

test( 'Placeholder property sets the placeholder for the input', function( assert ) {
    const placeholderText = 'placeholder';

    this.subject({
        placeholder: 'placeholder'
    });

    assert.equal(
        this.$( 'input' ).prop( 'placeholder' ),
        placeholderText
    );
});

test( 'Readonly property, makes the input readonly', function( assert ) {
    this.subject({
        readonly: true
    });

    assert.ok(
        this.$( 'input' ).prop( 'readonly' )
    );
});

test( 'Popover is initialized with the correct options', function( assert ) {
    const popoverText = 'Popover text';

    this.subject({
        popover: popoverText
    });

    this.render();

    const data = this.$().data();
    const popoverData = data[ 'bs.popover' ];

    assert.strictEqual(
        popoverData.enabled,
        true,
        'Popover is enabled'
    );

    assert.equal(
        popoverData.options.trigger,
        'focus',
        'Popover trigger is "focus"'
    );

    assert.equal(
        popoverData.options.content,
        popoverText,
        'Popover text is set correctly'
    );
});

test( 'Typeahead is initialized and has the correct classes', function( assert ) {
    const colors = [
        'Black',
        'Yellow'
    ];

    this.subject({
        suggestions: colors
    });

    const typeahead = this.$( '.tt-input' ).data().ttTypeahead;

    assert.ok(
        typeahead,
        'Typeahead is initialized'
    );
});

test( 'Typeahead classes are present', function( assert ) {
    const colors = [
        'Black',
        'Yellow'
    ];

    this.subject({
        suggestions: colors
    });

    assert.ok(
        this.$( '.twitter-typeahead' ),
        'twitter-typeahead class exists'
    );

    assert.ok(
        this.$( '.typeahead' ),
        'typeahead class exists'
    );

    assert.ok(
        this.$( '.tt-input' ),
        'tt-input class exists'
    );

    assert.ok(
        this.$( '.tt-menu' ),
        'tt-menu class exists'
    );

    assert.ok(
        this.$( '.tt-dataset' ),
        'tt-dataset class exists'
    );
});

test( 'isTypeaheadSetup is true when suggestions are provided', function( assert ) {
    const colors = [
        'Black',
        'Yellow'
    ];

    const component = this.subject({
        suggestions: colors
    });

    this.render();

    assert.strictEqual(
        component.get( 'isTypeaheadSetup' ),
        true
    );
});

test( 'Value is set correctly', function( assert ) {
    const value = 'set value';

    this.subject({ value: value });

    assert.equal(
        this.$( 'input' ).val(),
        value
    );
});
<commit_msg>Closes softlayer/sl-ember-components#1095<commit_after>import Ember from 'ember';
import { moduleForComponent, test } from 'ember-qunit';
import InputBasedMixin from 'sl-ember-components/mixins/sl-input-based';
import TooltipEnabledMixin from 'sl-ember-components/mixins/sl-tooltip-enabled';
import ComponentInputId from 'sl-ember-components/mixins/sl-component-input-id';

moduleForComponent( 'sl-input', 'Unit | Component | sl input', {
    unit: true
});

test( 'Expected Mixins are present', function( assert ) {
    assert.ok(
        InputBasedMixin.detect( this.subject() ),
        'InputBased Mixin is present'
    );

    assert.ok(
        TooltipEnabledMixin.detect( this.subject() ),
        'TooltipEnabled Mixin is present'
    );

    assert.ok(
        ComponentInputId.detect( this.subject() ),
        'ComponentInputId Mixin is present'
    );
});

test( 'getInput() returns correct element', function( assert ) {
    const component = this.subject();

    assert.ok(
        this.$( 'input' ).get( 0 ) ===
        component.getInput().get( 0 )
    );
});

test( 'Event handlers are registered and unregistered', function( assert ) {
    const component = this.subject({
        blur: 'blur'
    });
    const inputElement = this.$( 'input' ).get( 0 );
    const jQueryData = Ember.get( Ember.$, '_data' );
    const events = jQueryData( inputElement, 'events' );

    assert.ok(
        'blur' in events,
        'Blur event handler is registered after didInsertElement'
    );

    Ember.run( () => {
        component.trigger( 'willClearRender' );

        assert.notOk(
            'blur' in events,
            'Blur event handler is unregistered after willClearRender'
        );
    });
});

test( 'Blur action is triggered when input loses focus', function( assert ) {
    assert.expect( 1 );

    const done = assert.async();

    this.subject({
        blur: 'blur',
        targetObject: {
            blur() {
                assert.ok(
                    'blur was triggered'
                );

                done();
            }
        }
    });

    this.$( 'input' ).trigger( 'blur' );
});

test( 'Default property values', function( assert ) {
    const component = this.subject();

    assert.strictEqual(
        component.get( 'clickToEdit' ),
        false,
        'clickToEdit property false by default'
    );

    assert.equal(
        component.get( 'type' ),
        'text',
        'type property is text by default'
    );

    assert.strictEqual(
        component.get( 'isTypeaheadSetup' ),
        false,
        'isTypeaheadSetup property false by default'
    );

    assert.equal(
        component.get( 'suggestionNamePath' ),
        'name',
        'suggestionNamePath property is "name" by default'
    );

    assert.strictEqual(
        component.get( 'value' ),
        null,
        'value property is null by default'
    );
});

test( 'Click to edit input has the correct class', function( assert ) {
    this.subject({
        clickToEdit: true
    });

    assert.ok(
        this.$( 'input' ).hasClass( 'click-to-edit' )
    );
});

test( 'Input can be disabled', function( assert ) {
    this.subject({
        disabled: true
    });

    assert.ok(
        this.$( 'input' ).prop( 'disabled' )
    );
});

test( 'Help text is displayed', function( assert ) {
    const helpText = 'Testing help text is displayed';

    this.subject({
        helpText: helpText
    });

    assert.equal(
        this.$( '.help-block' ).text().trim(),
        helpText
    );
});

test( 'Label text is displayed', function( assert ) {
    const labelText = 'Test label text';

    this.subject({
        label: labelText
    });

    assert.equal(
        this.$( '.control-label' ).text().trim(),
        labelText
    );
});

test( 'Label text is not displayed', function( assert ) {
    this.subject();

    assert.equal(
        this.$( '.control-label' ).length,
        0
    );
});

test( 'Optional property displays optional label', function( assert ) {
    this.subject({
        label: 'Optional input',
        optional: true
    });

    assert.equal(
        this.$( '.text-info' ).text().trim(),
        'Optional'
    );
});

test( 'Required property displays required label', function( assert ) {
    this.subject({
        label: 'Required input',
        required: true
    });

    assert.equal(
        this.$( '.text-danger' ).text().trim(),
        'Required'
    );
});

test( 'Required property does not display required label', function( assert ) {
    this.subject({
        label: 'Required input',
        required: false
    });

    assert.equal(
        this.$( '.text-danger' ).length,
        0
    );
});

test( 'Placeholder property sets the placeholder for the input', function( assert ) {
    const placeholderText = 'placeholder';

    this.subject({
        placeholder: 'placeholder'
    });

    assert.equal(
        this.$( 'input' ).prop( 'placeholder' ),
        placeholderText
    );
});

test( 'Readonly property, makes the input readonly', function( assert ) {
    this.subject({
        readonly: true
    });

    assert.ok(
        this.$( 'input' ).prop( 'readonly' )
    );
});

test( 'Popover is initialized with the correct options', function( assert ) {
    const popoverText = 'Popover text';

    this.subject({
        popover: popoverText
    });

    this.render();

    const data = this.$().data();
    const popoverData = data[ 'bs.popover' ];

    assert.strictEqual(
        popoverData.enabled,
        true,
        'Popover is enabled'
    );

    assert.equal(
        popoverData.options.trigger,
        'focus',
        'Popover trigger is "focus"'
    );

    assert.equal(
        popoverData.options.content,
        popoverText,
        'Popover text is set correctly'
    );
});

test( 'Typeahead is initialized and has the correct classes', function( assert ) {
    const colors = [
        'Black',
        'Yellow'
    ];

    this.subject({
        suggestions: colors
    });

    const typeahead = this.$( '.tt-input' ).data().ttTypeahead;

    assert.ok(
        typeahead,
        'Typeahead is initialized'
    );
});

test( 'Typeahead classes are present', function( assert ) {
    const colors = [
        'Black',
        'Yellow'
    ];

    this.subject({
        suggestions: colors
    });

    assert.ok(
        this.$( '.twitter-typeahead' ),
        'twitter-typeahead class exists'
    );

    assert.ok(
        this.$( '.typeahead' ),
        'typeahead class exists'
    );

    assert.ok(
        this.$( '.tt-input' ),
        'tt-input class exists'
    );

    assert.ok(
        this.$( '.tt-menu' ),
        'tt-menu class exists'
    );

    assert.ok(
        this.$( '.tt-dataset' ),
        'tt-dataset class exists'
    );
});

test( 'isTypeaheadSetup is true when suggestions are provided', function( assert ) {
    const colors = [
        'Black',
        'Yellow'
    ];

    const component = this.subject({
        suggestions: colors
    });

    this.render();

    assert.strictEqual(
        component.get( 'isTypeaheadSetup' ),
        true
    );
});

test( 'Value is set correctly', function( assert ) {
    const value = 'set value';

    this.subject({ value: value });

    assert.equal(
        this.$( 'input' ).val(),
        value
    );
});

test( 'Observer keys are correct', function( assert ) {
    const component = this.subject();

    const setupTypeaheadKeys = [
        'suggestions'
    ];

    assert.deepEqual(
        component.setupTypeahead.__ember_observes__,
        setupTypeaheadKeys,
        'Observer keys are correct for setupTypeahead()'
    );
});
<|endoftext|>


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

  QUnit.module('modal plugin')

  QUnit.test('should be defined on jquery object', function (assert) {
    assert.ok($(document.body).modal, 'modal method is defined')
  })

  QUnit.module('modal', {
    setup: function () {
      // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
      $.fn.bootstrapModal = $.fn.modal.noConflict()
    },
    teardown: function () {
      $.fn.modal = $.fn.bootstrapModal
      delete $.fn.bootstrapModal
    }
  })

  QUnit.test('should provide no conflict', function (assert) {
    assert.strictEqual($.fn.modal, undefined, 'modal was set back to undefined (orig value)')
  })

  QUnit.test('should return jquery collection containing the element', function (assert) {
    var $el = $('
')
    var $modal = $el.bootstrapModal()
    assert.ok($modal instanceof $, 'returns jquery collection')
    assert.strictEqual($modal[0], $el[0], 'collection contains element')
  })

  QUnit.test('should expose defaults var for settings', function (assert) {
    assert.ok($.fn.bootstrapModal.Constructor.DEFAULTS, 'default object exposed')
  })

  QUnit.test('should insert into dom when show method is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should fire show event', function (assert) {
    var done = assert.async()

    $('
')
      .on('show.bs.modal', function () {
        assert.ok(true, 'show event fired')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should not fire shown when show was prevented', function (assert) {
    var done = assert.async()

    $('
')
      .on('show.bs.modal', function (e) {
        e.preventDefault()
        assert.ok(true, 'show event fired')
        done()
      })
      .on('shown.bs.modal', function () {
        assert.ok(false, 'shown event fired')
      })
      .bootstrapModal('show')
  })

  QUnit.test('should hide modal when hide is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        $(this).bootstrapModal('hide')
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should toggle when toggle is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        $(this).bootstrapModal('toggle')
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('toggle')
  })

  QUnit.test('should remove from dom when click [data-dismiss="modal"]', function (assert) {
    var done = assert.async()

    $('

')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        $(this).find('.close').click()
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('toggle')
  })

  QUnit.test('should allow modal close with "backdrop:false"', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        $(this).bootstrapModal('hide')
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should close modal when clicking outside of modal-content', function (assert) {
    var done = assert.async()

    $('

')
      .on('shown.bs.modal', function () {
        assert.notEqual($('#modal-test').length, 0, 'modal insterted into dom')
        $('.contents').click()
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        $('#modal-test .modal-backdrop').click()
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should close modal when escape key is pressed via keydown', function (assert) {
    var done = assert.async()

    var div = $('
')
    div
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').length, 'modal insterted into dom')
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        div.trigger($.Event('keydown', { which: 27 }))

        setTimeout(function () {
          assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
          div.remove()
          done()
        }, 0)
      })
      .bootstrapModal('show')
  })

  QUnit.test('should not close modal when escape key is pressed via keyup', function (assert) {
    var done = assert.async()

    var div = $('
')
    div
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').length, 'modal insterted into dom')
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        div.trigger($.Event('keyup', { which: 27 }))

        setTimeout(function () {
          assert.ok($('#modal-test').is(':visible'), 'modal still visible')
          div.remove()
          done()
        }, 0)
      })
      .bootstrapModal('show')
  })

  QUnit.test('should trigger hide event once when clicking outside of modal-content', function (assert) {
    var done = assert.async()

    var triggered

    $('

')
      .on('shown.bs.modal', function () {
        triggered = 0
        $('#modal-test .modal-backdrop').click()
      })
      .on('hide.bs.modal', function () {
        triggered += 1
        assert.strictEqual(triggered, 1, 'modal hide triggered once')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should close reopened modal with [data-dismiss="modal"] click', function (assert) {
    var done = assert.async()

    $('

')
      .one('shown.bs.modal', function () {
        $('#close').click()
      })
      .one('hidden.bs.modal', function () {
        // after one open-close cycle
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        $(this)
          .one('shown.bs.modal', function () {
            $('#close').click()
          })
          .one('hidden.bs.modal', function () {
            assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
            done()
          })
          .bootstrapModal('show')
      })
      .bootstrapModal('show')
  })

  QUnit.test('should restore focus to toggling element when modal is hidden after having been opened via data-api', function (assert) {
    var done = assert.async()

    var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')

    $('

')
      .on('hidden.bs.modal', function () {
        setTimeout(function () {
          assert.ok($(document.activeElement).is($toggleBtn), 'toggling element is once again focused')
          done()
        }, 0)
      })
      .on('shown.bs.modal', function () {
        $('#close').click()
      })
      .appendTo('#qunit-fixture')

    $toggleBtn.click()
  })

  QUnit.test('should not restore focus to toggling element if the associated show event gets prevented', function (assert) {
    var done = assert.async()
    var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')
    var $otherBtn = $('<button id="other-btn"/>').appendTo('#qunit-fixture')

    $('

')
      .one('show.bs.modal', function (e) {
        e.preventDefault()
        $otherBtn.focus()
        setTimeout($.proxy(function () {
          $(this).bootstrapModal('show')
        }, this), 0)
      })
      .on('hidden.bs.modal', function () {
        setTimeout(function () {
          assert.ok($(document.activeElement).is($otherBtn), 'focus returned to toggling element')
          done()
        }, 0)
      })
      .on('shown.bs.modal', function () {
        $('#close').click()
      })
      .appendTo('#qunit-fixture')

    $toggleBtn.click()
  })
})
<commit_msg>Add tests for aria-hidden of modal<commit_after>$(function () {
  'use strict';

  QUnit.module('modal plugin')

  QUnit.test('should be defined on jquery object', function (assert) {
    assert.ok($(document.body).modal, 'modal method is defined')
  })

  QUnit.module('modal', {
    setup: function () {
      // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
      $.fn.bootstrapModal = $.fn.modal.noConflict()
    },
    teardown: function () {
      $.fn.modal = $.fn.bootstrapModal
      delete $.fn.bootstrapModal
    }
  })

  QUnit.test('should provide no conflict', function (assert) {
    assert.strictEqual($.fn.modal, undefined, 'modal was set back to undefined (orig value)')
  })

  QUnit.test('should return jquery collection containing the element', function (assert) {
    var $el = $('
')
    var $modal = $el.bootstrapModal()
    assert.ok($modal instanceof $, 'returns jquery collection')
    assert.strictEqual($modal[0], $el[0], 'collection contains element')
  })

  QUnit.test('should expose defaults var for settings', function (assert) {
    assert.ok($.fn.bootstrapModal.Constructor.DEFAULTS, 'default object exposed')
  })

  QUnit.test('should insert into dom when show method is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should set aria-hidden to false when show method is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.strictEqual($('#modal-test').attr('aria-hidden'), 'false', 'aria-hidden is set to string "false" when modal shown')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should fire show event', function (assert) {
    var done = assert.async()

    $('
')
      .on('show.bs.modal', function () {
        assert.ok(true, 'show event fired')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should not fire shown when show was prevented', function (assert) {
    var done = assert.async()

    $('
')
      .on('show.bs.modal', function (e) {
        e.preventDefault()
        assert.ok(true, 'show event fired')
        done()
      })
      .on('shown.bs.modal', function () {
        assert.ok(false, 'shown event fired')
      })
      .bootstrapModal('show')
  })

  QUnit.test('should hide modal when hide is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        $(this).bootstrapModal('hide')
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should set aria-hidden to true when hide is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.strictEqual($('#modal-test').length, 1, 'modal has been inserted into the dom')
        $(this).bootstrapModal('hide')
      })
      .on('hidden.bs.modal', function () {
        assert.strictEqual($('#modal-test').attr('aria-hidden'), 'true', 'aria-hidden is set to string "true" when modal shown')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should toggle when toggle is called', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        $(this).bootstrapModal('toggle')
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('toggle')
  })

  QUnit.test('should remove from dom when click [data-dismiss="modal"]', function (assert) {
    var done = assert.async()

    $('

')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom')
        $(this).find('.close').click()
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('toggle')
  })

  QUnit.test('should allow modal close with "backdrop:false"', function (assert) {
    var done = assert.async()

    $('
')
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        $(this).bootstrapModal('hide')
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should close modal when clicking outside of modal-content', function (assert) {
    var done = assert.async()

    $('

')
      .on('shown.bs.modal', function () {
        assert.notEqual($('#modal-test').length, 0, 'modal insterted into dom')
        $('.contents').click()
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        $('#modal-test .modal-backdrop').click()
      })
      .on('hidden.bs.modal', function () {
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should close modal when escape key is pressed via keydown', function (assert) {
    var done = assert.async()

    var div = $('
')
    div
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').length, 'modal insterted into dom')
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        div.trigger($.Event('keydown', { which: 27 }))

        setTimeout(function () {
          assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
          div.remove()
          done()
        }, 0)
      })
      .bootstrapModal('show')
  })

  QUnit.test('should not close modal when escape key is pressed via keyup', function (assert) {
    var done = assert.async()

    var div = $('
')
    div
      .on('shown.bs.modal', function () {
        assert.ok($('#modal-test').length, 'modal insterted into dom')
        assert.ok($('#modal-test').is(':visible'), 'modal visible')
        div.trigger($.Event('keyup', { which: 27 }))

        setTimeout(function () {
          assert.ok($('#modal-test').is(':visible'), 'modal still visible')
          div.remove()
          done()
        }, 0)
      })
      .bootstrapModal('show')
  })

  QUnit.test('should trigger hide event once when clicking outside of modal-content', function (assert) {
    var done = assert.async()

    var triggered

    $('

')
      .on('shown.bs.modal', function () {
        triggered = 0
        $('#modal-test .modal-backdrop').click()
      })
      .on('hide.bs.modal', function () {
        triggered += 1
        assert.strictEqual(triggered, 1, 'modal hide triggered once')
        done()
      })
      .bootstrapModal('show')
  })

  QUnit.test('should close reopened modal with [data-dismiss="modal"] click', function (assert) {
    var done = assert.async()

    $('

')
      .one('shown.bs.modal', function () {
        $('#close').click()
      })
      .one('hidden.bs.modal', function () {
        // after one open-close cycle
        assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
        $(this)
          .one('shown.bs.modal', function () {
            $('#close').click()
          })
          .one('hidden.bs.modal', function () {
            assert.ok(!$('#modal-test').is(':visible'), 'modal hidden')
            done()
          })
          .bootstrapModal('show')
      })
      .bootstrapModal('show')
  })

  QUnit.test('should restore focus to toggling element when modal is hidden after having been opened via data-api', function (assert) {
    var done = assert.async()

    var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')

    $('

')
      .on('hidden.bs.modal', function () {
        setTimeout(function () {
          assert.ok($(document.activeElement).is($toggleBtn), 'toggling element is once again focused')
          done()
        }, 0)
      })
      .on('shown.bs.modal', function () {
        $('#close').click()
      })
      .appendTo('#qunit-fixture')

    $toggleBtn.click()
  })

  QUnit.test('should not restore focus to toggling element if the associated show event gets prevented', function (assert) {
    var done = assert.async()
    var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture')
    var $otherBtn = $('<button id="other-btn"/>').appendTo('#qunit-fixture')

    $('

')
      .one('show.bs.modal', function (e) {
        e.preventDefault()
        $otherBtn.focus()
        setTimeout($.proxy(function () {
          $(this).bootstrapModal('show')
        }, this), 0)
      })
      .on('hidden.bs.modal', function () {
        setTimeout(function () {
          assert.ok($(document.activeElement).is($otherBtn), 'focus returned to toggling element')
          done()
        }, 0)
      })
      .on('shown.bs.modal', function () {
        $('#close').click()
      })
      .appendTo('#qunit-fixture')

    $toggleBtn.click()
  })
})
<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * GIT COMMIT-MSG hook for validating commit message.
 * See https://bitbucket.org/rabbitsystems/favodine/wiki/Commit-message-format
 *
 * Installation:
 * >> cd <repo>
 * >> ln -s ../../lib/validate-commit-msg.js .git/hooks/commit-msg
 * >> chmod +x .git/hooks/commit-msg
 */

'use strict';

var fs = require('fs');
var util = require('util');

var MAX_LENGTH = 100;
var PATTERN = /^(?:fixup!\s*)?(\w*)(\(([\w\$\.\*/-]*)\))?\: (.*)$/;
var IGNORED = /^WIP\:/;
var TYPES = {
  feat: true,
  fix: true,
  docs: true,
  style: true,
  refactor: true,
  perf: true,
  test: true,
  chore: true,
  revert: true
};

var error = function() {
  // gitx does not display it
  // http://gitx.lighthouseapp.com/projects/17830/tickets/294-feature-display-hook-error-message-when-hook-fails
  // https://groups.google.com/group/gitx/browse_thread/thread/a03bcab60844b812
  console.error('INVALID COMMIT MSG: ' + util.format.apply(null, arguments));
};

var validateMessage = function(message) {
  var isValid = true;

  if (IGNORED.test(message)) {
    console.log('Commit message validation ignored.');
    return true;
  }

  if (message.length > MAX_LENGTH) {
    error('is longer than %d characters !', MAX_LENGTH);
    isValid = false;
  }

  var match = PATTERN.exec(message);

  if (!match) {
    error('does not match "<type>(<scope>): <subject>" ! was: ' + message);
    return false;
  }

  var type = match[1];
  var scope = match[3];
  var subject = match[4];

  if (!TYPES.hasOwnProperty(type)) {
    error('"%s" is not allowed type !', type);
    return false;
  }

  // Some more ideas, do we want anything like this ?
  // - allow only specific scopes (eg. fix(docs) should not be allowed ?
  // - auto correct the type to lower case ?
  // - auto correct first letter of the subject to lower case ?
  // - auto add empty line after subject ?
  // - auto remove empty () ?
  // - auto correct typos in type ?
  // - store incorrect messages, so that we can learn

  return isValid;
};

var firstLineFromBuffer = function(buffer) {
  return buffer.toString().split('\n').shift();
};

// publish for testing
exports.validateMessage = validateMessage;

// hacky start if not run by jasmine :-D
if (process.argv.join('').indexOf('jasmine-node') === -1) {
  var commitMsgFile = process.argv[2];
  var incorrectLogFile = commitMsgFile.replace('COMMIT_EDITMSG', 'logs/incorrect-commit-msgs');

  fs.readFile(
    commitMsgFile, function(err, buffer) {
      var msg = firstLineFromBuffer(buffer);

      if (!validateMessage(msg)) {
        fs.appendFile(
          incorrectLogFile, msg + '\n', function() {
            process.exit(1);
          }
        );
      } else {
        process.exit(0);
      }
    }
  );
}
<commit_msg>feat(): remove jasmine check<commit_after>#!/usr/bin/env node

/**
 * GIT COMMIT-MSG hook for validating commit message.
 * See https://docs.google.com/document/d/1rk04jEuGfk9kYzfqCuOlPTSJw3hEDZJTBN5E5f1SALo
 *
 * Installation:
 * >> cd <repo>
 * >> ln -s ../../lib/validate-commit-msg.js .git/hooks/commit-msg
 * >> chmod +x .git/hooks/commit-msg
 */

'use strict';

var fs = require('fs');
var util = require('util');

var MAX_LENGTH = 100;
var PATTERN = /^(?:fixup!\s*)?(\w*)(\(([\w\$\.\*/-]*)\))?\: (.*)$/;
var IGNORED = /^WIP\:/;
var TYPES = {
  feat: true,
  fix: true,
  docs: true,
  style: true,
  refactor: true,
  perf: true,
  test: true,
  chore: true,
  revert: true
};

var error = function() {
  // gitx does not display it
  // http://gitx.lighthouseapp.com/projects/17830/tickets/294-feature-display-hook-error-message-when-hook-fails
  // https://groups.google.com/group/gitx/browse_thread/thread/a03bcab60844b812
  console.error('INVALID COMMIT MSG: ' + util.format.apply(null, arguments));
};

var validateMessage = function(message) {
  var isValid = true;

  if (IGNORED.test(message)) {
    console.log('Commit message validation ignored.');
    return true;
  }

  if (message.length > MAX_LENGTH) {
    error('is longer than %d characters !', MAX_LENGTH);
    isValid = false;
  }

  var match = PATTERN.exec(message);

  if (!match) {
    error('does not match "<type>(<scope>): <subject>" ! was: ' + message);
    return false;
  }

  var type = match[1];
  var scope = match[3];
  var subject = match[4];

  if (!TYPES.hasOwnProperty(type)) {
    error('"%s" is not allowed type !', type);
    return false;
  }

  // Some more ideas, do we want anything like this ?
  // - allow only specific scopes (eg. fix(docs) should not be allowed ?
  // - auto correct the type to lower case ?
  // - auto correct first letter of the subject to lower case ?
  // - auto add empty line after subject ?
  // - auto remove empty () ?
  // - auto correct typos in type ?
  // - store incorrect messages, so that we can learn

  return isValid;
};

var firstLineFromBuffer = function(buffer) {
  return buffer.toString().split('\n').shift();
};

// publish for testing
exports.validateMessage = validateMessage;

var commitMsgFile = process.argv[2];
var incorrectLogFile = commitMsgFile.replace('COMMIT_EDITMSG', 'logs/incorrect-commit-msgs');

fs.readFile(
  commitMsgFile, function(err, buffer) {
    var msg = firstLineFromBuffer(buffer);

    if (!validateMessage(msg)) {
      fs.appendFile(
        incorrectLogFile, msg + '\n', function() {
          process.exit(1);
        }
      );
    } else {
      process.exit(0);
    }
  }
);
<|endoftext|>


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

let component;
let model = [
    {
        id: 1,
        username: 'YippieKiYay',
        emailAddress: 'john.mcclane@domain.com',
        firstName: 'John',
        lastName: 'McClane',
        isAdmin: true,
        createdAt: '2017-01-01',
        updatedAt: '2017-01-02'
    }, {
        id: 2,
        username: 'HanSolo',
        emailAddress: 'smugglerOne@domain.com',
        firstName: 'Han',
        lastName: 'Solo',
        isAdmin: false,
        createdAt: '2015-12-18',
        updatedAt: '2015-12-19'
    }
];
let columns = [
    {
        property: 'username',
        label: 'Username',
        type: 'text',
        defaultSort: 'username',
    },
    {
        property: 'email-address',
        label: 'Email',
        type: 'text',
    },
    {
        property: 'first-name',
        label: 'First Name',
        type: 'text',
    },
    {
        property: 'last-name',
        label: 'Last Name',
        type: 'text',
    },
    {
        property: 'updated-at',
        label: 'Last Updated',
        type: 'date',
    },
];

moduleForComponent('ember-table-jsonapi', 'Unit | Component | ember table jsonapi', {
    unit: true,
    needs: ['helper:dot-to-dash-filter', 'component:ember-table-jsonapi-filter', 'helper:and', 'component:pagination-pager'],
    beforeEach: function() {
        component = this.subject({
            bindModel: model,
            columns: columns,
            hasActions: 'true',
        });
    }
});

test('it renders', function(assert) {
    assert.expect(2);
    assert.equal(component._state, 'preRender', 'It pre-rendered');
    this.render();
    assert.equal(component._state, 'inDOM', 'It is in the DOM');
});

test('it displays table headers', function(assert) {
    this.render();

    var $component = this.$();
    assert.equal($component.find('thead tr:eq(0) th:eq(0)').text().trim(), 'Username', 'Table Filter - Username');
    assert.equal($component.find('thead tr:eq(0) th:eq(1)').text().trim(), 'Email', 'Table Filter - Email');
    assert.equal($component.find('thead tr:eq(0) th:eq(2)').text().trim(), 'First Name', 'Table Filter - First Name');
    assert.equal($component.find('thead tr:eq(0) th:eq(3)').text().trim(), 'Last Name', 'Table Filter - Last Name');
    assert.equal($component.find('thead tr:eq(0) th:eq(4)').text().trim(), 'Last Updated', 'Table Filter - Last Updated');
    assert.equal($component.find('thead tr:eq(0) th:eq(5)').text().trim(), 'Actions', 'Table Filter - Actions');
});

test('it displays table header filters', function(assert) {
    this.render(hbs`
        {{#ember-table-jsonapi columns=columns bindModel=model hasActions="true" as |section|}}
            {{#if section.isBody}}
                {{#each users as |row|}}

                        {{row.username}}
                        {{row.emailAddress}}
                        {{row.firstName}}
                        {{row.lastName}}

                            {{#if row.updatedAt}}
                                {{moment-format row.updatedAt 'MM/DD/YYYY'}}
                            {{else}}
                                {{moment-format row.createdAt 'MM/DD/YYYY'}}
                            {{/if}}

                            {{#link-to "index" class="btn btn-default btn-xs" role="button"}}
                                Edit
                            {{/link-to}}

                {{/each}}
            {{/if}}
        {{/ember-table-jsonapi}}
    `);

    var $component = this.$();

    // TODO write test to check column input filter
    assert.equal($component.find('thead tr:eq(1) th:eq(0)').text().trim(), 'Username', 'Table Filter - Username');
});
<commit_msg>Simplify unit testing<commit_after>import { moduleForComponent, test } from 'ember-qunit';

let component;
let model = [
    {
        id: 1,
        username: 'YippieKiYay',
        emailAddress: 'john.mcclane@domain.com',
        firstName: 'John',
        lastName: 'McClane',
        isAdmin: true,
        createdAt: '2017-01-01',
        updatedAt: '2017-01-02'
    }, {
        id: 2,
        username: 'HanSolo',
        emailAddress: 'smugglerOne@domain.com',
        firstName: 'Han',
        lastName: 'Solo',
        isAdmin: false,
        createdAt: '2015-12-18',
        updatedAt: '2015-12-19'
    }
];
let columns = [
    {
        property: 'username',
        label: 'Username',
        type: 'text',
        defaultSort: 'username',
    },
    {
        property: 'email-address',
        label: 'Email',
        type: 'text',
    },
    {
        property: 'first-name',
        label: 'First Name',
        type: 'text',
    },
    {
        property: 'last-name',
        label: 'Last Name',
        type: 'text',
    },
    {
        property: 'updated-at',
        label: 'Last Updated',
        type: 'date',
    },
];

moduleForComponent('ember-table-jsonapi', 'Unit | Component | ember table jsonapi', {
    unit: true,
    needs: ['helper:dot-to-dash-filter', 'component:ember-table-jsonapi-filter', 'helper:and', 'component:pagination-pager'],
    beforeEach: function() {
        component = this.subject({
            bindModel: model,
            columns: columns,
            hasActions: 'true',
        });
    }
});

test('it renders', function(assert) {
    assert.expect(2);
    assert.equal(component._state, 'preRender', 'It pre-rendered');
    this.render();
    assert.equal(component._state, 'inDOM', 'It is in the DOM');
});

test('it displays table headers', function(assert) {
    this.render();

    var $component = this.$();
    assert.equal($component.find('thead tr:eq(0) th:eq(0)').text().trim(), 'Username', 'Table Filter - Username');
    assert.equal($component.find('thead tr:eq(0) th:eq(1)').text().trim(), 'Email', 'Table Filter - Email');
    assert.equal($component.find('thead tr:eq(0) th:eq(2)').text().trim(), 'First Name', 'Table Filter - First Name');
    assert.equal($component.find('thead tr:eq(0) th:eq(3)').text().trim(), 'Last Name', 'Table Filter - Last Name');
    assert.equal($component.find('thead tr:eq(0) th:eq(4)').text().trim(), 'Last Updated', 'Table Filter - Last Updated');
    assert.equal($component.find('thead tr:eq(0) th:eq(5)').text().trim(), 'Actions', 'Table Filter - Actions');
});
<|endoftext|>


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

/**
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var assertInstanceOf = require( 'PHET_IO/assertions/assertInstanceOf' );
  var phetio = require( 'PHET_IO/phetio' );
  var phetioInherit = require( 'PHET_IO/phetioInherit' );
  var phetioNamespace = require( 'PHET_IO/phetioNamespace' );
  var SimIFrameAPI = require( 'PHET_IO/SimIFrameAPI' );
  var TFunctionWrapper = require( 'PHET_IO/types/TFunctionWrapper' );
  var TObject = require( 'PHET_IO/types/TObject' );
  var toEventOnEmit = require( 'PHET_IO/events/toEventOnEmit' );
  var TString = require( 'PHET_IO/types/TString' );
  var TVoid = require( 'PHET_IO/types/TVoid' );

  /**
   * Wrapper type for phet/joist's Sim class.
   * @param sim
   * @param phetioID
   * @constructor
   */
  function TSim( sim, phetioID ) {
    TObject.call( this, sim, phetioID );
    assertInstanceOf( sim, phet.joist.Sim );

    toEventOnEmit( sim.startedSimConstructorEmitter, sim.endedSimConstructorEmitter, 'model', phetioID, TSim, 'simStarted',
      function( value ) {
        return {
          sessionID: value.sessionID,
          repoName: value.repoName,
          simName: value.simName,
          simVersion: value.simVersion,
          url: value.url,
          userAgent: window.navigator.userAgent,
          randomSeed: value.randomSeed,
          provider: 'PhET Interactive Simulations, University of Colorado Boulder' // See #137
        };
      } );

    // Store a reference to the sim so that subsequent calls will be simpler.  PhET-iO only works with a single sim.
    phetio.sim = sim;
    SimIFrameAPI.triggerSimInitialized();
    sim.onStatic( 'simulationStarted', function() {
      phetio.simulationStarted();
    } );
  }

  phetioInherit( TObject, 'TSim', TSim, {

    disableRequestAnimationFrame: {
      returnType: TVoid,
      parameterTypes: [],
      implementation: function() {
        this.instance.disableRequestAnimationFrame();
      },
      documentation: 'Prevents the simulation from animating/updating'
    },

    addEventListener: {
      returnType: TVoid,
      parameterTypes: [ TString, TFunctionWrapper( TVoid, [ TString, TFunctionWrapper( TVoid, [] ) ] ) ],
      implementation: function( eventName, listener ) {
        this.instance.onStatic( eventName, listener );
      },
      documentation: 'Add an event listener to the sim instance'
    },

    getScreenshotDataURL: {
      returnType: TString,
      parameterTypes: [],
      implementation: function() {
        return window.phet.joist.ScreenshotGenerator.generateScreenshot( this.instance );
      },
      documentation: 'Gets a base64 representation of a screenshot of the simulation as a data url'
    }
  }, {
    documentation: 'The type for the simulation instance',
    events: [
      'simStarted'
    ]
  } );

  phetioNamespace.register( 'TSim', TSim );

  return TSim;
} );
<commit_msg>Use Emitter instead of trigger, see https://github.com/phetsims/joist/issues/368<commit_after>// Copyright 2016, University of Colorado Boulder

/**
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var assertInstanceOf = require( 'PHET_IO/assertions/assertInstanceOf' );
  var phetio = require( 'PHET_IO/phetio' );
  var phetioInherit = require( 'PHET_IO/phetioInherit' );
  var phetioNamespace = require( 'PHET_IO/phetioNamespace' );
  var SimIFrameAPI = require( 'PHET_IO/SimIFrameAPI' );
  var TFunctionWrapper = require( 'PHET_IO/types/TFunctionWrapper' );
  var TObject = require( 'PHET_IO/types/TObject' );
  var toEventOnEmit = require( 'PHET_IO/events/toEventOnEmit' );
  var TString = require( 'PHET_IO/types/TString' );
  var TVoid = require( 'PHET_IO/types/TVoid' );

  /**
   * Wrapper type for phet/joist's Sim class.
   * @param sim
   * @param phetioID
   * @constructor
   */
  function TSim( sim, phetioID ) {
    TObject.call( this, sim, phetioID );
    assertInstanceOf( sim, phet.joist.Sim );

    toEventOnEmit( sim.startedSimConstructorEmitter, sim.endedSimConstructorEmitter, 'model', phetioID, TSim, 'simStarted',
      function( value ) {
        return {
          sessionID: value.sessionID,
          repoName: value.repoName,
          simName: value.simName,
          simVersion: value.simVersion,
          url: value.url,
          userAgent: window.navigator.userAgent,
          randomSeed: value.randomSeed,
          provider: 'PhET Interactive Simulations, University of Colorado Boulder' // See #137
        };
      } );

    // Store a reference to the sim so that subsequent calls will be simpler.  PhET-iO only works with a single sim.
    phetio.sim = sim;
    SimIFrameAPI.triggerSimInitialized();
    sim.endedSimConstructorEmitter.addListener( function() {
      phetio.simulationStarted();
    } );
  }

  phetioInherit( TObject, 'TSim', TSim, {

    disableRequestAnimationFrame: {
      returnType: TVoid,
      parameterTypes: [],
      implementation: function() {
        this.instance.disableRequestAnimationFrame();
      },
      documentation: 'Prevents the simulation from animating/updating'
    },

    addEventListener: {
      returnType: TVoid,
      parameterTypes: [ TString, TFunctionWrapper( TVoid, [ TString, TFunctionWrapper( TVoid, [] ) ] ) ],
      implementation: function( eventName, listener ) {
        this.instance.onStatic( eventName, listener );
      },
      documentation: 'Add an event listener to the sim instance'
    },

    getScreenshotDataURL: {
      returnType: TString,
      parameterTypes: [],
      implementation: function() {
        return window.phet.joist.ScreenshotGenerator.generateScreenshot( this.instance );
      },
      documentation: 'Gets a base64 representation of a screenshot of the simulation as a data url'
    }
  }, {
    documentation: 'The type for the simulation instance',
    events: [
      'simStarted'
    ]
  } );

  phetioNamespace.register( 'TSim', TSim );

  return TSim;
} );
<|endoftext|>


<commit_before>/**
 * Mail
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Christoph Wurst <christoph@winzerhof-wurst.at>
 * @author Luc Calaresu <dev@calaresu.com>
 * @copyright Christoph Wurst 2015
 */

define(function(require) {
	'use strict';

	var Handlebars = require('handlebars');
	var Marionette = require('marionette');
	var Radio = require('radio');
	var AttachmentTemplate = require('text!templates/attachment.html');

	return Marionette.View.extend({
		tagName: 'li',
		template: Handlebars.compile(AttachmentTemplate),
		ui: {
			attachmentName: ".new-message-attachment-name"
		},
		events: {
			'click .icon-delete': 'removeAttachment'
		},
		modelEvents: {
			'change:progress': 'onProgress',
			'change:uploadStatus': 'onUploadStatus'
		},
		onRender: function() {
			var uploadRequest = this.model.get('uploadRequest');
			if (uploadRequest) {
				/* If upload, init the progressbar with the initial and max value  */
				this.ui.attachmentName.progressbar({value: 0, max: 1});
				// Remove two jQuery styling classes that make it ugly
				// and add a blue text while uploading
				this.ui.attachmentName
					.removeClass('ui-progressbar')
					.removeClass('ui-widget-content')
					.addClass('upload-ongoing');
			}
		},

		/**
		 * Called when the user clicked on the wastebasket.
		 */
		removeAttachment: function() {
			/* If we are trying to delete a still-uploading attachment, */
			/* we have to abort the request first */
			Radio.attachment.request('upload:abort', this.model);
			this.model.collection.remove(this.model);
		},

		/**
		 * Triggered when the attachment progress value changed
		 */
		onProgress: function() {
			/* Update the ProgressBar with the new model value */
			var progressValue = this.model.get('progress');
			this.ui.attachmentName.progressbar('option', 'value', progressValue);
		},

		/**
		 * Triggered when the attachment upload status has changed
		 */
		onUploadStatus: function() {
			switch(this.model.get('uploadStatus')) {
				case 1:     // uploading
					this.ui.attachmentName.addClass('upload-ongoing');
					break;
				case 2:     // error
					/* An error occurred, we make the filename and the progressbar red */
					this.ui.attachmentName
						.removeClass('upload-ongoing')
						.addClass('upload-warning');
					break;
				case 3:     // success
					/* remove the 'ongoing' class  */
					this.ui.attachmentName.removeClass('upload-ongoing');
					/* If everything went well, we just fade out the progressbar */
					this.ui.attachmentName.find('.ui-progressbar-value').fadeOut();
					break;
			}
		}
	});
});
<commit_msg>Some minor style corrections for travis<commit_after>/**
 * Mail
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Christoph Wurst <christoph@winzerhof-wurst.at>
 * @author Luc Calaresu <dev@calaresu.com>
 * @copyright Christoph Wurst 2015
 */

define(function(require) {
	'use strict';

	var Handlebars = require('handlebars');
	var Marionette = require('marionette');
	var Radio = require('radio');
	var AttachmentTemplate = require('text!templates/attachment.html');

	return Marionette.View.extend({
		tagName: 'li',
		template: Handlebars.compile(AttachmentTemplate),
		ui: {
			attachmentName: '.new-message-attachment-name'
		},
		events: {
			'click .icon-delete': 'removeAttachment'
		},
		modelEvents: {
			'change:progress': 'onProgress',
			'change:uploadStatus': 'onUploadStatus'
		},
		onRender: function() {
			var uploadRequest = this.model.get('uploadRequest');
			if (uploadRequest) {
				/* If upload, init the progressbar with the initial and max value  */
				this.ui.attachmentName.progressbar({value: 0, max: 1});
				// Remove two jQuery styling classes that make it ugly
				// and add a blue text while uploading
				this.ui.attachmentName
					.removeClass('ui-progressbar')
					.removeClass('ui-widget-content')
					.addClass('upload-ongoing');
			}
		},

		/**
		 * Called when the user clicked on the wastebasket.
		 */
		removeAttachment: function() {
			/* If we are trying to delete a still-uploading attachment, */
			/* we have to abort the request first */
			Radio.attachment.request('upload:abort', this.model);
			this.model.collection.remove(this.model);
		},

		/**
		 * Triggered when the attachment progress value changed
		 */
		onProgress: function() {
			/* Update the ProgressBar with the new model value */
			var progressValue = this.model.get('progress');
			this.ui.attachmentName.progressbar('option', 'value', progressValue);
		},

		/**
		 * Triggered when the attachment upload status has changed
		 */
		onUploadStatus: function() {
			switch (this.model.get('uploadStatus')) {
				case 1:     // uploading
					this.ui.attachmentName.addClass('upload-ongoing');
					break;
				case 2:     // error
					/* An error occurred, we make the filename and the progressbar red */
					this.ui.attachmentName
						.removeClass('upload-ongoing')
						.addClass('upload-warning');
					break;
				case 3:     // success
					/* remove the 'ongoing' class  */
					this.ui.attachmentName.removeClass('upload-ongoing');
					/* If everything went well, we just fade out the progressbar */
					this.ui.attachmentName.find('.ui-progressbar-value').fadeOut();
					break;
			}
		}
	});
});
<|endoftext|>


<commit_before>
var RegExpTree = require('regexp-tree');
module.exports =
UXRegExp = (function() {

  var use_collect_groups_with_same_name = 1;

  var PREFIX_NON_CAPTURING = '$$';

  var debug = 0;

  var show = function(x) {
    console.log(x);
  };

  var showt = function(x) {
    show(JSON.stringify(x, null, '  '));
  };

  var showo = function(x) {
    show(JSON.stringify(x));
  };

  //---------------------------------------------------------------------------- constructor

  function UXRegExp(re, options) {

    //if (debug >= 1) showo(['input expression', re, options]);

    var flags = '';
    var rtOptions = {};

    if(typeof options === 'string') {
      flags += options;
    } else if(typeof options === 'object') {
      if(options.flags) {
        flags += options.flags;
        delete options.flags;
      }
      if(options.debug) {
        debug = options.debug;
        delete options.debug;
      }
    }

    if(typeof re !== 'string') {
      re = re.toString();
    }

    // extract flags, set options and remove those not known by javascript

    var matches = /^\s*\/([\s\S]*)\/([a-z]*)\s*$/.exec(re);
    if (matches) {
      re = matches[1];
      flags += matches[2];
    }
    // escape '/'
    re = re.replace(/\//g,     '\\/');
    re = re.replace(/\\\\\//g, '\\/');

    // automatically use x-flag for regexp with newlines

    if (re.includes('\n')) {
      flags += 'x';
    }

    // santize flags (sort, uniq)

    flags = flags.split('')
                 .sort()
                 .filter(
                   function(e,i,a) {
                     return !i || e != a[i-1];
                   }
                 )
                 .join('');

    re = '/' + re + '/' + flags;

    showo(['after preprocess', re]);

    // build AST from re

    var ast = RegExpTree.parser.parse(re, rtOptions);

    //if(debug >= 3) showt(ast);

    // ensure all parts of alternatives (=sequences) are groups.
    //   this allows to determine the character positions
    //   by cummulating the lengths of preceding groups

    // these must be wrapped
    var toBeWrapped = function(node) {
      var result = ! (node.type === 'Group');
      //showo(['toBeWrapped', result, node.type, node.expression ? node.expression.type : node.value]);
      return result;
    }

    // these can be combined when wrapped
    var toBeCombined = function(node) {
      var result = toBeWrapped(node)
                      && ! (
                        node.type === 'Repetition'
                          && node.expression.type === 'Group'
                          && node.expression.capturing
                      );
      //showo(['toBeCombined', result, node.type, node.expression ? node.expression.type : node.value]);
      return result;
    }
    //var toBeCombined = toBeWrapped;
    //var toBeCombined = function(node) { return false; };

    // var unwrapped = RegExpTree.generate(ast);
    // if(debug >= 2) show('--------------------- unwrapped');
    // if(debug >= 2) show(unwrapped);

    RegExpTree.traverse(ast, {

      'Alternative': function(path) {

        // ignore if this was created by collecting wrapped nodes
        if(path.node.combined)
          return;

        //showo(['Alternative', path.node.expressions.map(function(x) {return [x.type, x.value]})]);
        var children = [];
        var collected = [];
        var nCollected = 0;
        var nDirect = 0;
        path.node.expressions.forEach( function(child) {
          //show([child.type, child.value, child.expression ? [child.expression.type, child.expression.value] : null]);
          if(toBeCombined(child)) {
            //showo(['collect', child.type, child.value]);
            collected.push(child);  // collect
            nCollected++;
          } else if(toBeWrapped(child)) {
            //showo(['wrap   ', child.type, child.value]);
            if(collected.length) children.push(collected);
            collected = [];
            children.push([child]); // single array item -> wrap!
            nCollected++;
          } else {
            //showo(['copy   ', child.type, child.value]);
            if(collected.length) children.push(collected);
            collected = [];
            children.push(child);   // no wrap
            nDirect++;
          }
        });
        // TODO: wrapping not really necessary after the last capturing group
        // to push all remaining objects without wrapping
        //Array.prototype.push.apply(children, collected);
        if(collected.length) children.push(collected);

        //showo([nCollected, nDirect]);
        if(1 || nCollected && nDirect) { // TODO: optimize groups in groups

          // clear all expressions
          path.node.expressions = [];

          children.forEach(function(child) {
            if(Array.isArray(child)) {
              // collected nodes have to be wrapped in group
              //showo(['child array', child.map(function(x) {return [x.type, x.value]})]);
              // add Group
              var groupPath = path.appendChild({
                type: 'Group',
                capturing: false,
                expression: null,
                wrapped: true
              });
              if(child.length > 1) {
                // add array of collected nodes to group
                var altPath = groupPath.setChild({
                  type: 'Alternative',
                  expressions: [],
                  combined: true
                });
                child.forEach(function(node) {
                  //showo(['append child alt', [node.type, node.value]]);
                  altPath.appendChild(node);
                });
              } else {
                // add single collected node to group
                //showo(['wrap single', child[0].type, child[0].value]);
                groupPath.setChild(child[0]);
              }
            } else {
              // add the node without wrapping
              //showo(['append child', [child.type, child.value]]);
              path.appendChild(child);
            }
          });
        }
      }
    });

    // var wrapped = RegExpTree.generate(ast);
    // if(debug >= 1) show('--------------------- wrapped');
    // if(debug >= 1) show(wrapped);

    // determine names of all groups (named and numbered)
    // find hierarchy of groups (collect an array of parent group names for each named group)

    getParentNames = function(path) {
      var parentNames = [];
      while (path) {
        path = path.getParent();
        if (path) {
          if (path.node.type === 'Group') {
            if (path.node.name) {
              parentNames.push(path.node.name);
            }
          }
        }
      }
      return parentNames;
    };

    var names = [null];
    var parents = {};
    var indexCaptureGroup = 1;
    var indexNonCaptureGroup = 1;

    RegExpTree.traverse(ast, {

      Group: function(path) {
        var node = path.node;
        var non_capturing = false;
        if (!node.name) {
          if(node.capturing) {
            node.name = indexCaptureGroup;
          } else {
            non_capturing = true;
            node.name = - (10000*(indexCaptureGroup-1) + indexNonCaptureGroup);
            indexNonCaptureGroup++;
          }
        }
        if (node.name) {
          names.push(node.name);
          if( ! non_capturing ) {
            indexCaptureGroup++;
            //indexNonCaptureGroup = 1;
          }
          parents[node.name] = getParentNames(path);
          //show([node.name, parents[node.name]]);
        }
        node.capturing = true;
        return;
      }
    });

    // remove names from all groups
    // set group numbers ofr named back references

    RegExpTree.traverse(ast, {
      Group: function(arg) {
        var node = arg.node;
        return delete node.name;
      },
      Backreference: function(arg) {
        var node = arg.node;
        node.kind = 'number';
        node.reference = names.indexOf(node.reference);
        node.number = node.reference;
        return delete node.name;
      }
    });

    this.names = names;
    this.parents = parents;
    //if(debug >= 3) show(names);
    //if(debug >= 3) show(parents);

    ast.flags = ast.flags.replace('x', '');
    var xre = RegExpTree.generate(ast);
    this.re = RegExpTree.toRegExp(xre);

    //showt(this);

    // if(debug >= 1) show('--------------------- re');
    // if(debug >= 1) show(this.re);
  }

  //---------------------------------------------------------------------------- exec

  UXRegExp.prototype.exec = function(text) {

    //if (debug >= 1) showo(text);

    var matches = this.re.exec(text);

    //if (debug >= 1) showo(matches);

    if (!matches)
      return null;

    var result = {
      input: text,
      groups: {},
      names: [],
      infos: {}
    };

    var setRootGroup = function(result, name, val, info) {
      result[name] = val;
      result.infos[name] = info;
    }

    var setGroup = function(result, name, val, info) {
      if(val != null) {
        if( use_collect_groups_with_same_name && result.groups[name] != null ) {
          if(Array.isArray(result.groups[name])) {
            result.groups[name].push(val);
            result.infos[name].push(info);
          } else {
            result.groups[name] = [result.groups[name], val];
            result.infos[name] = [result.infos[name], info];
          }
        } else {
          result.groups[name] = val;
          result.infos[name] = info;
        }
      }
      result.names.push(name);
    }

    var charIndexAll = matches.index;

    setRootGroup(result, 'all',
      matches[0],
      {index: charIndexAll}
    );
    setRootGroup(result, 'pre',
      matches.input.substring(0, charIndexAll),
      {index: 0}
    );
    setRootGroup(result, 'post',
      matches.input.substring(charIndexAll + matches[0].length),
      {index: charIndexAll + matches[0].length}
    );

    //if (debug >= 3) showo(result);

    // collect result groups as strings or groups according to original expression
    var position = [];
    var groupedMin = text.length;
    var groupedMax = 0;
    var next     = [charIndexAll];
    var lastLevel = 0;
    for (var i = 1; i < this.names.length; i++) {
      var name = this.names[i];
      var val = matches[i];
      var len = val ? val.length : 0;
      var level = (this.parents[name] || []).length;
      if( ! position[level] )
        position[level] = 0;
      var pos;
      if(level > lastLevel)
        pos = position[lastLevel];
      else
        pos = next[level];
      position[level] = pos;
      if(name && ! (typeof name === "number" && name < 0)) {
        if(pos < groupedMin)
          groupedMin = pos;
        if(pos + len > groupedMax)
          groupedMax = pos + len;
        setGroup(result, name, val, {index: pos});
      }
      next[level] = pos + len;
      //if (debug >= 2) show(['   '.repeat(level), name, pos, next[level]]);
      lastLevel = level;
    }

    setRootGroup(result, 'grouped',
      text.slice(groupedMin, groupedMax),
      {index: groupedMin}
    );

    //if (debug >= 1) showt(result);

    return result;
  };

  //---------------------------------------------------------------------------- test

  UXRegExp.prototype.test = function(text) {

    return this.re.test(text);
  };

  UXRegExp.show  = show;
  UXRegExp.showo = showo;
  UXRegExp.showt = showt;

  return UXRegExp;

})();
<commit_msg>disable debug output<commit_after>
var RegExpTree = require('regexp-tree');
module.exports =
UXRegExp = (function() {

  var use_collect_groups_with_same_name = 1;

  var PREFIX_NON_CAPTURING = '$$';

  var debug = 0;

  var show = function(x) {
    console.log(x);
  };

  var showt = function(x) {
    show(JSON.stringify(x, null, '  '));
  };

  var showo = function(x) {
    show(JSON.stringify(x));
  };

  //---------------------------------------------------------------------------- constructor

  function UXRegExp(re, options) {

    //if (debug >= 1) showo(['input expression', re, options]);

    var flags = '';
    var rtOptions = {};

    if(typeof options === 'string') {
      flags += options;
    } else if(typeof options === 'object') {
      if(options.flags) {
        flags += options.flags;
        delete options.flags;
      }
      if(options.debug) {
        debug = options.debug;
        delete options.debug;
      }
    }

    if(typeof re !== 'string') {
      re = re.toString();
    }

    // extract flags, set options and remove those not known by javascript

    var matches = /^\s*\/([\s\S]*)\/([a-z]*)\s*$/.exec(re);
    if (matches) {
      re = matches[1];
      flags += matches[2];
    }
    // escape '/'
    re = re.replace(/\//g,     '\\/');
    re = re.replace(/\\\\\//g, '\\/');

    // automatically use x-flag for regexp with newlines

    if (re.includes('\n')) {
      flags += 'x';
    }

    // santize flags (sort, uniq)

    flags = flags.split('')
                 .sort()
                 .filter(
                   function(e,i,a) {
                     return !i || e != a[i-1];
                   }
                 )
                 .join('');

    re = '/' + re + '/' + flags;

    //showo(['after preprocess', re]);

    // build AST from re

    var ast = RegExpTree.parser.parse(re, rtOptions);

    //if(debug >= 3) showt(ast);

    // ensure all parts of alternatives (=sequences) are groups.
    //   this allows to determine the character positions
    //   by cummulating the lengths of preceding groups

    // these must be wrapped
    var toBeWrapped = function(node) {
      var result = ! (node.type === 'Group');
      //showo(['toBeWrapped', result, node.type, node.expression ? node.expression.type : node.value]);
      return result;
    }

    // these can be combined when wrapped
    var toBeCombined = function(node) {
      var result = toBeWrapped(node)
                      && ! (
                        node.type === 'Repetition'
                          && node.expression.type === 'Group'
                          && node.expression.capturing
                      );
      //showo(['toBeCombined', result, node.type, node.expression ? node.expression.type : node.value]);
      return result;
    }
    //var toBeCombined = toBeWrapped;
    //var toBeCombined = function(node) { return false; };

    // var unwrapped = RegExpTree.generate(ast);
    // if(debug >= 2) show('--------------------- unwrapped');
    // if(debug >= 2) show(unwrapped);

    RegExpTree.traverse(ast, {

      'Alternative': function(path) {

        // ignore if this was created by collecting wrapped nodes
        if(path.node.combined)
          return;

        //showo(['Alternative', path.node.expressions.map(function(x) {return [x.type, x.value]})]);
        var children = [];
        var collected = [];
        var nCollected = 0;
        var nDirect = 0;
        path.node.expressions.forEach( function(child) {
          //show([child.type, child.value, child.expression ? [child.expression.type, child.expression.value] : null]);
          if(toBeCombined(child)) {
            //showo(['collect', child.type, child.value]);
            collected.push(child);  // collect
            nCollected++;
          } else if(toBeWrapped(child)) {
            //showo(['wrap   ', child.type, child.value]);
            if(collected.length) children.push(collected);
            collected = [];
            children.push([child]); // single array item -> wrap!
            nCollected++;
          } else {
            //showo(['copy   ', child.type, child.value]);
            if(collected.length) children.push(collected);
            collected = [];
            children.push(child);   // no wrap
            nDirect++;
          }
        });
        // TODO: wrapping not really necessary after the last capturing group
        // to push all remaining objects without wrapping
        //Array.prototype.push.apply(children, collected);
        if(collected.length) children.push(collected);

        //showo([nCollected, nDirect]);
        if(1 || nCollected && nDirect) { // TODO: optimize groups in groups

          // clear all expressions
          path.node.expressions = [];

          children.forEach(function(child) {
            if(Array.isArray(child)) {
              // collected nodes have to be wrapped in group
              //showo(['child array', child.map(function(x) {return [x.type, x.value]})]);
              // add Group
              var groupPath = path.appendChild({
                type: 'Group',
                capturing: false,
                expression: null,
                wrapped: true
              });
              if(child.length > 1) {
                // add array of collected nodes to group
                var altPath = groupPath.setChild({
                  type: 'Alternative',
                  expressions: [],
                  combined: true
                });
                child.forEach(function(node) {
                  //showo(['append child alt', [node.type, node.value]]);
                  altPath.appendChild(node);
                });
              } else {
                // add single collected node to group
                //showo(['wrap single', child[0].type, child[0].value]);
                groupPath.setChild(child[0]);
              }
            } else {
              // add the node without wrapping
              //showo(['append child', [child.type, child.value]]);
              path.appendChild(child);
            }
          });
        }
      }
    });

    // var wrapped = RegExpTree.generate(ast);
    // if(debug >= 1) show('--------------------- wrapped');
    // if(debug >= 1) show(wrapped);

    // determine names of all groups (named and numbered)
    // find hierarchy of groups (collect an array of parent group names for each named group)

    getParentNames = function(path) {
      var parentNames = [];
      while (path) {
        path = path.getParent();
        if (path) {
          if (path.node.type === 'Group') {
            if (path.node.name) {
              parentNames.push(path.node.name);
            }
          }
        }
      }
      return parentNames;
    };

    var names = [null];
    var parents = {};
    var indexCaptureGroup = 1;
    var indexNonCaptureGroup = 1;

    RegExpTree.traverse(ast, {

      Group: function(path) {
        var node = path.node;
        var non_capturing = false;
        if (!node.name) {
          if(node.capturing) {
            node.name = indexCaptureGroup;
          } else {
            non_capturing = true;
            node.name = - (10000*(indexCaptureGroup-1) + indexNonCaptureGroup);
            indexNonCaptureGroup++;
          }
        }
        if (node.name) {
          names.push(node.name);
          if( ! non_capturing ) {
            indexCaptureGroup++;
            //indexNonCaptureGroup = 1;
          }
          parents[node.name] = getParentNames(path);
          //show([node.name, parents[node.name]]);
        }
        node.capturing = true;
        return;
      }
    });

    // remove names from all groups
    // set group numbers ofr named back references

    RegExpTree.traverse(ast, {
      Group: function(arg) {
        var node = arg.node;
        return delete node.name;
      },
      Backreference: function(arg) {
        var node = arg.node;
        node.kind = 'number';
        node.reference = names.indexOf(node.reference);
        node.number = node.reference;
        return delete node.name;
      }
    });

    this.names = names;
    this.parents = parents;
    //if(debug >= 3) show(names);
    //if(debug >= 3) show(parents);

    ast.flags = ast.flags.replace('x', '');
    var xre = RegExpTree.generate(ast);
    this.re = RegExpTree.toRegExp(xre);

    //showt(this);

    // if(debug >= 1) show('--------------------- re');
    // if(debug >= 1) show(this.re);
  }

  //---------------------------------------------------------------------------- exec

  UXRegExp.prototype.exec = function(text) {

    //if (debug >= 1) showo(text);

    var matches = this.re.exec(text);

    //if (debug >= 1) showo(matches);

    if (!matches)
      return null;

    var result = {
      input: text,
      groups: {},
      names: [],
      infos: {}
    };

    var setRootGroup = function(result, name, val, info) {
      result[name] = val;
      result.infos[name] = info;
    }

    var setGroup = function(result, name, val, info) {
      if(val != null) {
        if( use_collect_groups_with_same_name && result.groups[name] != null ) {
          if(Array.isArray(result.groups[name])) {
            result.groups[name].push(val);
            result.infos[name].push(info);
          } else {
            result.groups[name] = [result.groups[name], val];
            result.infos[name] = [result.infos[name], info];
          }
        } else {
          result.groups[name] = val;
          result.infos[name] = info;
        }
      }
      result.names.push(name);
    }

    var charIndexAll = matches.index;

    setRootGroup(result, 'all',
      matches[0],
      {index: charIndexAll}
    );
    setRootGroup(result, 'pre',
      matches.input.substring(0, charIndexAll),
      {index: 0}
    );
    setRootGroup(result, 'post',
      matches.input.substring(charIndexAll + matches[0].length),
      {index: charIndexAll + matches[0].length}
    );

    //if (debug >= 3) showo(result);

    // collect result groups as strings or groups according to original expression
    var position = [];
    var groupedMin = text.length;
    var groupedMax = 0;
    var next     = [charIndexAll];
    var lastLevel = 0;
    for (var i = 1; i < this.names.length; i++) {
      var name = this.names[i];
      var val = matches[i];
      var len = val ? val.length : 0;
      var level = (this.parents[name] || []).length;
      if( ! position[level] )
        position[level] = 0;
      var pos;
      if(level > lastLevel)
        pos = position[lastLevel];
      else
        pos = next[level];
      position[level] = pos;
      if(name && ! (typeof name === "number" && name < 0)) {
        if(pos < groupedMin)
          groupedMin = pos;
        if(pos + len > groupedMax)
          groupedMax = pos + len;
        setGroup(result, name, val, {index: pos});
      }
      next[level] = pos + len;
      //if (debug >= 2) show(['   '.repeat(level), name, pos, next[level]]);
      lastLevel = level;
    }

    setRootGroup(result, 'grouped',
      text.slice(groupedMin, groupedMax),
      {index: groupedMin}
    );

    //if (debug >= 1) showt(result);

    return result;
  };

  //---------------------------------------------------------------------------- test

  UXRegExp.prototype.test = function(text) {

    return this.re.test(text);
  };

  UXRegExp.show  = show;
  UXRegExp.showo = showo;
  UXRegExp.showt = showt;

  return UXRegExp;

})();
<|endoftext|>


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

  function debug() {
    console.log(arguments);
  }

  function skip() {}

  var states = {
    PENDING: 0,
    FULFILLED: 1,
    REJECTED: 2
  };

  var vPromise = function (fn) {
    this._state = states.PENDING;
    this.value = null;
    var that = this;

    var onFulfilled = function (resolve) {
      if (typeof resolve !== 'function') { // 2.2.1
        return;
      }

      if (that._state !== states.PENDING) {
        that._state = states.FULFILLED;
        resolve(that.value);
      }
    };

    var onReject = function (reject, reason) {
      if (typeof reject !== 'function') { // 2.2.1
        return;
      }
      if (that._state !== states.PENDING) {
        that._state = states.REJECTED;
        reject(reason);
      }
    };

    var handle = function (resolve, reject) {
      if (that._state === states.PENDING) {
        return;
      }

      try {
        fn(onFulfilled(resolve), onReject(reject));
      } catch (e) {
        debug(e);
      }
    };

    if (fn !== skip) {
      fn(function (value) {
        that.value = value;
        setTimeout(function () {
          if (that._state !== states.PENDING) {
            return;
          }
          that._resolve(value);
          that._state = states.FULFILLED;
         }, 1);
      },
      function (reason) {
        that.reason = reason;
      });
    }

    this.then = function (resolve, reject) {
      if (that._state === states.PENDING) {
        that._resolve = resolve;
        that._reject = reject;
        return;
      }
      var next = new vPromise(fn);
      handle(resolve, reject, next);
      next._state = -1; // placeholder
      return next;
    };

    this.catch = function (fn) {
    };

    return this;
  };

  vPromise.resolve = function (value) {
    var skipped = new vPromise(skip);
    return doResolve(skipped, value);
  };

  function doResolve(skipped, value) {
    skipped._state = states.FULFILLED;
    skipped.value = value;
    return skipped;
  }

  vPromise.reject = function (reason) {
    var skipped = new vPromise(skip);
    return doReject(skipped, reason);
  };

  function doReject(skipped, reason) {
    skipped._state = states.REJECTED;
    skipped.reason = reason;
    return skipped;
  }

  if (typeof module != 'undefined') {
    module.exports = vPromise;
  }

}());
<commit_msg>Get 2.2.3 to pass<commit_after>(function () {
  'use strict';

  function debug() {
    console.log(arguments);
  }

  function skip() {}

  var states = {
    PENDING: 0,
    FULFILLED: 1,
    REJECTED: 2
  };

  var vPromise = function (fn) {
    this._state = states.PENDING;
    this.value = null;
    var that = this;

    var onFulfilled = function (resolve) {
      if (typeof resolve !== 'function') { // 2.2.1
        return;
      }

      if (that._state !== states.PENDING) {
        that._state = states.FULFILLED;
        resolve(that.value);
      }
    };

    var onReject = function (reject, reason) {
      if (typeof reject !== 'function') { // 2.2.1
        return;
      }
      if (that._state !== states.PENDING) {
        that._state = states.REJECTED;
        reject(reason);
      }
    };

    var handle = function (resolve, reject) {
      if (that._state === states.PENDING) {
        return;
      }

      try {
        fn(onFulfilled(resolve), onReject(reject, that.reason));
      } catch (e) {
        debug(e);
      }
    };

    if (fn !== skip) {
      fn(function (value) {
        that.value = value;
        setTimeout(function () {
          if (that._state !== states.PENDING) {
            return;
          }
          that._resolve(value);
          that._state = states.FULFILLED;
         }, 1);
      },
      function (reason) {
        that.reason = reason;
        setTimeout(function () {
          if (that._state !== states.PENDING) {
            return;
          }
          that._reject(reason);
          that._state = states.REJECTED;
         }, 1);
      });
    }

    this.then = function (resolve, reject) {
      if (that._state === states.PENDING) {
        that._resolve = resolve;
        that._reject = reject;
        return;
      }

      var next = new vPromise(fn);
      handle(resolve, reject);
      next._state = -1; // placeholder
      return next;
    };

    this.catch = function (fn) {
    };

    return this;
  };

  vPromise.resolve = function (value) {
    var skipped = new vPromise(skip);
    return doResolve(skipped, value);
  };

  function doResolve(skipped, value) {
    skipped._state = states.FULFILLED;
    skipped.value = value;
    return skipped;
  }

  vPromise.reject = function (reason) {
    var skipped = new vPromise(skip);
    return doReject(skipped, reason);
  };

  function doReject(skipped, reason) {
    skipped._state = states.REJECTED;
    skipped.reason = reason;
    return skipped;
  }

  if (typeof module != 'undefined') {
    module.exports = vPromise;
  }

}());
<|endoftext|>


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

  function skip() { return function (){} }

  var toArray = function (args) {
    return Array.prototype.slice.call(args, 0);
  };

  var isObject = function (obj) {
    return obj.toString() == "[object Object]";
  };

  var isFunction = function (func) {
    return typeof func === "function";
  }

  var states = {
    PENDING: 0,
    FULFILLED: 1,
    REJECTED: 2,
    PUSHEDFULFILLED: 3,
    PUSHEDREJECTED: 4
  };

  function asap(cb) {
    setTimeout(cb, 1);
  }

  var run = function (next, val) {
    if (next.status !== states.PENDING) {
      return;
    }
    next.status = states.FULFILLED;
    next.value = next(val);
    return next.value;
  };

  var startChain = function () {
    var ii;
    var chain = this.chain;
    var chainLength = chain.length;
    var val;

    if (this._state == states.PUSHEDFULFILLED) {
      this._state = states.FULFILLED;
      val = this.value;
    } else {
      //val = ;
    }
    for (ii = 0; ii < chainLength; ii++) {
      run(chain[ii], val);
    }
  };

  var _resolve = function (promise, x) {
    if (promise === x) {
      throw new TypeError("promise and x can not be same object");
    }
    if (isFunction(x) || isObject(x)) {
      var then = x.then; // TODO 2.3.3.2
    }

    if (isFunction(then)) {
      var called = false;
      then.call(x, function (y) {
        if (called) {
          return;
        }
        called = true;
        _resolve(promise, y);
      }, function (r) {
        if (called) {
          return;
        }
        called = true;
        _reject(promise, r);
      });
    }
  };

  var pushOnFulfilled = function(onFulfilled, onRejected) {
    if (onFulfilled.status == states.PENDING) {
      this.chain.push(onFulfilled);
    }
  };

  var vPromise = function (fn) {
    this._state = states.PENDING;
    var value = null;
    this.chain = [];
    var that = this;

    if (fn !== skip) {
      fn(function (val) {
        that.value = val;
        that._state = states.PUSHEDFULFILLED;
      }, function () {

      });
    }

    this.then = function (resolve, reject) {
      var vP = new vPromise(skip);
      vP._state = states.PENDING;
      vP.chain = this.chain;
      var onFulfilled = function (val) {
        return resolve(val);
      };
      onFulfilled.status = states.PENDING;
      onFulfilled.vP = vP;
      pushOnFulfilled.call(that, onFulfilled, reject);
      startChain.call(vP);
      return vP;
    };

    return this;
  };

  vPromise.resolve = function (value) {
    var vP = new vPromise();
    vP._state = states.FULFILLED;
    vP.value = value;
    return vP;
  };

  vPromise.reject = function (reason) {
    var vP = new vPromise();
    vP.reject(reason);
    return vP;
  };

  if (typeof module != 'undefined') {
    module.exports = vPromise;
  }

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

  function skip() { return function (){} }

  var isObject = function (obj) {
    return obj.toString() == "[object Object]";
  };

  var isFunction = function (func) {
    return typeof func === "function";
  }

  var states = {
    PENDING: 0,
    FULFILLED: 1,
    REJECTED: 2,
    PUSHEDFULFILLED: 3,
    PUSHEDREJECTED: 4
  };

  function asap(cb) {
    setTimeout(cb, 1);
  }

  var run = function (next, val) {
    if (next.status !== states.PENDING) {
      return;
    }
    next.status = states.FULFILLED;
    next.value = next(val);
    return next.value;
  };

  var startChain = function () {
    var ii;
    var chain = this.chain;
    var chainLength = chain.length;
    var val;

    if (this._state == states.PUSHEDFULFILLED) {
      this._state = states.FULFILLED;
      val = this.value;
    } else {
      //val = ;
    }
    for (ii = 0; ii < chainLength; ii++) {
      run(chain[ii], val);
    }
  };

  var _resolve = function (promise, x) {
    if (promise === x) {
      throw new TypeError("promise and x can not be same object");
    }
    if (isFunction(x) || isObject(x)) {
      var then = x.then; // TODO 2.3.3.2
    }

    if (isFunction(then)) {
      var called = false;
      then.call(x, function (y) {
        if (called) {
          return;
        }
        called = true;
        _resolve(promise, y);
      }, function (r) {
        if (called) {
          return;
        }
        called = true;
        _reject(promise, r);
      });
    }
  };

  var pushOnFulfilled = function(onFulfilled, onRejected) {
    if (onFulfilled.status == states.PENDING) {
      this.chain.push(onFulfilled);
    }
  };

  var vPromise = function (fn) {
    this._state = states.PENDING;
    var value = null;
    this.chain = [];
    var that = this;

    if (fn !== skip) {
      fn(function (val) {
        that.value = val;
        that._state = states.PUSHEDFULFILLED;
      }, function () {

      });
    }

    this.then = function (resolve, reject) {
      var vP = new vPromise(skip);
      vP._state = states.PENDING;
      vP.chain = this.chain;
      var onFulfilled = function (val) {
        return resolve(val);
      };
      onFulfilled.status = states.PENDING;
      onFulfilled.vP = vP;
      pushOnFulfilled.call(that, onFulfilled, reject);
      startChain.call(vP);
      return vP;
    };

    return this;
  };

  vPromise.resolve = function (value) {
    var vP = new vPromise();
    vP._state = states.FULFILLED;
    vP.value = value;
    return vP;
  };

  vPromise.reject = function (reason) {
    var vP = new vPromise();
    vP.reject(reason);
    return vP;
  };

  if (typeof module != 'undefined') {
    module.exports = vPromise;
  }

}());
<|endoftext|>