diff --git a/README.md b/README.md index b15e7f5..6b7a184 100755 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ Standard text input field. | messageKey | string (unique) | The AppMessage key matching the `messageKey` item defined in your `package.json`. Set this to a unique string to allow this item to be looked up using `Clay.getItemsByMessageKey()` in your custom function. You must set this if you wish for the value of this item to be persisted after the user closes the config page. | | label | string | The label that should appear next to this item. | | defaultValue | string | The default value of the input field. | +| serializeValueAs | string | target type to serialize value as. `string` means as is via cstring. `integer` means converted with `Math.trunc(Number.parseInt(value, 10))` as int32 (0 if NaN) | | description | string | Optional sub-text to include below the component | | attributes | object | An object containing HTML attributes to set on the input field. Set `type` to values such as "email", "time", "date" etc to adjust the behavior of the component. | | capabilities | array | Array of features that the connected watch must have for this item to be present | @@ -243,6 +244,7 @@ A dropdown menu containing multiple options. | defaultValue | string | The default value of the dropdown menu. Must match a value in the `options` array. | | description | string | Optional sub-text to include below the component | | options | array of objects | The options you want to appear in the dropdown menu. Each option is an object with a `label` and `value` property. | +| serializeValueAs | string | target type to serialize value as. `string` means as is via cstring. `integer` means converted with `Math.trunc(Number.parseInt(value, 10))` as int32 (0 if NaN) | | capabilities | array | Array of features that the connected watch must have for this item to be present | | group | string | Set this to allow this item, along with other items sharing the same group to be looked up using `Clay.getItemsByGroup()` in your [custom function](#custom-function) | @@ -417,6 +419,7 @@ A list of options allowing the user can only choose one option to submit. | defaultValue | string | The default selected item. Must match a value in the `options` array. | | description | string | Optional sub-text to include below the component | | options | array of objects | The options you want to appear in the radio group. Each option is an object with a `label` and `value` property. | +| serializeValueAs | string | target type to serialize value as. `string` means as is via cstring. `integer` means converted with `Math.trunc(Number.parseInt(value, 10))` as int32. (0 if NaN) | | capabilities | array | Array of features that the connected watch must have for this item to be present | | group | string | Set this to allow this item, along with other items sharing the same group to be looked up using `Clay.getItemsByGroup()` in your [custom function](#custom-function) | diff --git a/index.d.ts b/index.d.ts index 9002916..8962805 100644 --- a/index.d.ts +++ b/index.d.ts @@ -26,6 +26,7 @@ interface ClayConfigItem { label?: string; attributes?: Record; options?: unknown[]; + serializeValueAs?: string, items?: ClayConfigItem[]; capabilities?: string[]; group?: string; diff --git a/src/scripts/components/input.js b/src/scripts/components/input.js index 23e3d6b..a978e90 100644 --- a/src/scripts/components/input.js +++ b/src/scripts/components/input.js @@ -7,6 +7,7 @@ module.exports = { manipulator: 'val', defaults: { label: '', + serializeValueAs: 'string', description: '', attributes: {} } diff --git a/src/scripts/components/radiogroup.js b/src/scripts/components/radiogroup.js index c3f7642..158d501 100644 --- a/src/scripts/components/radiogroup.js +++ b/src/scripts/components/radiogroup.js @@ -8,6 +8,7 @@ module.exports = { defaults: { label: '', options: [], + serializeValueAs: 'string', description: '', attributes: {} } diff --git a/src/scripts/components/select.js b/src/scripts/components/select.js index e4b448b..d75a09c 100644 --- a/src/scripts/components/select.js +++ b/src/scripts/components/select.js @@ -8,6 +8,7 @@ module.exports = { defaults: { label: '', options: [], + serializeValueAs: 'string', description: '', attributes: {} }, @@ -17,7 +18,7 @@ module.exports = { var $value = self.$element.select('.value'); /** - * Updates the HTML value of the component to match the slected option's label + * Updates the HTML value of the component to match the selected option's label * @return {void} */ function setValueDisplay() { diff --git a/src/scripts/lib/manipulators.js b/src/scripts/lib/manipulators.js index baf69e7..f6ddae6 100755 --- a/src/scripts/lib/manipulators.js +++ b/src/scripts/lib/manipulators.js @@ -73,10 +73,19 @@ module.exports = { }, val: { get: function() { - return this.$manipulatorTarget.get('value'); + let value = this.$manipulatorTarget.get('value'); + switch (this.config.serializeValueAs) { + case 'integer': + let integerValue = Math.trunc(Number.parseInt(value, 10)); + return Number.isNaN(integerValue) ? 0 : integerValue; + default: + return value; + } }, set: function(value) { - if (this.get() === value.toString(10)) { return this; } + let currentValue = this.$manipulatorTarget.get('value'); + if (typeof currentValue !== 'undefined' && + currentValue === value.toString(10)) { return this; } this.$manipulatorTarget.set('value', value); return this.trigger('change'); }, @@ -116,12 +125,21 @@ module.exports = { }, radiogroup: { get: function() { - return this.$element.select('input:checked').get('value'); + let value = this.$element.select('input:checked').get('value'); + switch (this.config.serializeValueAs) { + case 'integer': + let integerValue = Math.trunc(Number.parseInt(value, 10)); + return Number.isNaN(integerValue) ? 0 : integerValue; + default: + return value; + } }, set: function(value) { - if (this.get() === value.toString(10)) { return this; } + let currentValue = this.$element.select('input:checked').get('value'); + if (typeof currentValue !== 'undefined' && + currentValue === value.toString(10)) { return this; } this.$element - .select('input[value="' + value.replace('"', '\\"') + '"]') + .select('input[value="' + value.toString(10).replace('"', '\\"') + '"]') .set('checked', true); return this.trigger('change'); }, diff --git a/test/spec/lib/manipulators.js b/test/spec/lib/manipulators.js index 4cf2ee4..ada96e6 100644 --- a/test/spec/lib/manipulators.js +++ b/test/spec/lib/manipulators.js @@ -161,13 +161,63 @@ describe('manipulators', function() { }); describe('val', function() { - var type = 'input'; - testSetGet(type, 'test321'); - testSetGet(type, 1234, '1234'); - testDisable(type); - testEnable(type); - testShow(type); - testHide(type); + let stringInputType = { + type: 'input', + serializeValueAs: 'string' + }; + + let integerInputType = { + type: 'input', + serializeValueAs: 'integer' + }; + + let stringSelectType = { + type: 'select', + defaultValue: 'value-1', + options: [ + { label: 'label 1', value: '1' }, + { label: 'label 2', value: '2' }], + serializeValueAs: 'string' + }; + + let integerSelectType = { + type: 'select', + defaultValue: 'value-1', + options: [ + { label: 'label 1', value: '1' }, + { label: 'label 2', value: '2' }], + serializeValueAs: 'integer' + }; + + testSetGet(stringInputType, 'test321'); + testSetGet(stringInputType, 1234, '1234'); + testSetGet(integerInputType, 'test321', 0); + testSetGet(integerInputType, 1234); + + testSetGet(stringSelectType, '1'); + testSetGet(stringSelectType, 2, '2'); + testSetGet(integerSelectType, 1); + testSetGet(integerSelectType, '2', 2); + + testDisable(stringInputType); + testDisable(integerInputType); + testDisable(stringSelectType); + testDisable(integerSelectType); + + testEnable(stringInputType); + testEnable(integerInputType); + testEnable(stringSelectType); + testEnable(integerSelectType); + + testHide(stringInputType); + testHide(integerInputType); + testHide(stringSelectType); + testHide(integerSelectType); + + testShow(stringInputType); + testShow(integerInputType); + testShow(stringSelectType); + testShow(integerSelectType); }); describe('slider', function() { @@ -203,22 +253,54 @@ describe('manipulators', function() { }); describe('radiogroup', function() { - var type = { + var stringType = { type: 'radiogroup', clayId: 1, options: [ { label: '1', value: 'one' }, { label: '2', value: 'two' }, - { label: '3', value: 'three "quote' } - ] + { label: '3', value: 'three "quote' }, + { label: '4', value: 4 }, + { label: '5', value: '5 with text after' }, + { label: '5', value: '6.5' } + ], + serializeValueAs: 'string' }; - testSetGet(type, 'one'); - testSetGet(type, 'two'); - testSetGet(type, 'three "quote'); - testDisable(type); - testEnable(type); - testShow(type); - testHide(type); + + var integerType = { + type: 'radiogroup', + clayId: 1, + options: [ + { label: '1', value: 'one' }, + { label: '2', value: 'two' }, + { label: '3', value: 'three "quote' }, + { label: '4', value: 4 }, + { label: '5', value: '5 with text after' }, + { label: '5', value: '6.5' } + ], + serializeValueAs: 'integer' + }; + + testSetGet(stringType, 'one'); + testSetGet(stringType, 'two'); + testSetGet(stringType, 'three "quote'); + testSetGet(stringType, '4'); + testSetGet(stringType, '5 with text after'); + testSetGet(stringType, '6.5'); + testSetGet(integerType, 'one', 0); + testSetGet(integerType, 'two', 0); + testSetGet(integerType, 'three "quote', 0); + testSetGet(integerType, 4, 4); + testSetGet(integerType, '5 with text after', 5); + testSetGet(integerType, '6.5', 6); + testDisable(stringType); + testDisable(integerType); + testEnable(stringType); + testEnable(integerType); + testShow(stringType); + testShow(integerType); + testHide(stringType); + testHide(integerType); }); describe('checkboxgroup', function() {