<commit_before>import Mirage from 'ember-cli-mirage';
import { trait } from 'ember-cli-mirage';

import {module, test} from 'qunit';

module('Unit | Factory', function() {
  test('it exists', function(assert) {
    assert.ok(Mirage.Factory);
  });

  test('the base class builds empty objects', function(assert) {
    let f = new Mirage.Factory();
    let data = f.build();

    assert.deepEqual(data, {});
  });

  test('a noop extension builds empty objects', function(assert) {
    let EmptyFactory = Mirage.Factory.extend();
    let f = new EmptyFactory();
    let data = f.build();

    assert.deepEqual(data, {});
  });

  test('it works with strings, numbers and booleans', function(assert) {
    let AFactory = Mirage.Factory.extend({
      name: 'Sam',
      age: 28,
      alive: true
    });

    let f = new AFactory();
    let data = f.build();

    assert.deepEqual(data, { name: 'Sam', age: 28, alive: true });
  });

  test('it supports inheritance', function(assert) {
    let PersonFactory = Mirage.Factory.extend({
      species: 'human'
    });
    let ManFactory = PersonFactory.extend({
      gender: 'male'
    });
    let SamFactory = ManFactory.extend({
      name: 'Sam'
    });

    let p = new PersonFactory();
    let m = new ManFactory();
    let s = new SamFactory();

    assert.deepEqual(p.build(), { species: 'human' });
    assert.deepEqual(m.build(), { species: 'human', gender: 'male' });
    assert.deepEqual(s.build(), { species: 'human', gender: 'male', name: 'Sam' });
  });

  test('it can use sequences', function(assert) {
    let PostFactory = Mirage.Factory.extend({
      likes(i) {
        return 5 * i;
      }
    });

    let p = new PostFactory();
    let post1 = p.build(1);
    let post2 = p.build(2);

    assert.deepEqual(post1, { likes: 5 });
    assert.deepEqual(post2, { likes: 10 });
  });

  test('it can reuse static properties', function(assert) {
    let BazFactory = Mirage.Factory.extend({
      foo: 5,
      bar(i) {
        return this.foo * i;
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);
    let baz2 = b.build(2);

    assert.deepEqual(baz1, { foo: 5, bar: 5 });
    assert.deepEqual(baz2, { foo: 5, bar: 10 });
  });

  test('it can reuse dynamic properties', function(assert) {
    let BazFactory = Mirage.Factory.extend({
      foo(i) {
        return 5 * i;
      },
      bar() {
        return this.foo * 2;
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);
    let baz2 = b.build(2);

    assert.deepEqual(baz1, { foo: 5, bar: 10 });
    assert.deepEqual(baz2, { foo: 10, bar: 20 });
  });

  test('it can have dynamic properties that depend on another', function(assert) {
    let BazFactory = Mirage.Factory.extend({
      name() {
        return 'foo';
      },
      bar() {
        return this.name.substr(1);
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);

    assert.deepEqual(baz1, { name: 'foo', bar: 'oo' });
  });

  test('it can reference properties out of order', function(assert) {
    let BazFactory = Mirage.Factory.extend({
      bar() {
        return this.foo + 2;
      },

      baz: 6,

      foo(i) {
        return this.baz * i;
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);
    let baz2 = b.build(2);

    assert.deepEqual(baz1, { baz: 6, foo: 6, bar: 8 });
    assert.deepEqual(baz2, { baz: 6, foo: 12, bar: 14 });
  });

  test('it can reference multiple properties in any order', function(assert) {
    let FooFactory = Mirage.Factory.extend({
      foo() {
        return this.bar + this.baz;
      },

      bar: 6,

      baz: 10
    });

    let BarFactory = Mirage.Factory.extend({
      bar: 6,

      foo() {
        return this.bar + this.baz;
      },

      baz: 10
    });

    let BazFactory = Mirage.Factory.extend({
      bar: 6,

      baz: 10,

      foo() {
        return this.bar + this.baz;
      }
    });

    let Foo = new FooFactory();
    let Bar = new BarFactory();
    let Baz = new BazFactory();

    let foo = Foo.build(1);
    let bar = Bar.build(1);
    let baz = Baz.build(1);

    assert.deepEqual(foo, { foo: 16, bar: 6, baz: 10 });
    assert.deepEqual(bar, { foo: 16, bar: 6, baz: 10 });
    assert.deepEqual(baz, { foo: 16, bar: 6, baz: 10 });
  });

  test('it can reference properties on complex object', function(assert) {
    let AbcFactory = Mirage.Factory.extend({
      a(i) {
        return this.b + i;
      },
      b() {
        return this.c + 1;
      },
      c() {
        return this.f + 1;
      },
      d(i) {
        return this.e + i;
      },
      e() {
        return this.c + 1;
      },
      f: 1,
      g: 2,
      h: 3
    });

    let b = new AbcFactory();
    let abc1 = b.build(1);
    let abc2 = b.build(2);

    assert.deepEqual(abc1, { a: 4, b: 3, c: 2, d: 4, e: 3, f: 1, g: 2, h: 3 });
    assert.deepEqual(abc2, { a: 5, b: 3, c: 2, d: 5, e: 3, f: 1, g: 2, h: 3 });
  });

  test('throws meaningfull exception on circular reference', function(assert) {
    let BazFactory = Mirage.Factory.extend({
      bar() {
        return this.foo;
      },

      foo() {
        return this.bar;
      }
    });

    let b = new BazFactory();
    assert.throws(function() {
      b.build(1);
    }, function(e) {
      return e.toString() === 'Error: Cyclic dependency in properties ["foo","bar"]';
    });
  });

  test('#build skips invoking `afterCreate`', function(assert) {
    let skipped = true;
    let PostFactory = Mirage.Factory.extend({
      afterCreate() {
        skipped = false;
      }
    });

    let factory = new PostFactory();
    let post = factory.build(0);

    assert.ok(skipped, 'skips invoking `afterCreate`');
    assert.equal(
      typeof post.afterCreate,
      'undefined',
      'does not build `afterCreate` attribute'
    );
  });

  test('extractAfterCreateCallbacks returns all afterCreate callbacks from factory with the base one being first', function(assert) {
    let PostFactory = Mirage.Factory.extend({
      published: trait({
        afterCreate() {
          return 'from published';
        }
      }),

      withComments: trait({
        afterCreate() {
          return 'from withComments';
        }
      }),

      otherTrait: trait({}),

      afterCreate() {
        return 'from base';
      }
    });

    let callbacks = PostFactory.extractAfterCreateCallbacks();
    assert.equal(callbacks.length, 3);
    assert.deepEqual(callbacks.map((cb) => cb()), ['from base', 'from published', 'from withComments']);
  });

  test('extractAfterCreateCallbacks filters traits from which the afterCreate callbacks will be extracted from', function(assert) {
    let PostFactory = Mirage.Factory.extend({
      published: trait({
        afterCreate() {
          return 'from published';
        }
      }),

      withComments: trait({
        afterCreate() {
          return 'from withComments';
        }
      }),

      otherTrait: trait({}),

      afterCreate() {
        return 'from base';
      }
    });

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: [] }).length, 1);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: [] }).map((cb) => cb()),
      ['from base']
    );

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: ['withComments'] }).length, 2);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: ['withComments'] }).map((cb) => cb()),
      ['from base', 'from withComments']
    );

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'published'] }).length, 3);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'published'] }).map((cb) => cb()),
      ['from base', 'from withComments', 'from published']
    );

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'otherTrait'] }).length, 2);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'otherTrait'] }).map((cb) => cb()),
      ['from base', 'from withComments']
    );
  });

  test('isTrait returns true if there is a trait with given name', function(assert) {
    let PostFactory = Mirage.Factory.extend({
      title: 'Lorem ipsum',

      published: trait({
        isPublished: true
      }),

      someNestedObject: {
        value: 'nested'
      }
    });

    assert.ok(!PostFactory.isTrait('title'));
    assert.ok(PostFactory.isTrait('published'));
    assert.ok(!PostFactory.isTrait('someNestedObject'));
    assert.ok(!PostFactory.isTrait('notdefined'));
  });
});
<commit_msg>Update factory-test<commit_after>import { Factory, trait } from 'ember-cli-mirage';

import {module, test} from 'qunit';

