From ae1174688483fd2103f140524777ba24f7c0d30b Mon Sep 17 00:00:00 2001 From: Juan Benavides Date: Fri, 22 Jan 2016 13:48:53 +0100 Subject: [PATCH] Added Json field --- admin/public/styles/keystone/field-types.less | 2 +- fields/types/json/JsonColumn.js | 1 + fields/types/json/JsonField.js | 58 ++++++++++++++++ fields/types/json/JsonFilter.js | 1 + fields/types/json/JsonType.js | 56 ++++++++++++++++ fields/types/json/Readme.md | 25 +++++++ fields/types/json/test/explorer.js | 11 ++++ fields/types/json/test/type.js | 66 +++++++++++++++++++ lib/fieldTypes.js | 1 + 9 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 fields/types/json/JsonColumn.js create mode 100644 fields/types/json/JsonField.js create mode 100644 fields/types/json/JsonFilter.js create mode 100644 fields/types/json/JsonType.js create mode 100644 fields/types/json/Readme.md create mode 100644 fields/types/json/test/explorer.js create mode 100644 fields/types/json/test/type.js diff --git a/admin/public/styles/keystone/field-types.less b/admin/public/styles/keystone/field-types.less index 1917aa92df..15407f6534 100644 --- a/admin/public/styles/keystone/field-types.less +++ b/admin/public/styles/keystone/field-types.less @@ -5,7 +5,7 @@ -// Code +// Code, JSON // ------------------------------ .CodeMirror-container { diff --git a/fields/types/json/JsonColumn.js b/fields/types/json/JsonColumn.js new file mode 100644 index 0000000000..3f73ebb82e --- /dev/null +++ b/fields/types/json/JsonColumn.js @@ -0,0 +1 @@ +module.exports = require('../text/TextColumn'); diff --git a/fields/types/json/JsonField.js b/fields/types/json/JsonField.js new file mode 100644 index 0000000000..9bfbc895cc --- /dev/null +++ b/fields/types/json/JsonField.js @@ -0,0 +1,58 @@ +import Field from '../Field'; +import React from 'react'; +import { FormInput } from '../../../admin/client/App/elemental'; + + +// See CodeMirror docs for API: +// http://codemirror.net/doc/manual.html + +module.exports = Field.create({ + displayName: 'JsonField', + statics: { + type: 'Json', + }, + onJsonChanged (event) { + let jsonObj = JSON.parse(event.target.value); + this.props.valueChanged(jsonObj); + }, + getJsonValue () { + if (this.props.value != null) { + return JSON.stringify(this.props.value, null, '\t'); + } + return this.props.value; + }, + renderValue () { + const { height } = this.props; + + const styles = { + height: height, + whiteSpace: 'pre-wrap', + overflowY: 'auto', + }; + + return ( + {this.getJsonValue()} + ); + }, + renderField () { + const { height, path, style } = this.props; + + const styles = { + height: height, + ...style, + }; + + return ( + + ); + }, + +}); diff --git a/fields/types/json/JsonFilter.js b/fields/types/json/JsonFilter.js new file mode 100644 index 0000000000..6dc230fcec --- /dev/null +++ b/fields/types/json/JsonFilter.js @@ -0,0 +1 @@ +module.exports = require('../text/TextFilter'); diff --git a/fields/types/json/JsonType.js b/fields/types/json/JsonType.js new file mode 100644 index 0000000000..78b5a0e321 --- /dev/null +++ b/fields/types/json/JsonType.js @@ -0,0 +1,56 @@ +var assign = require('object-assign'); +var FieldType = require('../Type'); +var TextType = require('../text/TextType'); +var util = require('util'); + + +/** + * HTML FieldType Constructor + * @extends Field + * @api public + */ +function json (list, path, options) { + this._nativeType = Object; + this._defaultSize = 'full'; + this.height = options.height || 180; + this._properties = ['editor', 'height']; + this.codemirror = options.codemirror || {}; + this.editor = assign({ mode: json }, this.codemirror); + json.super_.call(this, list, path, options); +} + +json.properName = 'Json'; +util.inherits(json, FieldType); + +/* Inherit from TextType prototype */ +json.prototype.addFilterToQuery = TextType.prototype.addFilterToQuery; + + +json.prototype.validateInput = function (data, required, item) { + var value = this.getValueFromData(data); + + if (value === undefined && item && (item.get(this.path) || item.get(this.path) === 0)) { + return true; + } + + if (value == null && required) { + return false; + } else if (value == null && !required) { + return true; + } else { + try { + value = this.getValueFromData(data, true); + + if (typeof value !== 'object') { + return false; + } else { + return true; + } + } catch (ex) { + return false; + } + } +}; + +/* Export Field Type */ +module.exports = json; diff --git a/fields/types/json/Readme.md b/fields/types/json/Readme.md new file mode 100644 index 0000000000..593b62993d --- /dev/null +++ b/fields/types/json/Readme.md @@ -0,0 +1,25 @@ +# Json Field +Stores a `Json string` in the model. + +## Example + +```js +{ type: Types.Json, height: 180} +``` + +## Options + +`height` `Number` +The height of the field (in pixels). Default: 180 + + +## Methods + +### Inherits from [`Text`](../text) + +* `addFilterToQuery` +* `validateInput` +* `validateRequiredInput` + +## Filtering +Uses the same logic and filter UI as the [`Text`](../text) field type. diff --git a/fields/types/json/test/explorer.js b/fields/types/json/test/explorer.js new file mode 100644 index 0000000000..07a05f97f8 --- /dev/null +++ b/fields/types/json/test/explorer.js @@ -0,0 +1,11 @@ +module.exports = { + Field: require('../JsonField'), + Filter: require('../JsonFilter'), + readme: require('fs').readFileSync('./fields/types/code/Readme.md', 'utf8'), + section: 'Text', + spec: { + label: 'Json', + path: 'json', + value: '{ name: \'hello world\'}', + }, +}; diff --git a/fields/types/json/test/type.js b/fields/types/json/test/type.js new file mode 100644 index 0000000000..561af84c1f --- /dev/null +++ b/fields/types/json/test/type.js @@ -0,0 +1,66 @@ +const demand = require('must'); +const JsonType = require('../JsonType'); + +exports.initList = function (List) { + List.add({ + json: { type: JsonType }, + nested: { + json: { type: JsonType }, + }, + }); +}; + +exports.createData = function (List) { // eslint-disable-line no-unused-vars + +}; + +exports.testFilters = function (List) { // eslint-disable-line no-unused-vars + +}; + + +exports.testFieldType = function (List) { + describe('updateItem', function () { + it('should update top level fields', function (done) { + var testItem = new List.model(); + + List.fields.json.updateItem(testItem, { + json: '{foo:bar}', + }, + function () { + demand(testItem.json).be('{foo:bar}'); + done(); + }); + }); + + + it('should update nested fields', function (done) { + var testItem = new List.model(); + List.fields['nested.json'].updateItem(testItem, { + nested: { + json: '{foo:bar}', + }, + }, + function () { + demand(testItem.nested.json).be('{foo:bar}'); + done(); + }); + }); + + + it('should update nested fields with flat paths', function (done) { + var testItem = new List.model(); + List.fields['nested.json'].updateItem(testItem, { + 'nested.json': '{foo:bar}', + }, + function () { + demand(testItem.nested.json).be('{foo:bar}'); + done(); + }); + }); + + + }); + + +}; diff --git a/lib/fieldTypes.js b/lib/fieldTypes.js index 750395deba..ecaeec6bf6 100644 --- a/lib/fieldTypes.js +++ b/lib/fieldTypes.js @@ -13,6 +13,7 @@ var fields = { get File () { return require('../fields/types/file/FileType'); }, get GeoPoint () { return require('../fields/types/geopoint/GeoPointType'); }, get Html () { return require('../fields/types/html/HtmlType'); }, + get Json () { return require('../fields/types/json/JsonType'); }, get Key () { return require('../fields/types/key/KeyType'); }, get LocalFile () { return require('../fields/types/localfile/LocalFileType'); }, get LocalFiles () { return require('../fields/types/localfiles/LocalFilesType'); },