Skip to content

Commit

Permalink
feat(form): enable widget overrides for forms
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas Metzener authored and anehx committed May 21, 2019
1 parent 59c6eff commit 581de15
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 22 deletions.
16 changes: 0 additions & 16 deletions addon/components/cf-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import Component from "@ember/component";
import { getOwner } from "@ember/application";
import layout from "../templates/components/cf-field";
import { task, timeout } from "ember-concurrency";
import { computed } from "@ember/object";
import { inject as service } from "@ember/service";

/**
* Component to display a label and input for a certain field of a document.
Expand All @@ -22,20 +20,6 @@ export default Component.extend({
classNames: ["uk-margin"],
classNameBindings: ["field.question.hidden:uk-hidden"],

calumaOptions: service(),
componentOverride: computed("calumaOptions._overrides.[]", function() {
// During testing the meta object is not necessarily set.
try {
const name = this.field.question.meta.widgetOverride;
const overrides = this.calumaOptions.getComponentOverrides();
if (name && overrides.some(override => override.component === name)) {
return name;
}
} catch (error) {
// Do nothing.
}
}),

/**
* Task to save a field. This will set the passed value to the answer and
* save the field to the API after a timeout off 500 milliseconds.
Expand Down
45 changes: 45 additions & 0 deletions addon/helpers/get-widget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Helper from "@ember/component/helper";
import { inject as service } from "@ember/service";
import { warn } from "@ember/debug";

/**
* Helper for getting the right widget for a field.
*
* This helper expects a field as first positional parameter. It checks if the
* field has a widget override in it's metadata. If one exists it checks if
* said widget was registered in the caluma options service and then returns
* the widget name.
*
* ```hbs
* {{component (get-widget field default="cf-form") foo=bar}}
* ```
*
* @function getWidget
* @param {Array} params
* @param {Object} [options]
* @param {String} [options.default]
*/
export default Helper.extend({
calumaOptions: service(),

compute([field], { default: defaultWidget = "cf-field/input" }) {
try {
const widget = field.question.meta.widgetOverride;
const overrides = this.calumaOptions.getComponentOverrides();
const override = overrides.find(({ component }) => component === widget);

if (!override) {
warn(
`Widget override "${widget}" is not registered. Please register it by calling \`calumaOptions.registerComponentOverride\``,
{ id: "ember-caluma.unregistered-override" }
);

throw new Error();
}

return widget;
} catch (e) {
return defaultWidget;
}
}
});
18 changes: 18 additions & 0 deletions addon/lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ export default EmberObject.extend({
return atob(this.get("raw.id"));
}),

field: computed(
"raw.form.slug",
"parentDocument.{id,fields.@each.id}",
function() {
if (!this.parentDocument) return null;

try {
return this.parentDocument.fields.find(
field =>
field.id ===
`Document:${this.parentDocument.id}:Question:${this.raw.form.slug}`
);
} catch (e) {
return null;
}
}
),

questionJexl: computed(function() {
const questionJexl = new jexl.Jexl();

Expand Down
6 changes: 1 addition & 5 deletions addon/templates/components/cf-field.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
{{/if}}
<div class="uk-flex">
<div class="uk-width-expand">
{{#if componentOverride}}
{{component componentOverride field=field disabled=disabled context=context onSave=(perform save)}}
{{else}}
{{cf-field/input field=field disabled=disabled onSave=(perform save)}}
{{/if}}
{{component (get-widget field) field=field disabled=disabled context=context onSave=(perform save)}}
</div>
{{#if field.question.infoText}}
{{cf-field/info text=field.question.infoText}}
Expand Down
6 changes: 5 additions & 1 deletion addon/templates/components/cf-navigation.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@
</div>

<div class="uk-width-1-1 uk-width-2-3@m">
{{cf-form document=displayedDocument context=context disabled=disabled}}
{{component (get-widget displayedDocument.field default="cf-form")
document=displayedDocument
context=context
disabled=disabled
}}
</div>
{{/if}}
</div>
1 change: 1 addition & 0 deletions app/helpers/get-widget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default, getWidget } from "ember-caluma/helpers/get-widget";
47 changes: 47 additions & 0 deletions tests/integration/helpers/get-widget-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "ember-qunit";
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";

module("Integration | Helper | get-widget", function(hooks) {
setupRenderingTest(hooks);

test("it returns valid overrides", async function(assert) {
const calumaOptions = this.owner.lookup("service:calumaOptions");

calumaOptions.registerComponentOverride({
label: "Some Component",
component: "some-component"
});

await render(
hbs`{{get-widget (hash question=(hash meta=(hash widgetOverride="some-component")))}}`
);

assert.dom(this.element).hasText("some-component");
});

test("it doesn't return an invalid override", async function(assert) {
await render(
hbs`{{get-widget (hash question=(hash meta=(hash widgetOverride="some-component")))}}`
);

assert.dom(this.element).hasText("cf-field/input");
});

test("it has a fallback", async function(assert) {
await render(hbs`{{get-widget null}}`);

assert.dom(this.element).hasText("cf-field/input");

await render(hbs`{{get-widget undefined}}`);

assert.dom(this.element).hasText("cf-field/input");
});

test("it can pass the default widget", async function(assert) {
await render(hbs`{{get-widget null default="cf-form"}}`);

assert.dom(this.element).hasText("cf-form");
});
});

0 comments on commit 581de15

Please sign in to comment.