module('Unit | Factory', function() {
  test('it exists', function(assert) {
    assert.ok(Factory);
  });

  test('the base class builds empty objects', function(assert) {
    let f = new Factory();
    let data = f.build();

    assert.deepEqual(data, {});
  });

  test('a noop extension builds empty objects', function(assert) {
    let EmptyFactory = Factory.extend();
    let f = new EmptyFactory();
    let data = f.build();

    assert.deepEqual(data, {});
  });

  test('it works with strings, numbers and booleans', function(assert) {
    let AFactory = Factory.extend({
      name: 'Sam',
      age: 28,
      alive: true
    });

    let f = new AFactory();
    let data = f.build();

    assert.deepEqual(data, { name: 'Sam', age: 28, alive: true });
  });

  test('it supports inheritance', function(assert) {
    let PersonFactory = Factory.extend({
      species: 'human'
    });
    let ManFactory = PersonFactory.extend({
      gender: 'male'
    });
    let SamFactory = ManFactory.extend({
      name: 'Sam'
    });

    let p = new PersonFactory();
    let m = new ManFactory();
    let s = new SamFactory();

    assert.deepEqual(p.build(), { species: 'human' });
    assert.deepEqual(m.build(), { species: 'human', gender: 'male' });
    assert.deepEqual(s.build(), { species: 'human', gender: 'male', name: 'Sam' });
  });

  test('it can use sequences', function(assert) {
    let PostFactory = Factory.extend({
      likes(i) {
        return 5 * i;
      }
    });

    let p = new PostFactory();
    let post1 = p.build(1);
    let post2 = p.build(2);

    assert.deepEqual(post1, { likes: 5 });
    assert.deepEqual(post2, { likes: 10 });
  });

  test('it can reuse static properties', function(assert) {
    let BazFactory = Factory.extend({
      foo: 5,
      bar(i) {
        return this.foo * i;
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);
    let baz2 = b.build(2);

    assert.deepEqual(baz1, { foo: 5, bar: 5 });
    assert.deepEqual(baz2, { foo: 5, bar: 10 });
  });

  test('it can reuse dynamic properties', function(assert) {
    let BazFactory = Factory.extend({
      foo(i) {
        return 5 * i;
      },
      bar() {
        return this.foo * 2;
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);
    let baz2 = b.build(2);

    assert.deepEqual(baz1, { foo: 5, bar: 10 });
    assert.deepEqual(baz2, { foo: 10, bar: 20 });
  });

  test('it can have dynamic properties that depend on another', function(assert) {
    let BazFactory = Factory.extend({
      name() {
        return 'foo';
      },
      bar() {
        return this.name.substr(1);
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);

    assert.deepEqual(baz1, { name: 'foo', bar: 'oo' });
  });

  test('it can reference properties out of order', function(assert) {
    let BazFactory = Factory.extend({
      bar() {
        return this.foo + 2;
      },

      baz: 6,

      foo(i) {
        return this.baz * i;
      }
    });

    let b = new BazFactory();
    let baz1 = b.build(1);
    let baz2 = b.build(2);

    assert.deepEqual(baz1, { baz: 6, foo: 6, bar: 8 });
    assert.deepEqual(baz2, { baz: 6, foo: 12, bar: 14 });
  });

  test('it can reference multiple properties in any order', function(assert) {
    let FooFactory = Factory.extend({
      foo() {
        return this.bar + this.baz;
      },

      bar: 6,

      baz: 10
    });

    let BarFactory = Factory.extend({
      bar: 6,

      foo() {
        return this.bar + this.baz;
      },

      baz: 10
    });

    let BazFactory = Factory.extend({
      bar: 6,

      baz: 10,

      foo() {
        return this.bar + this.baz;
      }
    });

    let Foo = new FooFactory();
    let Bar = new BarFactory();
    let Baz = new BazFactory();

    let foo = Foo.build(1);
    let bar = Bar.build(1);
    let baz = Baz.build(1);

    assert.deepEqual(foo, { foo: 16, bar: 6, baz: 10 });
    assert.deepEqual(bar, { foo: 16, bar: 6, baz: 10 });
    assert.deepEqual(baz, { foo: 16, bar: 6, baz: 10 });
  });

  test('it can reference properties on complex object', function(assert) {
    let AbcFactory = Factory.extend({
      a(i) {
        return this.b + i;
      },
      b() {
        return this.c + 1;
      },
      c() {
        return this.f + 1;
      },
      d(i) {
        return this.e + i;
      },
      e() {
        return this.c + 1;
      },
      f: 1,
      g: 2,
      h: 3
    });

    let b = new AbcFactory();
    let abc1 = b.build(1);
    let abc2 = b.build(2);

    assert.deepEqual(abc1, { a: 4, b: 3, c: 2, d: 4, e: 3, f: 1, g: 2, h: 3 });
    assert.deepEqual(abc2, { a: 5, b: 3, c: 2, d: 5, e: 3, f: 1, g: 2, h: 3 });
  });

  test('throws meaningfull exception on circular reference', function(assert) {
    let BazFactory = Factory.extend({
      bar() {
        return this.foo;
      },

      foo() {
        return this.bar;
      }
    });

    let b = new BazFactory();
    assert.throws(function() {
      b.build(1);
    }, function(e) {
      return e.toString() === 'Error: Cyclic dependency in properties ["foo","bar"]';
    });
  });

  test('#build skips invoking `afterCreate`', function(assert) {
    let skipped = true;
    let PostFactory = Factory.extend({
      afterCreate() {
        skipped = false;
      }
    });

    let factory = new PostFactory();
    let post = factory.build(0);

    assert.ok(skipped, 'skips invoking `afterCreate`');
    assert.equal(
      typeof post.afterCreate,
      'undefined',
      'does not build `afterCreate` attribute'
    );
  });

  test('extractAfterCreateCallbacks returns all afterCreate callbacks from factory with the base one being first', function(assert) {
    let PostFactory = Factory.extend({
      published: trait({
        afterCreate() {
          return 'from published';
        }
      }),

      withComments: trait({
        afterCreate() {
          return 'from withComments';
        }
      }),

      otherTrait: trait({}),

      afterCreate() {
        return 'from base';
      }
    });

    let callbacks = PostFactory.extractAfterCreateCallbacks();
    assert.equal(callbacks.length, 3);
    assert.deepEqual(callbacks.map((cb) => cb()), ['from base', 'from published', 'from withComments']);
  });

  test('extractAfterCreateCallbacks filters traits from which the afterCreate callbacks will be extracted from', function(assert) {
    let PostFactory = Factory.extend({
      published: trait({
        afterCreate() {
          return 'from published';
        }
      }),

      withComments: trait({
        afterCreate() {
          return 'from withComments';
        }
      }),

      otherTrait: trait({}),

      afterCreate() {
        return 'from base';
      }
    });

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: [] }).length, 1);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: [] }).map((cb) => cb()),
      ['from base']
    );

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: ['withComments'] }).length, 2);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: ['withComments'] }).map((cb) => cb()),
      ['from base', 'from withComments']
    );

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'published'] }).length, 3);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'published'] }).map((cb) => cb()),
      ['from base', 'from withComments', 'from published']
    );

    assert.equal(PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'otherTrait'] }).length, 2);
    assert.deepEqual(
      PostFactory.extractAfterCreateCallbacks({ traits: ['withComments', 'otherTrait'] }).map((cb) => cb()),
      ['from base', 'from withComments']
    );
  });

  test('isTrait returns true if there is a trait with given name', function(assert) {
    let PostFactory = Factory.extend({
      title: 'Lorem ipsum',

      published: trait({
        isPublished: true
      }),

      someNestedObject: {
        value: 'nested'
      }
    });

    assert.ok(!PostFactory.isTrait('title'));
    assert.ok(PostFactory.isTrait('published'));
    assert.ok(!PostFactory.isTrait('someNestedObject'));
    assert.ok(!PostFactory.isTrait('notdefined'));
  });
});
<|endoftext|>


<commit_before>import deepFreeze from 'deep-freeze';
import { DOHLASKY, PRIHLASKY } from '../../constants';
import { signIn } from '../../auth/SignIn/SignInActions';
import { signOut } from '../../auth/SignOut/SignOutActions';
import { saveVykon } from '../../casomeric/Casomira/StartovniCisla/StartovniCislaActions';
import { fetchStopky } from '../../entities/stopky/stopkyActions';
import {
  createPrihlaskySave,
  createValidationError
} from '../../registrator/PrihlaskyDohlasky/PrihlaskyForm/PrihlaskyFormActions';
import { createVykon, deleteVykon } from '../../registrator/Startujici/StartujiciActions';
import { createFailureFromAction } from '../../store/wsAPI';
import { hideError } from './ErrorInModalActions';
import errorInModalReducer from './errorInModalReducer';

const dohlaskySave = createPrihlaskySave(DOHLASKY);
const prihlaskySave = createPrihlaskySave(PRIHLASKY);

const genericUnsuccessfulResponse = {
  code: 'unfulfilled request',
  status: 'A strange error occurred.'
};

const unsuccessfulSaveResponse = {
  code: 'neexistuje',
  status: 'účastník s id ===id=== neexistuje.',
  requestId: '0.9310306652587374'
};

const unsuccessfulSignInResponse = {
  code: 'password incorrect',
  status: 'Špatné jméno či heslo. Uživatel může být též zamčený.',
  requestId: '0.9310306652587374'
};

const unsuccessfulSignOutResponse = {
  code: 'authentication token invalid',
  status: 'Špatný ověřovací token. Zkus se přihlásit znovu.',
  requestId: '0.9310306652587371'
};

it('na začátku', () => {
  const stateBefore = undefined;

  const stateAfter = errorInModalReducer(stateBefore, {});
  expect(stateAfter.code).toEqual('');
  expect(stateAfter.message).toEqual('');
  expect(stateAfter.show).toBe(false);
  expect(stateAfter.title).toEqual('');
});

global.crypto = { getRandomValues: arr => arr.fill(86) };

it('CASOMIRA_SAVE_VYKON_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    code: 'unfulfilled request',
    message: 'A strange error occurred.',
    show: true,
    title: 'ukládání registrace na start'
  };
  deepFreeze(stateBefore);

  const request = { id: '===id===' };
  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({
        action: saveVykon({}),
        request,
        response: genericUnsuccessfulResponse
      })
    )
  ).toEqual(stateAfter);
});

it('DOHLASKY_FORM_INVALID', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'nejde uložit',
    message: 'Přihláška nejde uložit. Povinná pole nejsou vyplněna.',
    show: true,
    title: 'vyplňování formuláře'
  };
  deepFreeze(stateBefore);

  expect(errorInModalReducer(stateBefore, createValidationError(DOHLASKY)())).toEqual(stateAfter);
});

it('DOHLASKY_SAVE_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'neexistuje',
    message: 'účastník s id ===id=== neexistuje.',
    show: true,
    title: 'ukládání formuláře'
  };
  deepFreeze(stateBefore);

  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({
        action: dohlaskySave(),
        request: {},
        response: unsuccessfulSaveResponse
      })
    )
  ).toEqual(stateAfter);
});

it('FETCH_STOPKY_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'unfulfilled request',
    message: 'A strange error occurred.',
    show: true,
    title: 'načítání stopek'
  };
  deepFreeze(stateBefore);

  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({
        action: fetchStopky(),
        response: genericUnsuccessfulResponse
      })
    )
  ).toEqual(stateAfter);
});

it('PRIHLASKY_FORM_INVALID', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'nejde uložit',
    message: 'Přihláška nejde uložit. Povinná pole nejsou vyplněna.',
    show: true,
    title: 'vyplňování formuláře'
  };
  deepFreeze(stateBefore);

  expect(errorInModalReducer(stateBefore, createValidationError(PRIHLASKY)())).toEqual(stateAfter);
});

it('PRIHLASKY_SAVE_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'neexistuje',
    message: 'účastník s id ===id=== neexistuje.',
    show: true,
    title: 'ukládání formuláře'
  };
  deepFreeze(stateBefore);

  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({
        action: prihlaskySave(),
        request: {},
        response: unsuccessfulSaveResponse
      })
    )
  ).toEqual(stateAfter);
});

it('SIGN_IN_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    code: 'password incorrect',
    message: 'Špatné jméno či heslo. Uživatel může být též zamčený.',
    show: true,
    title: 'přihlašování'
  };
  deepFreeze(stateBefore);

  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({ action: signIn({}), response: unsuccessfulSignInResponse })
    )
  ).toEqual(stateAfter);
});

it('SIGN_OUT_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    code: 'authentication token invalid',
    message: 'Špatný ověřovací token. Zkus se přihlásit znovu.',
    show: true,
    title: 'odhlašování'
  };
  deepFreeze(stateBefore);

  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({ action: signOut(), response: unsuccessfulSignOutResponse })
    )
  ).toEqual(stateAfter);
});

it('STARTUJICI_CREATE_VYKON_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    code: 'unfulfilled request',
    message: 'A strange error occurred.',
    show: true,
    title: 'vytváření registrace na start'
  };
  deepFreeze(stateBefore);

  const request = { id: '===id===', rok: 2018 };
  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({
        action: createVykon({}),
        request,
        response: genericUnsuccessfulResponse
      })
    )
  ).toEqual(stateAfter);
});

it('STARTUJICI_DELETE_VYKON_ERROR', () => {
  const stateBefore = {};
  const stateAfter = {
    code: 'unfulfilled request',
    message: 'A strange error occurred.',
    show: true,
    title: 'rušení registrace na start'
  };
  deepFreeze(stateBefore);

  const request = { id: '===id===', rok: 2018 };
  expect(
    errorInModalReducer(
      stateBefore,
      createFailureFromAction({
        action: deleteVykon({}),
        request,
        response: genericUnsuccessfulResponse
      })
    )
  ).toEqual(stateAfter);
});

it('hideError()', () => {
  const stateBefore = { code: 'code', message: 'Errrorr!', show: true, title: 'Chyba při něčem!' };
  const stateAfter = { code: '', message: '', show: false, title: '' };
  deepFreeze(stateBefore);

  expect(errorInModalReducer(stateBefore, hideError())).toEqual(stateAfter);
});
<commit_msg>Refactor unit tests.<commit_after>import deepFreeze from 'deep-freeze';
import { DOHLASKY, PRIHLASKY } from '../../constants';
import { signIn } from '../../auth/SignIn/SignInActions';
import { signOut } from '../../auth/SignOut/SignOutActions';
import { saveVykon } from '../../casomeric/Casomira/StartovniCisla/StartovniCislaActions';
import { fetchStopky } from '../../entities/stopky/stopkyActions';
import {
  createPrihlaskySave,
  createValidationError
} from '../../registrator/PrihlaskyDohlasky/PrihlaskyForm/PrihlaskyFormActions';
import { createVykon, deleteVykon } from '../../registrator/Startujici/StartujiciActions';
import { createFailureFromAction } from '../../store/wsAPI';
import { hideError } from './ErrorInModalActions';
import errorInModalReducer from './errorInModalReducer';

const dohlaskySave = createPrihlaskySave(DOHLASKY);
const prihlaskySave = createPrihlaskySave(PRIHLASKY);

const genericUnsuccessfulResponse = {
  code: 'unfulfilled request',
  status: 'A strange error occurred.'
};

const unsuccessfulSaveResponse = {
  code: 'neexistuje',
  status: 'účastník s id ===id=== neexistuje.',
  requestId: '0.9310306652587374'
};

const unsuccessfulSignInResponse = {
  code: 'password incorrect',
  status: 'Špatné jméno či heslo. Uživatel může být též zamčený.',
  requestId: '0.9310306652587374'
};

const unsuccessfulSignOutResponse = {
  code: 'authentication token invalid',
  status: 'Špatný ověřovací token. Zkus se přihlásit znovu.',
  requestId: '0.9310306652587371'
};

const testUnsuccessfulResponse = ({
  action,
  code = 'unfulfilled request',
  message = 'A strange error occurred.',
  request,
  response = genericUnsuccessfulResponse,
  title
}) => {
  const stateBefore = {};
  const stateAfter = { code, message, show: true, title };
  deepFreeze(stateBefore);

  expect(
    errorInModalReducer(stateBefore, createFailureFromAction({ action, request, response }))
  ).toEqual(stateAfter);
};

it('na začátku', () => {
  const stateBefore = undefined;

  const stateAfter = errorInModalReducer(stateBefore, {});
  expect(stateAfter.code).toEqual('');
  expect(stateAfter.message).toEqual('');
  expect(stateAfter.show).toBe(false);
  expect(stateAfter.title).toEqual('');
});

global.crypto = { getRandomValues: arr => arr.fill(86) };

it('CASOMIRA_SAVE_VYKON_ERROR', () =>
  testUnsuccessfulResponse({
    action: saveVykon({}),
    request: { id: '===id===' },
    title: 'ukládání registrace na start'
  }));

it('DOHLASKY_FORM_INVALID', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'nejde uložit',
    message: 'Přihláška nejde uložit. Povinná pole nejsou vyplněna.',
    show: true,
    title: 'vyplňování formuláře'
  };
  deepFreeze(stateBefore);

  expect(errorInModalReducer(stateBefore, createValidationError(DOHLASKY)())).toEqual(stateAfter);
});

it('DOHLASKY_SAVE_ERROR', () =>
  testUnsuccessfulResponse({
    action: dohlaskySave(),
    code: 'neexistuje',
    message: 'účastník s id ===id=== neexistuje.',
    request: {},
    response: unsuccessfulSaveResponse,
    title: 'ukládání formuláře'
  }));

it('FETCH_STOPKY_ERROR', () =>
  testUnsuccessfulResponse({
    action: fetchStopky(),
    title: 'načítání stopek'
  }));

it('PRIHLASKY_FORM_INVALID', () => {
  const stateBefore = {};
  const stateAfter = {
    ...stateBefore,
    code: 'nejde uložit',
    message: 'Přihláška nejde uložit. Povinná pole nejsou vyplněna.',
    show: true,
    title: 'vyplňování formuláře'
  };
  deepFreeze(stateBefore);

  expect(errorInModalReducer(stateBefore, createValidationError(PRIHLASKY)())).toEqual(stateAfter);
});

it('PRIHLASKY_SAVE_ERROR', () =>
  testUnsuccessfulResponse({
    action: prihlaskySave(),
    code: 'neexistuje',
    message: 'účastník s id ===id=== neexistuje.',
    request: {},
    response: unsuccessfulSaveResponse,
    title: 'ukládání formuláře'
  }));

it('SIGN_IN_ERROR', () =>
  testUnsuccessfulResponse({
    action: signIn({}),
    code: 'password incorrect',
    message: 'Špatné jméno či heslo. Uživatel může být též zamčený.',
    response: unsuccessfulSignInResponse,
    title: 'přihlašování'
  }));

it('SIGN_OUT_ERROR', () =>
  testUnsuccessfulResponse({
    action: signOut(),
    code: 'authentication token invalid',
    message: 'Špatný ověřovací token. Zkus se přihlásit znovu.',
    response: unsuccessfulSignOutResponse,
    title: 'odhlašování'
  }));

it('STARTUJICI_CREATE_VYKON_ERROR', () =>
  testUnsuccessfulResponse({
    action: createVykon({}),
    request: { id: '===id===', rok: 2018 },
    title: 'vytváření registrace na start'
  }));

it('STARTUJICI_DELETE_VYKON_ERROR', () =>
  testUnsuccessfulResponse({
    action: deleteVykon({}),
    request: { id: '===id===', rok: 2018 },
    title: 'rušení registrace na start'
  }));

it('hideError()', () => {
  const stateBefore = { code: 'code', message: 'Errrorr!', show: true, title: 'Chyba při něčem!' };
  const stateAfter = { code: '', message: '', show: false, title: '' };
  deepFreeze(stateBefore);

  expect(errorInModalReducer(stateBefore, hideError())).toEqual(stateAfter);
});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Spatial Filter component
 * This component adds the functionality of creating a spatial filter: a filter based on a drawn geometry (polygon, rectangle, circle or freeform). All features must
 * be in or partly in the drawn geometry (ie. intersects).
 * @author Meine Toonen
 */
Ext.define ("viewer.components.SpatialFilter",{
    extend: "viewer.components.Component",
    layerSelector:null,
    drawingButtonIds:null,
    vectorLayer:null,
    iconPath:null,
    features:null,
    config:{
        title: "",
        iconUrl: "",
        tooltip: "",
        layers:null,
        applyDirect:null,
        multiGeometries:null,
        label: ""
    },
    constructor: function (conf){
        if(conf.details.width === undefined){
            conf.details.width = 330;
        }
        if(conf.details.height === undefined){
            conf.details.height = 290;
        }
        if(conf.applyDirect === undefined){
            conf.applyDirect = true;
        }

        if(conf.multiGeometries === undefined){
            conf.multiGeometries = true;
        }
        viewer.components.SpatialFilter.superclass.constructor.call(this, conf);
        this.initConfig(conf);
        var me = this;
        this.features = new Array();
        this.renderButton({
            handler: function(){
                me.showWindow();
            },
            text: me.title,
            icon: "/viewer/viewer-html/components/resources/images/spatialFilter/spatialFilterButton.png",
            tooltip: me.tooltip,
            label: me.label
        });
        // Needed to untoggle the buttons when drawing is finished
        this.drawingButtonIds = {
            'polygon': Ext.id(),
            'circle': Ext.id(),
            'box': Ext.id(),
            'freehand': Ext.id()

        };
        this.iconPath=contextPath+"/viewer-html/components/resources/images/drawing/";

        this.loadWindow();
        this.viewerController.addListener(viewer.viewercontroller.controller.Event.ON_SELECTEDCONTENT_CHANGE,this.selectedContentChanged,this );
        return this;
    },

    showWindow : function(){
        if(this.vectorLayer === null){
            this.createVectorLayer();
        }
        this.layerSelector.initLayers();
        this.popup.popupWin.setTitle(this.title);
        this.popup.show();
    },

    drawGeometry: function(type){
        var appendFilter = Ext.getCmp (this.name + 'AppendFilter')
        if(!appendFilter.getValue()){
            this.vectorLayer.removeAllFeatures();
            this.features = new Array();
        }
        this.vectorLayer.drawFeature(type);
    },
    applyFilter : function(){
        var features = this.features;;
        var multi = "";
        if (features.length > 0) {
            multi += "MULTIPOLYGON (";
            for (var i = 0; i < features.length; i++) {
                var feature = features[i];
                var coords = feature.replace("POLYGON", "");
                if (i > 0) {
                    multi += ",";
                }
                multi += coords;
            }
            multi += ")";
        }
        this.setFilter(multi);
    },
    setFilter: function(geometry){
        var appLayer = this.layerSelector.getSelectedAppLayer();
        var me = this;
        if(appLayer.attributes === undefined || appLayer.attributes === null) {
            this.viewerController.getAppLayerFeatureService(appLayer).loadAttributes(appLayer,function(){
                me.setFilter(geometry);
            },function(e){
                Ext.MessageBox.alert("Error", e);
            });
        }else{
            var geomAttr = appLayer.geometryAttribute;
            if (geomAttr !== undefined){
                var filter = "";
                if(geometry.length > 0){
                    filter = "INTERSECTS(" + geomAttr + ", " + geometry + ")";
                }
                this.viewerController.setFilter(
                    Ext.create("viewer.components.CQLFilterWrapper",{
                        id: "filter_"+this.getName(),
                        cql: filter,
                        operator : "AND",
                        type: "GEOMETRY"
                    }),appLayer);
            }
        }

    },
    buffer : function(){
        var features = this.features;
        var distance = Ext.getCmp(this.name + "BufferDistance").getValue();
        if(distance === null || distance === 0){
            return;
        }
        var requestParams = {
            features: features,
            buffer : distance
        };
        Ext.Ajax.request({
            url: actionBeans["buffergeom"],
            params: requestParams,
            method:  "POST",
            scope:this,
            success: function(result, request) {
                var response = Ext.JSON.decode(result.responseText);
                if(response.success){
                    this.features = [];
                    var features = response.features;
                    var featureObjs = [];
                    for(var i = 0 ; i < features.length ;i++){
                        var feature = Ext.create("viewer.viewercontroller.controller.Feature",{
                            wktgeom:features[i]
                        });
                        featureObjs.push(feature);
                    }
                    this.vectorLayer.removeAllFeatures();
                    this.vectorLayer.addFeatures(featureObjs);
                }else{
                    Ext.MessageBox.alert("Foutmelding", response.errorMessage);
                }
            },
            failure: function(result, request) {
                var response = Ext.JSON.decode(result.responseText);
                Ext.MessageBox.alert("Foutmelding", response.error);
            }
        });
    },
    bufferReturned : function(){

    },

    // <editor-fold desc="Event handlers" defaultstate="collapsed">
    layerChanged : function (appLayer,afterLoadAttributes,scope){
        var buttons = Ext.getCmp(this.name +"filterButtons");
        if(appLayer !== null){
            buttons.setDisabled(false);
            this.vectorLayer.removeAllFeatures();
        }else{
            buttons.setDisabled(true);
            this.cancel();
        }
    },

    featureAdded : function (obj, feature){
        var applyDirect = Ext.getCmp (this.name + 'ApplyDirect')
        this.features.push(feature.wktgeom);
        if(applyDirect.getValue()){
            this.applyFilter();
        }
        this.toggleAll(false);
    },
    selectedContentChanged : function (){
        if(this.vectorLayer === null){
            this.createVectorLayer();
        }else{
            this.viewerController.mapComponent.getMap().addLayer(this.vectorLayer);
        }
    },
    // </editor-fold>

    // <editor-fold desc="Initialization methods" defaultstate="collapsed">
    loadWindow : function (){
        var me =this;
        var formItems = [
        {
            xtype: 'button',
            id: this.drawingButtonIds.polygon,
            icon: this.iconPath+"shape_polygon_red.png",
            componentCls: 'mobileLarge',
            tooltip: "Teken een polygoon",
            enableToggle: true,
            toggleGroup: 'drawingTools',
            listeners: {
                click:{
                    scope: me,
                    fn: function(){
                        me.drawGeometry("Polygon");
                    }
                }
            }
        },
        {
            xtype: 'button',
            id: this.drawingButtonIds.box,
            icon: this.iconPath+"shape_square_red.png",
            componentCls: 'mobileLarge',
            tooltip: "Teken een vierkant",
            enableToggle: true,
            toggleGroup: 'drawingTools',
            listeners: {
                click:{
                    scope: me,
                    fn: function(){
                        me.drawGeometry("Box");
                    }
                }
            }
        },
        {
            xtype: 'button',
            id: this.drawingButtonIds.freehand,
            icon: this.iconPath+"freehand.png",
            componentCls: 'mobileLarge',
            tooltip: "Teken een vrije vorm",
            enableToggle: true,
            toggleGroup: 'drawingTools',
            listeners: {
                click:{
                    scope: me,
                    fn: function(){
                        me.drawGeometry("Freehand");
                    }
                }
            }
        }];
        if(!MobileManager.isMobile()) {
            formItems.push({
                xtype: 'button',
                id: this.drawingButtonIds.circle,
                icon: this.iconPath+"shape_circle_red.png",
                componentCls: 'mobileLarge',
                tooltip: "Teken een cirkel",
                enableToggle: true,
                toggleGroup: 'drawingTools',
                listeners: {
                    click:{
                        scope: me,
                        fn: function(){
                            me.drawGeometry("Circle");
                        }
                    }
                }
            });
        }
        formItems.push(
        {
            xtype: "container",
            width: "100%",
            layout: {
                type: 'hbox'
            },
            items: [
                {
                    id: this.name + "BufferDistance",
                    name: this.name + "BufferDistance",
                    xtype: "numberfield",
                    fieldLabel: "Bufferafstand",
                    minValue: 0,
                    labelWidth: 75,
                    width: 170

                },{
                    xtype: "button",
                    text: "Buffer",
                    listeners:{
                        click:{
                            scope:this,
                            fn:this.buffer
                        }
                    }
                }]
        },
        {
            xtype: "checkbox",
            boxLabel: 'Meerdere geometriën als filter',
            name: 'appendFilter',
            inputValue: this.multiGeometries,
            checked: this.multiGeometries,
            id: this.name + 'AppendFilter'
        },
        {
            xtype: "checkbox",
            boxLabel: 'Filter direct toepassen',
            name: 'applyDirect',
            inputValue: this.applyDirect,
            checked: this.applyDirect,
            id: this.name + 'ApplyDirect'
        });
        this.maincontainer = Ext.create('Ext.container.Container', {
            id: this.name + 'Container',
            width: '100%',
            height: '100%',
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            style: {
                backgroundColor: 'White'
            },
            renderTo: this.getContentDiv(),
            items: [{
                id: this.name + 'LayerSelectorPanel',
                xtype: "container",
                padding: "4px",
                width: '100%',
                height: 36
            },{
                id: this.name + 'filterButtons',
                xtype: "container",
                disabled:true,
                autoScroll: true,
                width: '100%',
                layout:{
                    type: "vbox"
                },
                flex: 1,
                items: formItems
            },{
                id: this.name + 'ClosingPanel',
                xtype: "container",
                width: '100%',
                height: MobileManager.isMobile() ? 45 : 25,
                style: {
                    marginTop: '10px'
                },
                layout: {
                    type:'hbox',
                    pack:'end'
                },
                items: [
                    {xtype: 'button', text: 'Reset', componentCls: 'mobileLarge', handler: function(){
                        me.resetForm();
                    }},
                    {xtype: 'button', text: 'Toepassen', componentCls: 'mobileLarge', handler: function(){
                        me.applyFilter();
                    }},
                    {xtype: 'button', text: 'Sluiten', componentCls: 'mobileLarge', handler: function() {
                        me.resetForm();
                        me.popup.hide();
                    }}
                ]
            }]
        });
        this.createLayerSelector();
    },
    createLayerSelector: function(){
        var config = {
            viewerController : this.viewerController,
            restriction : "filterable",
            id : this.name + "layerSelector",
            layers: this.layers,
            div: this.name + 'LayerSelectorPanel'
        };
        this.layerSelector = Ext.create("viewer.components.LayerSelector",config);
        this.layerSelector.addListener(viewer.viewercontroller.controller.Event.ON_LAYERSELECTOR_CHANGE,this.layerChanged,this);
    },
    createVectorLayer : function (){
         this.vectorLayer = this.viewerController.mapComponent.createVectorLayer({
            name: this.name + 'VectorLayer',
            geometrytypes:["Circle","Polygon"],
            showmeasures:false,
            viewerController : this.viewerController,
            style: {
                fillcolor: "FF0000",
                fillopacity: 50,
                strokecolor: "FF0000",
                strokeopacity: 50
            }
        });
        this.viewerController.mapComponent.getMap().addLayer(this.vectorLayer);

        this.vectorLayer.addListener (viewer.viewercontroller.controller.Event.ON_FEATURE_ADDED,this.featureAdded,this);
    },

    //</editor-fold>

    // Some helper functions here
    toggleAll : function(state){
        for ( var key in this.drawingButtonIds){
            var el = this.drawingButtonIds[key];
            var button = Ext.getCmp(el);
            button.toggle(state);
        }
    },

    resetForm : function (){
        this.features = new Array();
        this.vectorLayer.removeAllFeatures();
        this.applyFilter();
    },
    getExtComponents: function() {
        return [ this.maincontainer.getId() ];
    }
});
<commit_msg>Loading indicator for calculating the buffered geometries<commit_after>/*
 * Copyright (C) 2014 3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Spatial Filter component
 * This component adds the functionality of creating a spatial filter: a filter based on a drawn geometry (polygon, rectangle, circle or freeform). All features must
 * be in or partly in the drawn geometry (ie. intersects).
 * @author Meine Toonen
 */
Ext.define ("viewer.components.SpatialFilter",{
    extend: "viewer.components.Component",
    layerSelector:null,
    drawingButtonIds:null,
    vectorLayer:null,
    iconPath:null,
    features:null,
    config:{
        title: "",
        iconUrl: "",
        tooltip: "",
        layers:null,
        applyDirect:null,
        multiGeometries:null,
        label: ""
    },
    constructor: function (conf){
        if(conf.details.width === undefined){
            conf.details.width = 330;
        }
        if(conf.details.height === undefined){
            conf.details.height = 290;
        }
        if(conf.applyDirect === undefined){
            conf.applyDirect = true;
        }

        if(conf.multiGeometries === undefined){
            conf.multiGeometries = true;
        }
        viewer.components.SpatialFilter.superclass.constructor.call(this, conf);
        this.initConfig(conf);
        var me = this;
        this.features = new Array();
        this.renderButton({
            handler: function(){
                me.showWindow();
            },
            text: me.title,
            icon: "/viewer/viewer-html/components/resources/images/spatialFilter/spatialFilterButton.png",
            tooltip: me.tooltip,
            label: me.label
        });
        // Needed to untoggle the buttons when drawing is finished
        this.drawingButtonIds = {
            'polygon': Ext.id(),
            'circle': Ext.id(),
            'box': Ext.id(),
            'freehand': Ext.id()

        };
        this.iconPath=contextPath+"/viewer-html/components/resources/images/drawing/";

        this.loadWindow();
        this.viewerController.addListener(viewer.viewercontroller.controller.Event.ON_SELECTEDCONTENT_CHANGE,this.selectedContentChanged,this );
        return this;
    },

    showWindow : function(){
        if(this.vectorLayer === null){
            this.createVectorLayer();
        }
        this.layerSelector.initLayers();
        this.popup.popupWin.setTitle(this.title);
        this.popup.show();
    },

    drawGeometry: function(type){
        var appendFilter = Ext.getCmp (this.name + 'AppendFilter')
        if(!appendFilter.getValue()){
            this.vectorLayer.removeAllFeatures();
            this.features = new Array();
        }
        this.vectorLayer.drawFeature(type);
    },
    applyFilter : function(){
        var features = this.features;;
        var multi = "";
        if (features.length > 0) {
            multi += "MULTIPOLYGON (";
            for (var i = 0; i < features.length; i++) {
                var feature = features[i];
                var coords = feature.replace("POLYGON", "");
                if (i > 0) {
                    multi += ",";
                }
                multi += coords;
            }
            multi += ")";
        }
        this.setFilter(multi);
    },
    setFilter: function(geometry){
        var appLayer = this.layerSelector.getSelectedAppLayer();
        var me = this;
        if(appLayer.attributes === undefined || appLayer.attributes === null) {
            this.viewerController.getAppLayerFeatureService(appLayer).loadAttributes(appLayer,function(){
                me.setFilter(geometry);
            },function(e){
                Ext.MessageBox.alert("Error", e);
            });
        }else{
            var geomAttr = appLayer.geometryAttribute;
            if (geomAttr !== undefined){
                var filter = "";
                if(geometry.length > 0){
                    filter = "INTERSECTS(" + geomAttr + ", " + geometry + ")";
                }
                this.viewerController.setFilter(
                    Ext.create("viewer.components.CQLFilterWrapper",{
                        id: "filter_"+this.getName(),
                        cql: filter,
                        operator : "AND",
                        type: "GEOMETRY"
                    }),appLayer);
            }
        }

    },
    buffer : function(){
        Ext.getCmp(this.name + "BufferContainer").setLoading("Buffer berekenen...");
        var features = this.features;
        var distance = Ext.getCmp(this.name + "BufferDistance").getValue();
        if(distance === null || distance === 0){
            return;
        }
        var requestParams = {
            features: features,
            buffer : distance
        };
        Ext.Ajax.request({
            url: actionBeans["buffergeom"],
            params: requestParams,
            method:  "POST",
            scope:this,
            success: function(result, request) {
                var response = Ext.JSON.decode(result.responseText);
                if(response.success){
                    this.features = [];
                    var features = response.features;
                    var featureObjs = [];
                    for(var i = 0 ; i < features.length ;i++){
                        var feature = Ext.create("viewer.viewercontroller.controller.Feature",{
                            wktgeom:features[i]
                        });
                        featureObjs.push(feature);
                    }
                    this.vectorLayer.removeAllFeatures();
                    this.vectorLayer.addFeatures(featureObjs);
                }else{
                    Ext.MessageBox.alert("Foutmelding", response.errorMessage);
                }
                Ext.getCmp(this.name + "BufferContainer").setLoading(false);
            },
            failure: function(result, request) {
                Ext.getCmp(this.name + "BufferContainer").setLoading(false);
                var response = Ext.JSON.decode(result.responseText);
                Ext.MessageBox.alert("Foutmelding", response.error);
            }
        });
    },

    // <editor-fold desc="Event handlers" defaultstate="collapsed">
    layerChanged : function (appLayer,afterLoadAttributes,scope){
        var buttons = Ext.getCmp(this.name +"filterButtons");
        if(appLayer !== null){
            buttons.setDisabled(false);
            this.vectorLayer.removeAllFeatures();
        }else{
            buttons.setDisabled(true);
            this.cancel();
        }
    },

    featureAdded : function (obj, feature){
        var applyDirect = Ext.getCmp (this.name + 'ApplyDirect')
        this.features.push(feature.wktgeom);
        if(applyDirect.getValue()){
            this.applyFilter();
        }
        this.toggleAll(false);
    },
    selectedContentChanged : function (){
        if(this.vectorLayer === null){
            this.createVectorLayer();
        }else{
            this.viewerController.mapComponent.getMap().addLayer(this.vectorLayer);
        }
    },
    // </editor-fold>

    // <editor-fold desc="Initialization methods" defaultstate="collapsed">
    loadWindow : function (){
        var me =this;
        var formItems = [
        {
            xtype: 'button',
            id: this.drawingButtonIds.polygon,
            icon: this.iconPath+"shape_polygon_red.png",
            componentCls: 'mobileLarge',
            tooltip: "Teken een polygoon",
            enableToggle: true,
            toggleGroup: 'drawingTools',
            listeners: {
                click:{
                    scope: me,
                    fn: function(){
                        me.drawGeometry("Polygon");
                    }
                }
            }
        },
        {
            xtype: 'button',
            id: this.drawingButtonIds.box,
            icon: this.iconPath+"shape_square_red.png",
            componentCls: 'mobileLarge',
            tooltip: "Teken een vierkant",
            enableToggle: true,
            toggleGroup: 'drawingTools',
            listeners: {
                click:{
                    scope: me,
                    fn: function(){
                        me.drawGeometry("Box");
                    }
                }
            }
        },
        {
            xtype: 'button',
            id: this.drawingButtonIds.freehand,
            icon: this.iconPath+"freehand.png",
            componentCls: 'mobileLarge',
            tooltip: "Teken een vrije vorm",
            enableToggle: true,
            toggleGroup: 'drawingTools',
            listeners: {
                click:{
                    scope: me,
                    fn: function(){
                        me.drawGeometry("Freehand");
                    }
                }
            }
        }];
        if(!MobileManager.isMobile()) {
            formItems.push({
                xtype: 'button',
                id: this.drawingButtonIds.circle,
                icon: this.iconPath+"shape_circle_red.png",
                componentCls: 'mobileLarge',
                tooltip: "Teken een cirkel",
                enableToggle: true,
                toggleGroup: 'drawingTools',
                listeners: {
                    click:{
                        scope: me,
                        fn: function(){
                            me.drawGeometry("Circle");
                        }
                    }
                }
            });
        }
        formItems.push(
        {
            id: this.name + "BufferContainer",
            name: this.name + "BufferContainer",
            xtype: "container",
            width: "100%",
            layout: {
                type: 'hbox'
            },
            items: [
                {
                    id: this.name + "BufferDistance",
                    name: this.name + "BufferDistance",
                    xtype: "numberfield",
                    fieldLabel: "Bufferafstand",
                    minValue: 0,
                    labelWidth: 75,
                    width: 170

                },{
                    xtype: "button",
                    text: "Buffer",
                    listeners:{
                        click:{
                            scope:this,
                            fn:this.buffer
                        }
                    }
                }]
        },
        {
            xtype: "checkbox",
            boxLabel: 'Meerdere geometriën als filter',
            name: 'appendFilter',
            inputValue: this.multiGeometries,
            checked: this.multiGeometries,
            id: this.name + 'AppendFilter'
        },
        {
            xtype: "checkbox",
            boxLabel: 'Filter direct toepassen',
            name: 'applyDirect',
            inputValue: this.applyDirect,
            checked: this.applyDirect,
            id: this.name + 'ApplyDirect'
        });
        this.maincontainer = Ext.create('Ext.container.Container', {
            id: this.name + 'Container',
            width: '100%',
            height: '100%',
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            style: {
                backgroundColor: 'White'
            },
            renderTo: this.getContentDiv(),
            items: [{
                id: this.name + 'LayerSelectorPanel',
                xtype: "container",
                padding: "4px",
                width: '100%',
                height: 36
            },{
                id: this.name + 'filterButtons',
                xtype: "container",
                disabled:true,
                autoScroll: true,
                width: '100%',
                layout:{
                    type: "vbox"
                },
                flex: 1,
                items: formItems
            },{
                id: this.name + 'ClosingPanel',
                xtype: "container",
                width: '100%',
                height: MobileManager.isMobile() ? 45 : 25,
                style: {
                    marginTop: '10px'
                },
                layout: {
                    type:'hbox',
                    pack:'end'
                },
                items: [
                    {xtype: 'button', text: 'Reset', componentCls: 'mobileLarge', handler: function(){
                        me.resetForm();
                    }},
                    {xtype: 'button', text: 'Toepassen', componentCls: 'mobileLarge', handler: function(){
                        me.applyFilter();
                    }},
                    {xtype: 'button', text: 'Sluiten', componentCls: 'mobileLarge', handler: function() {
                        me.resetForm();
                        me.popup.hide();
                    }}
                ]
            }]
        });
        this.createLayerSelector();
    },
    createLayerSelector: function(){
        var config = {
            viewerController : this.viewerController,
            restriction : "filterable",
            id : this.name + "layerSelector",
            layers: this.layers,
            div: this.name + 'LayerSelectorPanel'
        };
        this.layerSelector = Ext.create("viewer.components.LayerSelector",config);
        this.layerSelector.addListener(viewer.viewercontroller.controller.Event.ON_LAYERSELECTOR_CHANGE,this.layerChanged,this);
    },
    createVectorLayer : function (){
         this.vectorLayer = this.viewerController.mapComponent.createVectorLayer({
            name: this.name + 'VectorLayer',
            geometrytypes:["Circle","Polygon"],
            showmeasures:false,
            viewerController : this.viewerController,
            style: {
                fillcolor: "FF0000",
                fillopacity: 50,
                strokecolor: "FF0000",
                strokeopacity: 50
            }
        });
        this.viewerController.mapComponent.getMap().addLayer(this.vectorLayer);

        this.vectorLayer.addListener (viewer.viewercontroller.controller.Event.ON_FEATURE_ADDED,this.featureAdded,this);
    },

    //</editor-fold>

    // Some helper functions here
    toggleAll : function(state){
        for ( var key in this.drawingButtonIds){
            var el = this.drawingButtonIds[key];
            var button = Ext.getCmp(el);
            button.toggle(state);
        }
    },

    resetForm : function (){
        this.features = new Array();
        this.vectorLayer.removeAllFeatures();
        this.applyFilter();
    },
    getExtComponents: function() {
        return [ this.maincontainer.getId() ];
    }
});
<|endoftext|>


<commit_before>/**
 * © Alexander Buzin, 2014-2015
 * Site: http://alexbuzin.me/
 * Email: alexbuzin88@gmail.com
*/

// [x]#TODO:130 RESTRUCTURIZE.
// [x]#TODO:120 RESTRUCTURIZE threejs and cannonjs library calling.
// [x]#DONE:30 Add stats.
// #TODO:10 Add http://underscorejs.org/.
// DONE:20 clean all console.logs.
// DOING:0 Wagner.base.js is not a part of library.
// FIXME: Fix fog.
// DOING:10 improve libraries support.

/* ================ WHITESTORM|JS ==================== */
var WHS = {
    REVISION: "r8",

    loader: {
        JSON: new THREE.JSONLoader(),
        Texture: new THREE.TextureLoader(),
        Font: new THREE.FontLoader()
    },

    API: {},

    _settings: {

        assets: "./assets",

        path_worker: '../libs/physijs_worker.js',
        path_ammo: '../libs/ammo.js',

    },

    debug: false,

    loops: []
};

console.log('WhitestormJS', WHS.REVISION);

WHS.API.loadJSON = function(url, callback, texturePath) {
    return WHS.loader.JSON.load(url, callback, texturePath)
};

WHS.API.loadTexture = function(url, onLoad, onProgress, onError) {
    return WHS.loader.Texture.load(url, onLoad, onProgress, onError);
}

WHS.API.loadFont = function(url, onLoad, onProgress, onError) {
    return WHS.loader.Font.load(url, onLoad, onProgress, onError);
}

if ( typeof define === 'function' && define.amd ) {

    define( 'whitestorm', WHS );

} else if ( 'undefined' !== typeof exports && 'undefined' !== typeof module ) {

    module.exports = WHS;

}<commit_msg>.<commit_after>/**
 * © Alexander Buzin, 2014-2015
 * Site: http://alexbuzin.me/
 * Email: alexbuzin88@gmail.com
*/

// [x]#TODO:130 RESTRUCTURIZE.
// [x]#TODO:120 RESTRUCTURIZE threejs and cannonjs library calling.
// [x]#DONE:30 Add stats.
// #TODO:10 Add http://underscorejs.org/.
// DONE:20 clean all console.logs.
// DOING:0 Wagner.base.js is not a part of library.
// FIXME: Fix fog.
// DOING:10 improve libraries support.

/* ================ WHITESTORM|JS ==================== */
var WHS = {
    REVISION: "r8",

    loader: {
        JSON: new THREE.JSONLoader(),
        Texture: new THREE.TextureLoader(),
        Font: new THREE.FontLoader()
    },

    API: {},

    _settings: {

        assets: "./assets",

        path_worker: '../libs/physijs_worker.js',
        path_ammo: '../libs/ammo.js',

    },

    debug: false,

    loops: []
};

console.log('WhitestormJS', WHS.REVISION);

const native = new WeakMap(); // Store private variables.

WHS.API.loadJSON = function(url, callback, texturePath) {
    return WHS.loader.JSON.load(url, callback, texturePath)
};

WHS.API.loadTexture = function(url, onLoad, onProgress, onError) {
    return WHS.loader.Texture.load(url, onLoad, onProgress, onError);
}

WHS.API.loadFont = function(url, onLoad, onProgress, onError) {
    return WHS.loader.Font.load(url, onLoad, onProgress, onError);
}

if ( typeof define === 'function' && define.amd ) {

    define( 'whitestorm', WHS );

} else if ( 'undefined' !== typeof exports && 'undefined' !== typeof module ) {

    module.exports = WHS;

}<|endoftext|>


<commit_before>goog.provide('ol.geom.LineString');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.length');
goog.require('ol.geom.flat.simplify');

/**
 * @classdesc
 * Linestring geometry.
 *
 * @constructor
 * @extends {ol.geom.SimpleGeometry}
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @api stable
 */
ol.geom.LineString = function(coordinates, opt_layout) {

  goog.base(this);

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.flatMidpoint_ = null;

  /**
   * @private
   * @type {number}
   */
  this.flatMidpointRevision_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.maxDelta_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.maxDeltaRevision_ = -1;

  this.setCoordinates(coordinates,
      /** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));

};
goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry);

/**
 * @param {ol.Coordinate} coordinate Coordinate.
 * @api stable
 */
ol.geom.LineString.prototype.appendCoordinate = function(coordinate) {
  goog.asserts.assert(coordinate.length == this.stride);
  if (goog.isNull(this.flatCoordinates)) {
    this.flatCoordinates = coordinate.slice();
  } else {
    goog.array.extend(this.flatCoordinates, coordinate);
  }
  this.changed();
};

/**
 * Make a complete copy of the geometry.
 * @return {!ol.geom.LineString} Clone.
 * @api stable
 */
ol.geom.LineString.prototype.clone = function() {
  var lineString = new ol.geom.LineString(null);
  lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
  return lineString;
};

/**
 * @inheritDoc
 */
ol.geom.LineString.prototype.closestPointXY =
    function(x, y, closestPoint, minSquaredDistance) {
  if (minSquaredDistance <
      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
    return minSquaredDistance;
  }
  if (this.maxDeltaRevision_ != this.getRevision()) {
    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
        this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
    this.maxDeltaRevision_ = this.getRevision();
  }
  return ol.geom.flat.closest.getClosestPoint(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
      this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
};

/**
 * Returns the coordinate at `m` using linear interpolation, or `null` if no
 * such coordinate exists.
 *
 * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
 * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
 * M will return the first coordinate and Ms greater than the last M will
 * return the last coordinate.
 *
 * @param {number} m M.
 * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
 * @return {ol.Coordinate} Coordinate.
 * @api stable
 */
ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
  if (this.layout != ol.geom.GeometryLayout.XYM &&
      this.layout != ol.geom.GeometryLayout.XYZM) {
    return null;
  }
  var extrapolate = goog.isDef(opt_extrapolate) ? opt_extrapolate : false;
  return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0,
      this.flatCoordinates.length, this.stride, m, extrapolate);
};

/**
 * @return {Array.<ol.Coordinate>} Coordinates.
 * @api stable
 */
ol.geom.LineString.prototype.getCoordinates = function() {
  return ol.geom.flat.inflate.coordinates(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};

/**
 * @return {number} Length (on projected plane).
 * @api stable
 */
ol.geom.LineString.prototype.getLength = function() {
  return ol.geom.flat.length.lineString(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};

/**
 * @return {Array.<number>} Flat midpoint.
 */
ol.geom.LineString.prototype.getFlatMidpoint = function() {
  if (this.flatMidpointRevision_ != this.getRevision()) {
    this.flatMidpoint_ = ol.geom.flat.interpolate.lineString(
        this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
        0.5, this.flatMidpoint_);
    this.flatMidpointRevision_ = this.getRevision();
  }
  return this.flatMidpoint_;
};

/**
 * @inheritDoc
 */
ol.geom.LineString.prototype.getSimplifiedGeometryInternal =
    function(squaredTolerance) {
  var simplifiedFlatCoordinates = [];
  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
      squaredTolerance, simplifiedFlatCoordinates, 0);
  var simplifiedLineString = new ol.geom.LineString(null);
  simplifiedLineString.setFlatCoordinates(
      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
  return simplifiedLineString;
};

/**
 * @inheritDoc
 * @api stable
 */
ol.geom.LineString.prototype.getType = function() {
  return ol.geom.GeometryType.LINE_STRING;
};

/**
 * @inheritDoc
 * @api
 */
ol.geom.LineString.prototype.intersectsExtent = function(extent) {
  return ol.geom.flat.intersectsextent.lineString(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
      extent);
};

/**
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @api stable
 */
ol.geom.LineString.prototype.setCoordinates =
    function(coordinates, opt_layout) {
  if (goog.isNull(coordinates)) {
    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
  } else {
    this.setLayout(opt_layout, coordinates, 1);
    if (goog.isNull(this.flatCoordinates)) {
      this.flatCoordinates = [];
    }
    this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
        this.flatCoordinates, 0, coordinates, this.stride);
    this.changed();
  }
};

/**
 * @param {ol.geom.GeometryLayout} layout Layout.
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 */
ol.geom.LineString.prototype.setFlatCoordinates =
    function(layout, flatCoordinates) {
  this.setFlatCoordinatesInternal(layout, flatCoordinates);
  this.changed();
};
<commit_msg>Add new ol.geom.LineString#forEachSegment function<commit_after>goog.provide('ol.geom.LineString');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.length');
goog.require('ol.geom.flat.segments');
goog.require('ol.geom.flat.simplify');

/**
 * @classdesc
 * Linestring geometry.
 *
 * @constructor
 * @extends {ol.geom.SimpleGeometry}
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @api stable
 */
ol.geom.LineString = function(coordinates, opt_layout) {

  goog.base(this);

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.flatMidpoint_ = null;

  /**
   * @private
   * @type {number}
   */
  this.flatMidpointRevision_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.maxDelta_ = -1;

  /**
   * @private
   * @type {number}
   */
  this.maxDeltaRevision_ = -1;

  this.setCoordinates(coordinates,
      /** @type {ol.geom.GeometryLayout|undefined} */ (opt_layout));

};
goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry);

/**
 * @param {ol.Coordinate} coordinate Coordinate.
 * @api stable
 */
ol.geom.LineString.prototype.appendCoordinate = function(coordinate) {
  goog.asserts.assert(coordinate.length == this.stride);
  if (goog.isNull(this.flatCoordinates)) {
    this.flatCoordinates = coordinate.slice();
  } else {
    goog.array.extend(this.flatCoordinates, coordinate);
  }
  this.changed();
};

/**
 * Make a complete copy of the geometry.
 * @return {!ol.geom.LineString} Clone.
 * @api stable
 */
ol.geom.LineString.prototype.clone = function() {
  var lineString = new ol.geom.LineString(null);
  lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
  return lineString;
};

/**
 * @inheritDoc
 */
ol.geom.LineString.prototype.closestPointXY =
    function(x, y, closestPoint, minSquaredDistance) {
  if (minSquaredDistance <
      ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
    return minSquaredDistance;
  }
  if (this.maxDeltaRevision_ != this.getRevision()) {
    this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
        this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
    this.maxDeltaRevision_ = this.getRevision();
  }
  return ol.geom.flat.closest.getClosestPoint(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
      this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
};

/**
 * Iterate over each segment, calling the provided callback.
 * If the callback returns a truthy value the function returns that
 * value immediately. Otherwise the function returns `false`.
 *
 * @param {function(ol.Coordinate, ol.Coordinate): T} callback Function
 *     called for each segment.
 * @return {T|boolean} Value.
 * @template T
 * @api
 */
ol.geom.LineString.prototype.forEachSegment = function(callback) {
  return ol.geom.flat.segments.forEach(this.flatCoordinates, 0,
      this.flatCoordinates.length, this.stride, callback);
};

/**
 * Returns the coordinate at `m` using linear interpolation, or `null` if no
 * such coordinate exists.
 *
 * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
 * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
 * M will return the first coordinate and Ms greater than the last M will
 * return the last coordinate.
 *
 * @param {number} m M.
 * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
 * @return {ol.Coordinate} Coordinate.
 * @api stable
 */
ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
  if (this.layout != ol.geom.GeometryLayout.XYM &&
      this.layout != ol.geom.GeometryLayout.XYZM) {
    return null;
  }
  var extrapolate = goog.isDef(opt_extrapolate) ? opt_extrapolate : false;
  return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0,
      this.flatCoordinates.length, this.stride, m, extrapolate);
};

/**
 * @return {Array.<ol.Coordinate>} Coordinates.
 * @api stable
 */
ol.geom.LineString.prototype.getCoordinates = function() {
  return ol.geom.flat.inflate.coordinates(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};

/**
 * @return {number} Length (on projected plane).
 * @api stable
 */
ol.geom.LineString.prototype.getLength = function() {
  return ol.geom.flat.length.lineString(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
};

/**
 * @return {Array.<number>} Flat midpoint.
 */
ol.geom.LineString.prototype.getFlatMidpoint = function() {
  if (this.flatMidpointRevision_ != this.getRevision()) {
    this.flatMidpoint_ = ol.geom.flat.interpolate.lineString(
        this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
        0.5, this.flatMidpoint_);
    this.flatMidpointRevision_ = this.getRevision();
  }
  return this.flatMidpoint_;
};

/**
 * @inheritDoc
 */
ol.geom.LineString.prototype.getSimplifiedGeometryInternal =
    function(squaredTolerance) {
  var simplifiedFlatCoordinates = [];
  simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
      squaredTolerance, simplifiedFlatCoordinates, 0);
  var simplifiedLineString = new ol.geom.LineString(null);
  simplifiedLineString.setFlatCoordinates(
      ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
  return simplifiedLineString;
};

/**
 * @inheritDoc
 * @api stable
 */
ol.geom.LineString.prototype.getType = function() {
  return ol.geom.GeometryType.LINE_STRING;
};

/**
 * @inheritDoc
 * @api
 */
ol.geom.LineString.prototype.intersectsExtent = function(extent) {
  return ol.geom.flat.intersectsextent.lineString(
      this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
      extent);
};

/**
 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
 * @api stable
 */
ol.geom.LineString.prototype.setCoordinates =
    function(coordinates, opt_layout) {
  if (goog.isNull(coordinates)) {
    this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
  } else {
    this.setLayout(opt_layout, coordinates, 1);
    if (goog.isNull(this.flatCoordinates)) {
      this.flatCoordinates = [];
    }
    this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
        this.flatCoordinates, 0, coordinates, this.stride);
    this.changed();
  }
};

/**
 * @param {ol.geom.GeometryLayout} layout Layout.
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 */
ol.geom.LineString.prototype.setFlatCoordinates =
    function(layout, flatCoordinates) {
  this.setFlatCoordinatesInternal(layout, flatCoordinates);
  this.changed();
};
<|endoftext|>