From b3bd7d4bceb956960a08340231fd188b18d0448a Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 8 Jun 2018 18:23:47 +0300 Subject: [PATCH 01/49] erp5_web_renderjs_ui: use 'error' class for validation errors i need it because use span for displaying icons in json form --- .../web_page_module/rjs_gadget_erp5_label_field_js.js | 1 + .../web_page_module/rjs_gadget_erp5_nojqm_css.css | 8 ++++---- .../portal_skins/erp5_web_renderjs_ui/erp5css.less.txt | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_label_field_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_label_field_js.js index 29a23fe1c65..61e310aba85 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_label_field_js.js +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_label_field_js.js @@ -141,6 +141,7 @@ if (this.state.error_text) { if (span === null) { span = document.createElement('span'); + span.setAttribute('class', 'error'); span.textContent = this.state.error_text; this.props.container_element.appendChild(span); } else { diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css index 57a10bb18fd..28976ae0d76 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css @@ -1190,11 +1190,11 @@ div[data-gadget-scope='header'] .ui-header ul { .gadget-content form .ui-field-contain { position: relative; } -.gadget-content form .ui-field-contain > span { +.gadget-content form .ui-field-contain > span.error { animation: fadein 0.2s ease-out; } @media not screen and (max-width: 85em), only screen and (min-width: 45em) and (max-width: 85em) { - .gadget-content form .ui-field-contain > span { + .gadget-content form .ui-field-contain > span.error { background-color: #FF6600; color: #f8fff3; left: 25%; @@ -1206,7 +1206,7 @@ div[data-gadget-scope='header'] .ui-header ul { width: auto; z-index: 1001; } - .gadget-content form .ui-field-contain > span:before { + .gadget-content form .ui-field-contain > span.error:before { position: absolute; top: 100%; left: 2em; @@ -1218,7 +1218,7 @@ div[data-gadget-scope='header'] .ui-header ul { } } @media not screen and (min-width: 45em) { - .gadget-content form .ui-field-contain > span { + .gadget-content form .ui-field-contain > span.error { margin-left: 6pt; color: #FF6600; } diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt index bb41eb40380..a89dd34ce48 100644 --- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt +++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt @@ -1403,7 +1403,7 @@ div[data-gadget-scope='header'] .ui-header { // relative for displaying popups with errors position: relative; - & > span { + & > span.error { animation: fadein @transition-timing; @media @desktop, @tablet { -- 2.30.9 From cc913d0758d2b3df6fa2d43a74c4c5fc81c0768f Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 11 Jun 2018 15:09:32 +0000 Subject: [PATCH 02/49] erp5_json_form: initial add --- .../portal_skins/erp5_json_form.xml | 26 + .../erp5_json_form/json-schema.xml | 26 + .../json-schema/schema4.json.json | 149 ++ .../json-schema/schema4.json.xml | 28 + .../json-schema/schema6.json.json | 154 ++ .../json-schema/schema6.json.xml | 28 + .../json-schema/schema7.json.json | 168 ++ .../json-schema/schema7.json.xml | 28 + .../jsonform.gadget.appcache.appcache | 22 + .../jsonform.gadget.appcache.xml | 28 + .../erp5_json_form/jsonform.gadget.html.html | 16 + .../erp5_json_form/jsonform.gadget.html.xml | 28 + .../erp5_json_form/jsonform.gadget.js.js | 619 ++++++ .../erp5_json_form/jsonform.gadget.js.xml | 28 + .../portal_skins/erp5_json_form/jsonform.xml | 26 + ...gadget_json_generated_form_child.html.html | 18 + .../gadget_json_generated_form_child.html.xml | 28 + .../gadget_json_generated_form_child.js.js | 1430 ++++++++++++++ .../gadget_json_generated_form_child.js.xml | 28 + .../erp5_json_form/jsonform/tv4.js.js | 1687 +++++++++++++++++ .../erp5_json_form/jsonform/tv4.js.xml | 28 + bt5/erp5_json_form/bt/comment | 2 + bt5/erp5_json_form/bt/dependency_list | 1 + bt5/erp5_json_form/bt/description | 1 + bt5/erp5_json_form/bt/maintainer_list | 1 + bt5/erp5_json_form/bt/template_format_version | 1 + bt5/erp5_json_form/bt/template_skin_id_list | 1 + bt5/erp5_json_form/bt/title | 1 + bt5/erp5_json_form/bt/version | 1 + 29 files changed, 4602 insertions(+) create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.json create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.json create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.json create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.appcache create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.html create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.xml create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js create mode 100644 bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.xml create mode 100644 bt5/erp5_json_form/bt/comment create mode 100644 bt5/erp5_json_form/bt/dependency_list create mode 100644 bt5/erp5_json_form/bt/description create mode 100644 bt5/erp5_json_form/bt/maintainer_list create mode 100644 bt5/erp5_json_form/bt/template_format_version create mode 100644 bt5/erp5_json_form/bt/template_skin_id_list create mode 100644 bt5/erp5_json_form/bt/title create mode 100644 bt5/erp5_json_form/bt/version diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form.xml new file mode 100644 index 00000000000..cdba2281157 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form.xml @@ -0,0 +1,26 @@ + + + + + + + + + + _objects + + + + + + id + erp5_json_form + + + title + + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema.xml new file mode 100644 index 00000000000..cbafac43b5a --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema.xml @@ -0,0 +1,26 @@ + + + + + + + + + + _objects + + + + + + id + json-schema + + + title + + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.json b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.json new file mode 100644 index 00000000000..bcbb84743e3 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.json @@ -0,0 +1,149 @@ +{ + "id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "$schema": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.xml new file mode 100644 index 00000000000..e70369b20d7 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema4.json.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + schema4.json + + + content_type + application/json + + + precondition + + + + title + schema4.json + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.json b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.json new file mode 100644 index 00000000000..5656240b947 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.json @@ -0,0 +1,154 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "http://json-schema.org/draft-06/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "examples": { + "type": "array", + "items": {} + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": {}, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": {} +} diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.xml new file mode 100644 index 00000000000..00ece57f36b --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema6.json.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + schema6.json + + + content_type + application/json + + + precondition + + + + title + schema6.json + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.json b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.json new file mode 100644 index 00000000000..5bee90ec141 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.json @@ -0,0 +1,168 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$comment": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "readOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": true + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": true, + "enum": { + "type": "array", + "items": true, + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentEncoding": { "type": "string" }, + "if": {"$ref": "#"}, + "then": {"$ref": "#"}, + "else": {"$ref": "#"}, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": true +} diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.xml new file mode 100644 index 00000000000..4bad30d30d2 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/json-schema/schema7.json.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + schema7.json + + + content_type + application/json + + + precondition + + + + title + schema7.json + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.appcache b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.appcache new file mode 100644 index 00000000000..fd6fcdb868c --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.appcache @@ -0,0 +1,22 @@ +#shared +rsvp.js +renderjs.js +handlebars.js +gadget_erp5_nojqm.css + +gadget_erp5_global.js +gadget_html5_select.html +gadget_html5_select.js + +#jsonform +jio.js +gadget_html5_select.html +gadget_html5_select.js +json-schema/schema4.json +json-schema/schema6.json +json-schema/schema7.json +jsonform.gadget.html +jsonform.gadget.js +jsonform/gadget_json_generated_form_child.html +jsonform/gadget_json_generated_form_child.js +jsonform/tv4.js diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.xml new file mode 100644 index 00000000000..63b3403ef8f --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.appcache.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + jsonform.gadget.appcache + + + content_type + text/cache-manifest + + + precondition + + + + title + jsonform.gadget.appcache + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.html b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.html new file mode 100644 index 00000000000..8f38c203d1f --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.html @@ -0,0 +1,16 @@ + + + + + + ERP5 + + + + + + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.xml new file mode 100644 index 00000000000..d63d0617dcc --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + jsonform.gadget.html + + + content_type + text/html + + + precondition + + + + title + schema.gadget.html + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js new file mode 100644 index 00000000000..2701dfdb0a4 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -0,0 +1,619 @@ +/*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/ +/*global window, document, URL, rJS, RSVP, jIO, tv4, location */ + +(function (window, document, location, rJS, RSVP, jIO, tv4) { + "use strict"; + var expandSchema; + + function decodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~1/g, '/').replace(/~0/g, '~'); + } + + function encodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~/g, '~0').replace(/\//g, '~1'); + } + + function getMaxPathInDict(dict, path) { + var target, + key, + max_len = 0; + if (!path) { + return ""; + } + for (key in dict) { + if (dict.hasOwnProperty(key) && + path.startsWith(key) && + key.length > max_len) { + target = key; + max_len = key.length; + } + } + return target; + } + + function checkCircular(g, path, url) { + var required_stack, + idx, + prev_field_path = getMaxPathInDict(g.props.schema_required_urls, path); + required_stack = g.props.schema_required_urls[prev_field_path] || []; + idx = required_stack.indexOf(url); + if (idx >= 0) { + if (path === prev_field_path && idx === 0) { + return; + } + throw new Error("Circular reference detected"); + } + g.props.schema_required_urls[path] = [url].concat(required_stack); + } + + function convertToRealWorldSchemaPath(g, path) { + var url, + hash, + map = g.props.schema_map, + prev_downl_path, + max_len = 0; + if (!path) { + return ""; + } + // previous downloaded path + prev_downl_path = getMaxPathInDict(map, path); + if (prev_downl_path === undefined) { + url = ""; + max_len = 0; + } else { + url = map[prev_downl_path]; + if (prev_downl_path === "/") { + max_len = 0; + } else { + max_len = prev_downl_path.length; + } + } + hash = path.substr(max_len); + if (hash) { + // XXX urlencode for hash + if (url.indexOf("#") >= 0) { + url = url + hash; + } else { + url = url + "#" + hash; + } + } + return url; + } + + function convertUrlToAbsolute(g, path, url, base_url_failback) { + var // previous downloaded path + base_url = convertToRealWorldSchemaPath(g, path), + absolute_url; + if (base_url === "" || base_url.indexOf("#") === 0) { + absolute_url = new URL(url, base_url_failback); + } else { + absolute_url = new URL(url, base_url); + } + return absolute_url; + } + + function downloadJSON(url) { + return RSVP.Queue() + .push(function () { + return jIO.util.ajax({ + url: url, + dataType: "json" + }); + }) + .push(function (evt) { + return evt.target.response; + }); + } + + function resolveLocalReference(schema, ref) { + // 2 here is for #/ + var i, ref_path = ref.substr(2, ref.length), + parts = ref_path.split("/"); + if (parts.length === 1 && parts[0] === "") { + // It was uses #/ to reference the entire json so just return it. + return schema; + } + for (i = 0; i < parts.length; i += 1) { + if (schema === undefined) { + throw new Error("local ref `" + ref + "` does not exist in:"); + } + schema = schema[decodeJsonPointer(parts[i])]; + } + return schema; + } + + function schemaPushSchemaPart(schema, schema_path, schema_part) { + var i, + k, + key_list; + if (schema_path === "/") { + schema_path = ""; + } + key_list = schema_path.split("/"); + for (i = 0; i < key_list.length; i += 1) { + k = decodeJsonPointer(key_list[i]); + if (i === key_list.length - 1) { + if (schema_part !== undefined) { + schema[k] = schema_part; + } else { + return schema[k]; + } + } else { + if (!schema.hasOwnProperty(k)) { + schema[k] = {}; + } + schema = schema[k]; + } + } + } + + function loadJSONSchema(g, $ref, path) { + var protocol, + url, + download_url, + hash, + schema_url_map; + // XXX need use `id` property + if (!path) { + path = "/"; + } + url = convertUrlToAbsolute(g, path, $ref, window.location); + download_url = url.origin + url.pathname; + schema_url_map = { + "http://json-schema.org/draft-04/schema": "json-schema/schema4.json", + "http://json-schema.org/draft-06/schema": "json-schema/schema6.json", + "http://json-schema.org/draft-07/schema": "json-schema/schema7.json", + "http://json-schema.org/schema": "json-schema/schema7.json" + }; + if (schema_url_map.hasOwnProperty(download_url)) { + url = new URL(schema_url_map[download_url], g.__path); + download_url = url.origin + url.pathname; + } + protocol = url.protocol; + if (protocol === "http:" || protocol === "https:") { + if (window.location.protocol !== protocol) { + throw new Error("You cannot mixed http and https calls"); + } + } + hash = url.hash; + url = url.href; + return downloadJSON(download_url) + .push(function (json) { + checkCircular(g, path, url); + return resolveLocalReference(json, hash); + }) + .push(undefined, function (err) { + // XXX it will be great to have ability convert json_pointers(hash) + // in line numbers for pointed to line in rich editors. + // we can use https://github.com/vtrushin/json-to-ast for it + var url_from_pointed = convertToRealWorldSchemaPath(g, path), + schema_a = document.createElement("a"), + pointed_a = document.createElement("a"); + schema_a.setAttribute("href", download_url); + schema_a.text = (new URL(download_url)).pathname; + pointed_a.setAttribute("href", url_from_pointed); + pointed_a.text = (new URL(url_from_pointed)).pathname; + g.props.schema_resolve_errors[url_from_pointed] = { + schemaPath: path, + message: [ + document.createTextNode("schema error: "), + document.createTextNode(err.message), + schema_a, + document.createTextNode(" pointed from schema: "), + pointed_a + ] + }; + return null; // schema part can't be null + }) + .push(function (schema_part) { + // console.log(path); + if (schema_part === null) { + // if resolving schema part contain errors + // use {} as failback + schema_part = {}; + } else { + // save map url only for correctly resolved schema + // otherwise we have issue in convertToRealWorldSchemaPath + g.props.schema_map[path] = url; + } + schemaPushSchemaPart(g.props.schema, path, JSON.parse(JSON.stringify(schema_part))); + // console.log(g.props.schema[""]); + return expandSchema(g, schema_part, path, $ref); + }) + .push(function (schema_arr) { + // if length array > 1 form rendered on demand already + // so not needed circular detection + if (schema_arr.length === 1) { + // XXX need smart circular detection in this place + schema_arr[0].circular = true; + } + return schema_arr; + }); + } + + function allOf(g, schema_array, schema_path) { + return RSVP.Queue() + .push(function () { + var i, + arr = []; + for (i = 0; i < schema_array.length; i += 1) { + arr.push(expandSchema(g, schema_array[i], schema_path + '/allOf/' + i.toString())); + } + return RSVP.all(arr); + }) + .push(function (arr) { + var i, + x, + y, + key, + next_schema, + schema, + schema_item, + summ_arr; + for (i = 0; i < arr.length - 1; i += 1) { + summ_arr = []; + for (x = 0; x < arr[i].length; x += 1) { + for (y = 0; y < arr[i + 1].length; y += 1) { + schema = arr[i][x].schema; + next_schema = arr[i + 1][y].schema; + if (schema === true && next_schema === true) { + schema_item = { + schema: true, + schema_path: arr[i][x].schema_path + }; + } else if (schema === false || next_schema === false) { + schema_item = { + schema: false, + schema_path: arr[i][x].schema_path + }; + } else { + if (schema === true) { + schema = {}; + } + if (next_schema === true) { + next_schema = {}; + } + // copy before change + schema = JSON.parse(JSON.stringify(schema)); + for (key in next_schema) { + if (next_schema.hasOwnProperty(key)) { + if (schema.hasOwnProperty(key)) { + // XXX need use many many rules for merging + schema[key] = next_schema[key]; + } else { + schema[key] = next_schema[key]; + } + } + } + schema_item = { + schema: schema, + schema_path: arr[i][x].schema_path + }; + } + summ_arr.push(schema_item); + } + } + arr[i + 1] = summ_arr; + } + return arr[arr.length - 1]; + }); + } + + function anyOf(g, schema_array, schema_path) { + return RSVP.Queue() + .push(function () { + var i, + arr = []; + for (i = 0; i < schema_array.length; i += 1) { + arr.push(expandSchema(g, schema_array[i], schema_path + '/anyOf/' + i.toString())); + } + return RSVP.all(arr); + }) + .push(function (arr) { + var i, + z, + schema_arr = []; + for (i = 0; i < arr.length; i += 1) { + for (z = 0; z < arr[i].length; z += 1) { + if (arr[i][z].schema === true) { + // or(any, restricted, restricted, .. ) simplify to any + return [arr[i][z]]; + } + schema_arr.push(arr[i][z]); + } + } + return schema_arr; + }); + } + + expandSchema = function (g, schema, schema_path, ref) { + // XXX `if then else` construction can be simplify to + // anyOf(allOf(if_schema, then_schema), else_schema) + // and realized by existed rails + if (schema === undefined) { + schema = true; + } + if (schema.anyOf !== undefined) { + return anyOf(g, schema.anyOf, schema_path); + } + if (schema.allOf !== undefined) { + return allOf(g, schema.allOf, schema_path); + } + if (schema.$ref) { + return loadJSONSchema(g, schema.$ref, schema_path); + } + return RSVP.Queue() + .push(function () { + return [{ + title: ref || schema.title, + schema: schema, + schema_path: schema_path + }]; + }); + }; + + function expandSchemaForField(g, schema, schema_path, for_required) { + var required_stack, + prev_field_path; + if (for_required) { + prev_field_path = getMaxPathInDict(g.props.schema_required_urls, schema_path); + required_stack = g.props.schema_required_urls[prev_field_path]; + } else { + required_stack = []; + } + g.props.schema_required_urls[schema_path] = required_stack; + return expandSchema(g, schema, schema_path); + } + + rJS(window) + .ready(function () { + var g = this; + g.props = {}; + g.options = {}; + }) + .declareAcquiredMethod("notifyChange", "notifyChange") + .allowPublicAcquisition("notifyChange", function () { + return this.notifyChange(); + }) + .declareAcquiredMethod("notifyValid", "notifyValid") + .declareAcquiredMethod("notifyInvalid", "notifyInvalid") + .allowPublicAcquisition("checkValidity", function (arr) { + return this.checkValidity(arr[0]); + }) + .declareMethod('checkValidity', function (json_document) { + // XXX need use local schema and local json document + // in every subgadget to take into account user anyOf choice + // and so more precisely point to issue + var g = this.props.form_gadget, + gadget = this; + return RSVP.Queue() + .push(function () { + if (json_document === undefined) { + return g.getContent(); + } + return json_document; + }) + .push(function (json_d) { + return tv4.validateMultiple(json_d, gadget.props.schema[""]); + }) + .push(function (validation) { + var i, + error_id, + error, + span, + tasks = [], + errors = [], + schema_resolve_errors = gadget.props.schema_resolve_errors, + errors_block = g.element.querySelector("div.error-block"); + + if (errors_block) { + errors_block.parentNode.removeChild(errors_block); + } + g.element.querySelectorAll(".error").forEach(function (error_message) { + error_message.textContent = ""; + error_message.removeAttribute("id"); + error_message.hidden = true; + }); + + g.element.querySelectorAll("div.error-input").forEach(function (div) { + div.setAttribute("class", ""); + }); + + for (i in schema_resolve_errors) { + if (schema_resolve_errors.hasOwnProperty(i)) { + errors.push(schema_resolve_errors[i]); + } + } + + errors = errors.concat(validation.errors); + errors = errors.concat(validation.missing); + + if (errors.length === 0) { + return gadget.notifyValid() + .push(function () { + return false; + }); + } + span = document.createElement("span"); + span.setAttribute("class", "error"); + span.textContent = "errors: "; + errors_block = document.createElement("div"); + errors_block.setAttribute("class", "subfield error-block"); + errors_block.appendChild(span); + + function print_error(error, errorUid, errorId) { + return function (element) { + var id = element.id, + error_message, + createTextNode = document.createTextNode.bind(document), + a = document.createElement("a"); + a.setAttribute("href", "#" + errorUid); + a.text = errorId; + element.setAttribute("class", "error-input"); + error_message = element.querySelector("#" + id.replace(/\//g, "\\/") + " > .error"); + error_message.appendChild(a); + error_message.setAttribute("id", errorUid); + if (error.message instanceof Array) { + error.message.forEach(function (x) { + error_message.appendChild(x); + }); + } else { + error_message.appendChild(createTextNode(error.message)); + } + error_message.hidden = false; + + a = document.createElement("a"); + a.text = errorId; + a.setAttribute("data-error-link", "#" + errorUid); + a.setAttribute("class", "error-link"); + if (errorId !== "1") { + errors_block.appendChild(createTextNode(",")); + } + errors_block.appendChild(a); + }; + } + for (i = 0; i < errors.length; i += 1) { + error = errors[i]; + error_id = (i + 1).toString(); + tasks.push( + g.getElementByPath(error.dataPath || "/") + .push(print_error(error, "error" + error_id, error_id)) + ); + } + + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }) + .push(function () { + g.element.insertBefore(errors_block, g.element.firstChild); + }) + .push(gadget.notifyInvalid.bind(gadget)) + .push(function () { + return false; + }); + }); + }) + + .declareMethod('render', function (options) { + return this.changeState({ + key: options.key, + value: options.value || "", + schema: options.schema, + schema_url: options.schema_url, + editable: options.editable === undefined ? true : options.editable + }); + }) + .onStateChange(function (options) { + var g = this; + g.props.toplevel = true; + // contain map of current normalized schema + // json pointer and corresponding url + // it's need for schema uri computation + g.props.schema = {}; + g.props.schema_map = {}; + // schema_required_urls[path] = [ + // stack required urls, on every unrequired field stack begining from [] + // "url1", + // "url2" + // ] + g.props.schema_required_urls = {}; + // schema_resolve_errors[schema_url] = { + // schemaPath: local_schema_path, + // message: error_message can be array containing dom elements + // } + g.props.schema_resolve_errors = {}; + return RSVP.Queue() + .push(function () { + if (!g.props.form_gadget) { + return g.declareGadget('jsonform/gadget_json_generated_form_child.html', + {scope: "j" + Math.random().toString(36).substr(2, 9)}) + .push(function (json_form_child) { + g.props.form_gadget = json_form_child; + g.element.appendChild(json_form_child.element); + }); + } + }) + .push(function () { + if (options.schema) { + return options.schema; + } + var schema_url = options.schema_url || + (options.value && options.value.$schema); + if (schema_url) { + return loadJSONSchema(g, schema_url) + .push(function (schema_arr) { + return schema_arr[0].schema; + }); + } + return {}; + }) + .push(function (schema) { + g.options.schema = schema; + return g.props.form_gadget.renderForm({ + schema: schema, + schema_path: "", + document: options.value, + required: true, + top: true + }); + }) + .push(function () { + return g.checkValidity(); + }) + .push(function () { + return g; + }); + }) + .allowPublicAcquisition("expandSchema", function (arr) { + return expandSchemaForField(this, arr[0], arr[1], arr[2]); + }) + .onEvent('click', function (evt) { + if (evt.target === this.props.delete_button) { + return this.selfRemove(evt); + } + + var link = evt.target.getAttribute("data-error-link"), + button_list = this.props.add_buttons, + i; + if (link) { + location.href = link; + return; + } + + for (i = 0; i < button_list.length; i = i + 1) { + if (evt.target === button_list[i].element) { + return button_list[i].event(evt); + } + } + }) + .declareJob('listenEvents', function () { + // XXX Disable + return; + }) + + .declareMethod('getContent', function () { + var g = this; + if (g.state.editable) { + return g.props.form_gadget.getContent() + .push(function (value) { + // Change the value state in place + // This will prevent the gadget to be changed if + // its parent call render with the same value + // (as ERP5 does in case of formulator error) + g.state.value = value; + if (g.state.key) { + var form_data = {}; + value = JSON.stringify(value); + form_data[g.state.key] = value; + return form_data; + } + return value; + }); + } + return {}; + }); + +}(window, document, location, rJS, RSVP, jIO, tv4)); \ No newline at end of file diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml new file mode 100644 index 00000000000..15b61f4d1bd --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + jsonform.gadget.js + + + content_type + application/javascript + + + precondition + + + + title + schema.gadget.js + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.xml new file mode 100644 index 00000000000..e95a62ff6f9 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.xml @@ -0,0 +1,26 @@ + + + + + + + + + + _objects + + + + + + id + jsonform + + + title + + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html new file mode 100644 index 00000000000..a607a22de3d --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html @@ -0,0 +1,18 @@ + + + + + + ERP5 + + + + + + + + +
+
+ + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.xml new file mode 100644 index 00000000000..64890d6898d --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + gadget_json_generated_form_child.html + + + content_type + text/html + + + precondition + + + + title + gadget_json_generated_form_child.html + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js new file mode 100644 index 00000000000..2b7aa497730 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -0,0 +1,1430 @@ +/*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/ +/*global window, document, URL, rJS, RSVP, jIO, tv4, location */ + +(function (window, document, location, rJS, RSVP, jIO, tv4) { + "use strict"; + var render_object; + + function decodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~1/g, '/').replace(/~0/g, '~'); + } + + function encodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~/g, '~0').replace(/\//g, '~1'); + } + + function getDocumentType(doc) { + if (doc instanceof Array) { + return "array"; + } + return typeof doc; + } + + function createElement(type, props) { + var element = document.createElement(type), + key; + for (key in props) { + if (props.hasOwnProperty(key)) { + element.setAttribute(key, props[key]); + } + } + return element; + } + + function getDocumentSchema(doc) { + var type = getDocumentType(doc), + schema = { + type: type + }; + if (type === "array") { + schema.maxItems = 0; + } else if (type === "object") { + schema.additionalProperties = false; + } else { + schema.readOnly = true; + } + return schema; + } + + function render_selection(schema, json_document) { + var input = document.createElement("select"), + option, + i, + enum_arr = schema['enum']; + input.size = 1; + if (schema.default) { + if (json_document === undefined) { + json_document = schema.default; + } + } else { + option = document.createElement("option"); + option.value = ""; + if (json_document === undefined) { + option.selected = true; + } + input.appendChild(option); + } + for (i = 0; i < enum_arr.length; i += 1) { + if (enum_arr.hasOwnProperty(i)) { + option = document.createElement("option"); + option.value = enum_arr[i]; + option.textContent = enum_arr[i]; + if (enum_arr[i] === json_document) { + option.selected = true; + } + input.appendChild(option); + } + } + return input; + } + + function render_boolean(schema, json_document) { + var input, + schema_for_selection = { + type: "boolean", + enum: [true, false] + }; + // XXX change json_document on open is not correct @bk + if (json_document === "true") { + json_document = true; + } + if (json_document === "false") { + json_document = false; + } + if (getDocumentType(schema.default) === "boolean") { + schema_for_selection.default = schema.default; + } + input = render_selection(schema_for_selection, json_document); + input.setAttribute('data-json-type', "boolean"); + return input; + } + + function render_textarea(json_field, default_value, data_format) { + var input = document.createElement("textarea"); + if (default_value !== undefined) { + if (default_value instanceof Array) { + input.value = default_value.join("\n"); + } else { + input.value = default_value; + } + } + input["data-format"] = data_format; + return input; + } + + function addSubForm(options) { + var input_element = options.element, + g = options.gadget, + property_name, + parent_path, + scope; + + scope = "j" + Math.random().toString(36).substr(2, 9); + if (options.parent_type !== "array") { + parent_path = options.path; + property_name = options.property_name; + if (!property_name) { + property_name = input_element.value; + } + if (!property_name) { + // XXX notify user + // you can't create property without property_name + return RSVP.Queue(); + } + if (g.props.objects[parent_path].hasOwnProperty(property_name) && g.props.objects[parent_path][property_name] !== "") { + // XXX notify user + // you can't create property with existed property_name + return RSVP.Queue(); + } + if (input_element) { + input_element.value = ""; + } + } + + return g.declareGadget('gadget_json_generated_form_child.html', {scope: scope}) + .push(function (form_gadget) { + form_gadget.element.setAttribute("data-gadget-parent-scope", + g.element.getAttribute("data-gadget-scope")); + if (options.parent_type !== "array") { + g.props.objects[parent_path][property_name] = scope; + form_gadget.element.setAttribute("data-json-parent", parent_path); + form_gadget.element.setAttribute("data-json-property-name", property_name); + } + return form_gadget.renderForm({ + type: options.type, + required: options.required, + delete_button: options.delete_button, + schema: options.schema_part, + schema_path: options.schema_path, + document: options.default_dict, + display_label: options.parent_type !== "array", + scope: scope + }); + }); + } + + function expandProperties(g, properties, schema_path, required) { + var ret_obj = {}; + return RSVP.Queue() + .push(function () { + var property_name, + arr = []; + function addPropertyName(p_name) { + return function (schema_array) { + ret_obj[p_name] = schema_array; + }; + } + for (property_name in properties) { + if (properties.hasOwnProperty(property_name)) { + arr.push( + g.expandSchema( + properties[property_name], + schema_path + encodeJsonPointer(property_name), + required.indexOf(property_name) >= 0 + ) + .push(addPropertyName(property_name)) + ); + } + } + return RSVP.all(arr); + }) + .push(function () { + return ret_obj; + }); + } + + function checkSchemaArrOneChoise(schema_arr) { + if (schema_arr.length === 1) { + if (schema_arr[0].schema === true) { + return false; + } + if (schema_arr[0].schema.type instanceof Array) { + return schema_arr[0].schema.type.length <= 1; + } + return true; + } + return false; + } + + function checkSchemaSimpleType(schema) { + return [ + 'string', + 'integer', + 'number', + 'boolean', + 'null' + ].indexOf(schema.type) >= 0; + } + + function convertExpandedProperties2array(properties) { + var property_name, + arr = [], + i, + schema_array; + for (property_name in properties) { + if (properties.hasOwnProperty(property_name)) { + schema_array = properties[property_name]; + for (i = 0; i < schema_array.length; i += 1) { + // add propertyName to title + if (schema_array[i].title && schema_array.length > 1) { + schema_array[i].title = property_name + ' /' + schema_array[i].title; + } else { + schema_array[i].title = property_name; + } + // add propertyName to schemaItem + schema_array[i].property_name = property_name; + arr.push(schema_array[i]); + } + } + } + return arr; + } + + function schemaArrFilteredByDocument(schema_arr, json_document) { + var i, + flag, + ret_arr = [], + schema; + if (schema_arr.length === 1) { + return schema_arr[0]; + } + if (json_document !== undefined) { + for (i = 0; i < schema_arr.length; i += 1) { + schema = schema_arr[i].schema; + if (schema === true) { + flag = true; + } else if (schema === false) { + flag = false; + } else { + flag = tv4.validate(json_document, schema); + } + if (flag) { + ret_arr.push(schema_arr[i]); + } + } + if (ret_arr.length === 0) { + // XXX find schema more compatible with document + return schema_arr[0]; + } + } + // XXX if (ret_arr.length > 1) notify user + return ret_arr[0]; + } + + function checkValidityAndNotifyChange(g) { + return RSVP.all([ + g.checkValidity(), + g.notifyChange() + ]); + } + + function render_schema_selector(gadget, title, schema_arr, event, rerender) { + return RSVP.Queue() + .push(function () { + var schema_alternatives = [], + schema_item, + description, + i, + z, + type; + function generateItemsForAny(property_name, schema_path) { + var desc, + types = [ + "string", + "number", + "boolean", + "array", + "object", + "null" + ], + ii; + if (property_name) { + desc = property_name + " # "; + } else { + desc = ""; + } + for (ii = 0; ii < types.length; ii += 1) { + schema_alternatives.push({ + title: desc + types[ii], + value: { + property_name: property_name, + schema: { type: types[ii] }, + schema_path: schema_path + } + }); + } + } + for (i = 0; i < schema_arr.length; i += 1) { + schema_item = schema_arr[i]; + description = schema_item.title; + if (schema_item.schema === true) { + generateItemsForAny(schema_item.property_name, schema_item.schema_path); + } else if (getDocumentType(schema_item.schema.type) === "array") { + description = description || schema_item.schema.description; + for (z = 0; z < schema_item.schema.type.length; z += 1) { + type = schema_item.schema.type[z]; + schema_alternatives.push({ + title: description + ' # ' + type, + value: { + type: type, + property_name: schema_item.property_name, + schema_path: schema_item.schema_path, + schema: schema_item.schema + } + }); + } + } else { + description = description || + schema_item.schema.type || + schema_item.schema.description; + schema_alternatives.push({ + title: description, + value: { + property_name: schema_item.property_name, + schema_path: schema_item.schema_path, + schema: schema_item.schema + } + }); + } + } + return schema_alternatives; + }) + .push(function (schema_alternatives) { + var scope = 's' + Math.random().toString(36).substr(2, 9); + if (schema_alternatives.length > 1) { + return gadget.declareGadget("../gadget_html5_select.html", {scope: scope}) + .push(function (g) { + return RSVP.Queue() + .push(function () { + var x, + item_list = [[title, title]], + item; + if (rerender) { + return rerender(g, schema_alternatives); + } + for (x = 0; x < schema_alternatives.length; x += 1) { + item = schema_alternatives[x]; + item_list.push([item.title, x]); + } + return { + name: scope, + editable: true, + hidden: item_list.length === 0, + value: item_list[0][1], + item_list: item_list + }; + }) + .push(function (render_options) { + gadget.props.add_custom_data[scope] = { + element: g.element, + event: function () { + return g.getContent() + .push(function (value) { + return event(schema_alternatives[value[scope]].value); + }) + .push(function () { + return checkValidityAndNotifyChange(gadget); + }) + .push(function () { + if (rerender) { + return rerender(g, schema_alternatives); + } + return render_options; + }) + .push(function (render_options) { + return g.render(render_options); + }); + }, + rerender: function () { + return RSVP.Queue() + .push(function () { + if (rerender) { + return rerender(g, schema_alternatives); + } + return render_options; + }) + .push(function (render_options) { + return g.render(render_options); + }); + } + }; + return g.render(render_options); + }) + //not need if gadget_html5_select.render return element + .push(function () { + return g.element; + }); + }); + } + if (schema_alternatives.length === 1) { + return RSVP.Queue() + .push(function () { + if (rerender) { + return rerender(undefined, schema_alternatives); + } + return true; + }) + .push(function (ret) { + var input = document.createElement("button"); + input.setAttribute("class", "ui-btn-icon-notext ui-icon-plus"); + input.type = "button"; + input.title = title; + if (!ret) { + input.setAttribute("style", "display: none;"); + } + gadget.props.add_buttons.push({ + element: input, + event: function () { + return event(schema_alternatives[0].value) + .push(function () { + if (rerender) { + return rerender(undefined, schema_alternatives); + } + return true; + }) + .push(function (r) { + if (!r) { + input.setAttribute("style", "display: none;"); + } else { + input.removeAttribute("style"); + } + return checkValidityAndNotifyChange(gadget); + }); + }, + rerender: function () { + return RSVP.Queue() + .push(function () { + if (rerender) { + return rerender(undefined, schema_alternatives); + } + return true; + }) + .push(function (r) { + if (!r) { + input.setAttribute("style", "display: none;"); + } else { + input.removeAttribute("style"); + } + }); + } + }); + return input; + }); + } + return RSVP.Queue() + .push(function () { + return document.createElement("div"); + }); + }); + } + + function render_array(gadget, schema, json_document, root, path, schema_path) { + var div, + div_input, + input, + minItems = schema.minItems || 0; + div = document.createElement("div"); + div.setAttribute("class", "jsonformfield"); + div.title = schema.description; + + div_input = document.createElement("div"); + div_input.setAttribute("class", "input"); + + function element_append(child) { + if (child) { + input.parentNode.insertBefore(child, input); + } + } + + function div_append(child) { + if (child) { + div_input.appendChild(child); + } + } + + // XXX add failback rendering if json_document not array + // input = render_textarea(schema, default_value, "array"); + return gadget.expandSchema(schema.items, schema_path + '/items', minItems !== 0) + .push(function (schema_arr) { + var queue = RSVP.Queue(), + i, + len = 0; + // XXX rewrite loading document for anyOf schema + if (json_document) { + for (i = 0; i < json_document.length; i = i + 1) { + queue + .push( + addSubForm.bind(gadget, { + gadget: gadget, + parent_type: 'array', + schema_path: schema_path + '/items', + schema_part: schema_arr, + default_dict: json_document[i], + required: i < minItems + }) + ) + .push(div_append); + } + len = json_document.length; + } + + if (checkSchemaArrOneChoise(schema_arr) && minItems > len) { + for (i = 0; i < (minItems - len); i += 1) { + queue + .push( + addSubForm.bind(gadget, { + gadget: gadget, + parent_type: 'array', + schema_path: schema_arr[0].schema_path, + schema_part: schema_arr[0].schema, + required: true + }) + ) + .push(div_append); + } + } + + queue.push(render_schema_selector.bind(gadget, + gadget, "add item to array", + schema_arr, function (value) { + return addSubForm({ + gadget: gadget, + parent_type: 'array', + type: value.type, + schema_path: value.schema_path, + schema_part: value.schema + }) + .push(element_append); + })); + return queue; + }) + .push(function (element) { + // var maxItems = schema.maxItems; + input = element; + // XXX update on every add/delete item + // input.hidden = maxItems !== undefined && json_document.length >= maxItems; + div_input.appendChild(input); + div.appendChild(div_input); + root.appendChild(div); + }); + } + + function render_field(gadget, key, path, json_field, default_value, root, schema_path, options) { + var type, + div, + delete_button, + label, + label_text, + div_input, + span_info, + error_message, + input, + first_path, + queue = RSVP.Queue(); + + if (json_field instanceof Array) { + json_field = schemaArrFilteredByDocument(json_field, default_value); + schema_path = json_field.schema_path; + json_field = json_field.schema; + } + + options = options || {}; + type = options.type; + + if (path && key) { + first_path = path + encodeJsonPointer(key); + } else { + first_path = ""; + } + + if (json_field === undefined) { + json_field = getDocumentSchema(default_value); + } + + if (getDocumentType(json_field.type) === "string") { + type = json_field.type; + } // else json_field.type is array so we use type + if (type === undefined && default_value !== undefined) { + type = getDocumentType(default_value); + } + + // XXX bad peace of code + // i do not sure that type can be computed so + // but our schema in slapos bad + if (!type) { + if (json_field.properties && + json_field.required && + json_field.required.length > 0) { + type = "object"; + } + } + + div = document.createElement("div"); + div.setAttribute("class", "jsonformfield ui-field-contain"); + div.title = json_field.description; + // if (key && !first_path) { + if (options.delete_button === true) { + delete_button = createElement("span", + {"class": "ui-btn-icon-top ui-icon-trash-o"} + ); + gadget.props.delete_button = delete_button; + div.appendChild(delete_button); + } else if (options.top !== true) { + if (options.required) { + delete_button = createElement("span", + {"class": "ui-btn-icon-top ui-icon-circle"} + ); + div.appendChild(delete_button); + } else { + delete_button = createElement("span"); + delete_button.innerHTML = " "; + div.appendChild(delete_button); + } + } + if (false) { + // XXX; + label = document.createElement("input"); + label.value = key; + gadget.props.property_name_edit = label; + } else { + label_text = [key, json_field.title] + .filter(function (v) { return v; }) + .join(" ") + // use non-breaking hyphen + .replace(/-/g, "‑"); + if (label_text) { + if (options.top) { + label = document.createElement("span"); + label.textContent = label_text; + root.appendChild(label); + } else { + label = document.createElement("label"); + label.textContent = label_text; + div.appendChild(label); + } + + } + } + div_input = document.createElement("div"); + div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/'); + div_input.setAttribute("class", "input"); + + if (json_field.enum !== undefined) { + input = render_selection(json_field, default_value); + } + + if (type === "boolean") { + input = render_boolean(json_field, default_value); + } + + if (!input && ["string", "integer", "number"].indexOf(type) >= 0) { + if (json_field.contentMediaType === "text/plain") { + input = render_textarea(json_field, default_value, "string"); + } else { + input = document.createElement("input"); + if (default_value !== undefined) { + input.value = default_value; + } + + if (type === "integer" || type === "number") { + if (default_value === undefined && typeof json_field.default === "number") { + input.value = json_field.default; + } + input.type = "number"; + input.setAttribute("data-json-type", type); + if (type === "integer") { + input.setAttribute("step", "1"); + } + if (type === "number") { + input.setAttribute("step", "any"); + } + } else { + if (default_value === undefined && typeof json_field.default === "string") { + input.value = json_field.default; + } + input.type = "text"; + if (json_field.pattern) { + input.pattern = json_field.pattern; + } + if (json_field.format === 'uri') { + input.type = "url"; + input.spellcheck = false; + } + } + } + } + + if (type === "array") { + queue = render_array( + gadget, + json_field, + default_value, + div_input, + first_path + '/', + schema_path + ); + gadget.props.arrays[first_path + '/'] = div; + } + + if (type === "object") { + queue + .push(function () { + return render_object( + gadget, + json_field, + default_value, + div_input, + first_path + '/', + schema_path + ); + }); + } + + if (input) { + // object and array excluded from + // gadget.props.inputs not contain values + gadget.props.inputs.push(input); + input.name = first_path; + input.required = options.required; + // XXX for gui + //input.setAttribute("class", "slapos-parameter"); + div_input.appendChild(input); + } else { + div.setAttribute("data-json-path", first_path + '/'); + div.setAttribute("data-json-type", type); + } + + if (json_field.info !== undefined) { + span_info = document.createElement("span"); + span_info.textContent = json_field.info; + div_input.appendChild(span_info); + } + error_message = document.createElement("span"); + error_message.setAttribute("class", "error"); + error_message.hidden = true; + div_input.appendChild(error_message); + div.appendChild(div_input); + + return queue + .push(function () { + root.appendChild(div); + return div; + }); + } + + function render_object_additionalProperty(g, title, json_document, path, schema, schema_path, used, element_append) { + var div, + div_input, + input; + + div = document.createElement("div"); + div.setAttribute("class", "jsonformfield"); + // div.title = json_field.description; + + div_input = document.createElement("div"); + div_input.setAttribute("class", "input"); + + input = document.createElement("input"); + input.type = "text"; + input.placeholder = "name of " + title; + div_input.appendChild(input); + + return g.expandSchema(schema, schema_path) + .push(function (schema_arr) { + var queue = RSVP.Queue(), + property_name; + for (property_name in json_document) { + if (json_document.hasOwnProperty(property_name) && !used.hasOwnProperty(property_name)) { + used[property_name] = ""; + queue + .push( + addSubForm.bind(g, { + gadget: g, + property_name: property_name, + path: path, + schema_path: schema_path, + schema_part: schema_arr, + default_dict: json_document[property_name] + }) + ) + .push(element_append); + } + } + queue.push(function () { + return render_schema_selector(g, "add " + title, schema_arr, function (value) { + return addSubForm({ + gadget: g, + element: input, + path: path, + type: value.type, + schema_path: value.schema_path, + schema_part: value.schema + }) + .push(element_append); + }); + }); + return queue; + }) + .push(function (input) { + div_input.appendChild(input); + div.appendChild(div_input); + return div; + }); + } + + render_object = function (g, json_field, default_dict, root, path, schema_path) { + var required = json_field.required || [], + schema_editor = json_field.hasOwnProperty("properties") && + json_field.properties.hasOwnProperty("$schema"), + used_properties = {}, + properties, + selector = {}; + + g.props.objects[path] = used_properties; + + function element_append(child) { + if (child) { + // insert additionalProperty before selector + selector.element.parentNode.insertBefore(child, selector.element); + } + } + + function root_append(child) { + root.appendChild(child); + } + + if (default_dict === undefined) { + default_dict = {}; + } + + return expandProperties(g, json_field.properties, schema_path + '/properties/', required) + .push(function (ret) { + var schema_arr, + q = RSVP.Queue(), + s_o, + key; + properties = ret; + for (key in properties) { + if (properties.hasOwnProperty(key)) { + schema_arr = properties[key]; + s_o = schemaArrFilteredByDocument(schema_arr, default_dict[key]); + if (checkSchemaArrOneChoise(schema_arr)) { + if (required.indexOf(key) >= 0) { + used_properties[key] = false; + q.push(render_field.bind(g, g, key, path, + s_o.schema, default_dict[key], root, s_o.schema_path, {required: true}) + ); + } + if (!used_properties.hasOwnProperty(key) && + !schema_editor && + (checkSchemaSimpleType(s_o.schema) || !s_o.circular) + ) { + used_properties[key] = false; + q.push(render_field.bind(g, g, key, path, + s_o.schema, default_dict[key], root, s_o.schema_path, { + required: false, + delete_button: false + })); + } + } + if (!used_properties.hasOwnProperty(key) && + default_dict.hasOwnProperty(key)) { + used_properties[key] = ""; + q.push( + addSubForm.bind(g, { + gadget: g, + property_name: key, + path: path, + schema_path: s_o.schema_path, + schema_part: s_o.schema, + default_dict: default_dict[key] + }) + ) + .push(root_append); + } + } + } + return q; + }) + .push(function () { + var schema_arr = convertExpandedProperties2array(properties); + return render_schema_selector(g, "add property", schema_arr, function (value) { + used_properties[value.property_name] = ""; + return addSubForm({ + gadget: g, + property_name: value.property_name, + path: path, + type: value.type, + schema_path: value.schema_path, + schema_part: value.schema + }) + .push(function (element) { + var s_e = selector.element; + if (s_e) { + s_e.parentNode.insertBefore(element, s_e); + } + }); + }, + function (gadget_s, schema_alternatives) { + var x, + item_list = [["add property", "add property"]], + item; + if (schema_alternatives) { + for (x = 0; x < schema_alternatives.length; x += 1) { + item = schema_alternatives[x]; + if (!used_properties.hasOwnProperty(item.value.property_name)) { + item_list.push([item.title, x]); + } + } + if (gadget_s) { + return { + name: gadget_s.element.getAttribute('data-gadget-scope'), + editable: true, + hidden: item_list.length === 1, + value: item_list[0][1], + item_list: item_list + }; + } + return item_list.length > 1; + } + }); + }) + .push(function (element) { + selector.element = element; + return root_append(element); + }) + .push(function () { + var queue = RSVP.Queue(), + additionalProperties; + + if (json_field.patternProperties !== undefined) { + // XXX need loop on any pattern properties + if (json_field.patternProperties['.*'] !== undefined) { + queue + .push(render_object_additionalProperty.bind(g, + g, + ".* property", + default_dict, + path, + json_field.patternProperties['.*'], + schema_path + '/patternProperties/.*', + used_properties, + element_append + )) + .push(root_append); + } + } + + if (json_field.additionalProperties === undefined) { + additionalProperties = true; + } else { + additionalProperties = json_field.additionalProperties; + } + if (additionalProperties !== false) { + queue + .push(render_object_additionalProperty.bind(g, + g, + "additional property", + default_dict, + path, + additionalProperties, + schema_path + '/additionalProperties', + used_properties, + element_append + )) + .push(root_append); + } + + return queue; + }) + .push(function () { + var key, + queue = RSVP.Queue(); + for (key in default_dict) { + if (default_dict.hasOwnProperty(key)) { + if (!used_properties.hasOwnProperty(key)) { + queue + .push( + addSubForm.bind(g, { + gadget: g, + property_name: key, + path: path, + schema_path: "", + schema_part: undefined, + default_dict: default_dict[key] + }) + ) + .push(root_append); + } + } + } + return queue; + }); + }; + + function getFormValuesAsJSONDict(g) { + var multi_level_dict = {"": {}}, + count_of_values = 0, + scope, + options = g.props, + array, + path, + key, + i, + len, + queue = RSVP.Queue(); + + function convertOnMultiLevel(d, key, value) { + var ii, + kk, + key_list = key.split("/"); + for (ii = 0; ii < key_list.length; ii += 1) { + kk = decodeJsonPointer(key_list[ii]); + if (ii === key_list.length - 1) { + if (value !== undefined) { + d[kk] = value; + count_of_values += 1; + } else { + return d[kk]; + } + } else { + if (!d.hasOwnProperty(kk)) { + d[kk] = {}; + } + d = d[kk]; + } + } + } + + function recursiveGetContent(scope, path) { + queue + .push(function () { + return g.getDeclaredGadget(scope); + }) + .push(function (gadget) { + return gadget.getContent(); + }) + .push(function (jdict) { + if (jdict === undefined) { + return; + } + convertOnMultiLevel(multi_level_dict, path, jdict); + }); + } + + function getContentAndPushArray(scope, parent_path) { + queue + .push(function () { + return g.getDeclaredGadget(scope); + }) + .push(function (gadget) { + return gadget.getContent(); + }) + .push(function (jdict) { + if (jdict === undefined) { + return; + } + var arr = convertOnMultiLevel(multi_level_dict, parent_path); + if (!(arr instanceof Array)) { + arr = []; + convertOnMultiLevel(multi_level_dict, parent_path, arr); + } + arr.push(jdict); + }); + } + + for (path in options.arrays) { + if (options.arrays.hasOwnProperty(path)) { + array = options.arrays[path] + .querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']"); + len = array.length; + if (len === 0) { + convertOnMultiLevel(multi_level_dict, path.slice(0, -1), []); + } + for (i = 0; i < len; i = i + 1) { + getContentAndPushArray( + array[i].getAttribute('data-gadget-scope'), + // slice remove concluding '/' + path.slice(0, -1) + ); + } + } + } + + for (path in options.objects) { + if (options.objects.hasOwnProperty(path)) { + for (key in options.objects[path]) { + if (options.objects[path].hasOwnProperty(key)) { + scope = options.objects[path][key]; + if (scope) { + recursiveGetContent(scope, path + encodeJsonPointer(key)); + } + } + } + } + } + + return queue + .push(function () { + var json_dict = {}, + k; + g.props.inputs.forEach(function (input) { + if (input.required || input.value !== "") { + var type = input.getAttribute('data-json-type'); + if (type === 'number') { + json_dict[input.name] = parseFloat(input.value); + } else if (type === "integer") { + json_dict[input.name] = parseInt(input.value, 10); + } else if (type === "boolean") { + if (input.value === "true") { + json_dict[input.name] = true; + } else if (input.value === "false") { + json_dict[input.name] = false; + } + } else if (input.tagName === "TEXTAREA") { + if (input["data-format"] === "string") { + json_dict[input.name] = input.value; + } else { + json_dict[input.name] = input.value.split('\n'); + } + } else { + json_dict[input.name] = input.value; + } + } + }); + for (k in json_dict) { + if (json_dict.hasOwnProperty(k)) { + convertOnMultiLevel(multi_level_dict, k, json_dict[k]); + } + } + if (count_of_values === 0) { + return; + } + return multi_level_dict[""]; + }); + } + + function getSubGadgetElement(g, scope) { + return g.element.querySelector("div[data-gadget-scope='" + scope + "']"); + } + + rJS(window) + .ready(function () { + var g = this; + g.props = {}; + g.options = {}; + }) + .declareAcquiredMethod("notifyChange", "notifyChange") + .declareAcquiredMethod("renameChildrenParent", "renameChildren") + .allowPublicAcquisition("renameChildren", function (opt_arr, scope) { + var property_name, + objects = this.props.objects, + new_name = opt_arr[0], + element = getSubGadgetElement(this, scope), + parent = element.getAttribute('data-json-parent'); + if (objects.hasOwnProperty(parent)) { + parent = objects[parent]; + if (parent.hasOwnProperty(new_name)) { + throw new Error("property already exist"); + } + // XXX validate property if property pattern + for (property_name in parent) { + if (parent.hasOwnProperty(property_name) && parent[property_name] === scope) { + delete parent[property_name]; + parent[new_name] = scope; + return new_name; + } + } + throw new Error("gadget not found for renaming"); + } + }) + .declareMethod("rename", function (new_name, event) { + var g = this, + name = g.element.getAttribute('data-json-property-name'); + return this.renameChildrenParent(new_name) + .push(function () { + return g.element.setAttribute('data-json-property-name', new_name); + }) + .push(undefined, function (error) { + // XXX notify user + event.srcElement.value = name; + event.srcElement.focus(); + }); + }) + .declareAcquiredMethod("selfRemove", "deleteChildren") + .allowPublicAcquisition("deleteChildren", function (arr, scope) { + var g = this, + key, + i, + button_list = this.props.add_buttons, + objects = this.props.objects, + element = getSubGadgetElement(g, scope), + parent = element.getAttribute("data-json-parent"), + tasks = []; + if (objects.hasOwnProperty(parent)) { + parent = objects[parent]; + for (key in parent) { + if (parent.hasOwnProperty(key) && parent[key] === scope) { + delete parent[key]; + } + } + } + element.parentNode.removeChild(element); + for (key in g.props.add_custom_data) { + if (g.props.add_custom_data.hasOwnProperty(key)) { + tasks.push(g.props.add_custom_data[key].rerender()); + } + } + for (i = 0; i < button_list.length; i = i + 1) { + tasks.push(button_list[i].rerender()); + } + tasks.push(checkValidityAndNotifyChange(g)); + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }); + }) + + .declareMethod('getElementByPath', function (data_path) { + var g = this, + array, + path, + scope, + key, + next_data_path, + slash_count = 0, + slash_count_next, + bingo, + idx, + options = g.props; + if (data_path !== "/") { + for (path in options.arrays) { + if (options.arrays.hasOwnProperty(path) && data_path.startsWith(path)) { + slash_count_next = path.split("/").length - 1; + if (slash_count_next > slash_count) { + bingo = path; + slash_count = slash_count_next; + } + } + } + if (bingo) { + array = options.arrays[bingo] + .querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']"); + next_data_path = data_path.slice(bingo.length).split("/"); + idx = next_data_path[0]; + next_data_path = "/" + next_data_path.slice(1).join("/"); + return g.getDeclaredGadget(array[idx].getAttribute('data-gadget-scope')) + .push(function (gadget) { + return gadget.getElementByPath(next_data_path); + }); + } + + slash_count = 0; + for (path in options.objects) { + if (options.objects.hasOwnProperty(path) && data_path.startsWith(path)) { + slash_count_next = path.split("/").length - 1; + if (slash_count_next > slash_count) { + bingo = path; + slash_count = slash_count_next; + } + } + } + if (bingo) { + path = options.objects[bingo]; + key = decodeJsonPointer(data_path.slice(bingo.length).split('/')[0]); + if (path.hasOwnProperty(key)) { + next_data_path = data_path.slice(bingo.length + encodeJsonPointer(key).length); + if (!next_data_path) { + next_data_path = "/"; + } + scope = path[key]; + } + } + if (scope === false) { + // gadget for this element absent + // so find element in current gadget + return document.getElementById( + g.element.getAttribute("data-gadget-scope") + bingo + key + '/' + ); + } + if (scope) { + // get gadget by scope and use relative path for find element in gadget + return g.getDeclaredGadget(scope) + .push(function (gadget) { + return gadget.getElementByPath(next_data_path); + }); + } + } + return RSVP.Queue() + .push(function () { + return document.getElementById( + g.element.getAttribute("data-gadget-scope") + data_path + ); + }); + }) + .declareAcquiredMethod("notifyValid", "notifyValid") + .declareAcquiredMethod("notifyInvalid", "notifyInvalid") + .declareAcquiredMethod("checkValidity", "checkValidity") + + .allowPublicAcquisition("notifyValid", function (arr, sub_scope) { + return true; + }) + .allowPublicAcquisition("notifyChange", function (arr, sub_scope) { + var g = this, + opt = arr[0], + event_object; + event_object = g.props.add_custom_data[sub_scope]; + if (event_object && opt.type === "change") { + return event_object.event(); + } + return g.notifyChange(); + }) + .declareMethod('renderForm', function (options) { + var g = this, + property_name = g.element.getAttribute('data-json-property-name'), + schema = options.schema, + root; + g.props.inputs = []; + g.props.add_buttons = []; + g.props.add_custom_data = {}; + g.props.arrays = {}; + g.props.objects = {}; + g.props.path = options.path; // self gadget scope + if (!property_name || !options.display_label) { + property_name = ""; + } + root = g.element.querySelector('[data-json-path="/"]'); + if (!root) { + root = g.element; + } + if (options.delete_button === undefined) { + if (options.top) { + options.delete_button = false; + } else { + options.delete_button = !options.required; + } + } + while (root.firstChild) { + root.removeChild(root.firstChild); + } + return render_field(g, property_name, "", schema, + options.document, root, options.schema_path, + { + type: options.type, + required: options.required, + delete_button: options.delete_button, + top: options.top + }) + .push(function () { + g.listenEvents(); + return g.element; + }); + }) + + .declareAcquiredMethod("expandSchema", "expandSchema") + .onEvent('click', function (evt) { + if (evt.target === this.props.delete_button) { + return this.selfRemove(evt); + } + + var link = evt.target.getAttribute("data-error-link"), + button_list = this.props.add_buttons, + i; + if (link) { + location.href = link; + return; + } + + for (i = 0; i < button_list.length; i = i + 1) { + if (evt.target === button_list[i].element) { + return button_list[i].event(evt); + } + } + }) + + .onEvent('change', function (evt) { + if (evt.target === this.props.property_name_edit) { + return this.rename(this.props.property_name_edit.value, evt); + } + + var field_list = this.props.inputs, + i; + for (i = 0; i < field_list.length; i = i + 1) { + if (evt.target === field_list[i]) { + return checkValidityAndNotifyChange(this); + } + } + }) + .declareJob('listenEvents', function () { + // XXX Disable + return; + }) + + .declareMethod('getContent', function () { + var g = this; + return getFormValuesAsJSONDict(g); + }); + +}(window, document, location, rJS, RSVP, jIO, tv4)); \ No newline at end of file diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.xml new file mode 100644 index 00000000000..00514ccee83 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + gadget_json_generated_form_child.js + + + content_type + application/javascript + + + precondition + + + + title + gadget_json_generated_form_child.js + + + + + diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js new file mode 100644 index 00000000000..48513c229a4 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js @@ -0,0 +1,1687 @@ +/* +Author: Geraint Luff and others +Year: 2013 + +This code is released into the "public domain" by its author(s). Anybody may use, alter and distribute the code without restriction. The author makes no guarantees, and takes no liability of any kind for use of this code. + +If you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory. +*/ +(function (global, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else if (typeof module !== 'undefined' && module.exports){ + // CommonJS. Define export. + module.exports = factory(); + } else { + // Browser globals + global.tv4 = factory(); + } +}(this, function () { + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + })(); +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create +if (!Object.create) { + Object.create = (function(){ + function F(){} + + return function(o){ + if (arguments.length !== 1) { + throw new Error('Object.create implementation only accepts one parameter.'); + } + F.prototype = o; + return new F(); + }; + })(); +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FisArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + if (this === null) { + throw new TypeError(); + } + var t = Object(this); + var len = t.length >>> 0; + + if (len === 0) { + return -1; + } + var n = 0; + if (arguments.length > 1) { + n = Number(arguments[1]); + if (n !== n) { // shortcut for verifying if it's NaN + n = 0; + } else if (n !== 0 && n !== Infinity && n !== -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; +} + +// Grungey Object.isFrozen hack +if (!Object.isFrozen) { + Object.isFrozen = function (obj) { + var key = "tv4_test_frozen_key"; + while (obj.hasOwnProperty(key)) { + key += Math.random(); + } + try { + obj[key] = true; + delete obj[key]; + return false; + } catch (e) { + return true; + } + }; +} +// Based on: https://github.com/geraintluff/uri-templates, but with all the de-substitution stuff removed + +var uriTemplateGlobalModifiers = { + "+": true, + "#": true, + ".": true, + "/": true, + ";": true, + "?": true, + "&": true +}; +var uriTemplateSuffices = { + "*": true +}; + +function notReallyPercentEncode(string) { + return encodeURI(string).replace(/%25[0-9][0-9]/g, function (doubleEncoded) { + return "%" + doubleEncoded.substring(3); + }); +} + +function uriTemplateSubstitution(spec) { + var modifier = ""; + if (uriTemplateGlobalModifiers[spec.charAt(0)]) { + modifier = spec.charAt(0); + spec = spec.substring(1); + } + var separator = ""; + var prefix = ""; + var shouldEscape = true; + var showVariables = false; + var trimEmptyString = false; + if (modifier === '+') { + shouldEscape = false; + } else if (modifier === ".") { + prefix = "."; + separator = "."; + } else if (modifier === "/") { + prefix = "/"; + separator = "/"; + } else if (modifier === '#') { + prefix = "#"; + shouldEscape = false; + } else if (modifier === ';') { + prefix = ";"; + separator = ";"; + showVariables = true; + trimEmptyString = true; + } else if (modifier === '?') { + prefix = "?"; + separator = "&"; + showVariables = true; + } else if (modifier === '&') { + prefix = "&"; + separator = "&"; + showVariables = true; + } + + var varNames = []; + var varList = spec.split(","); + var varSpecs = []; + var varSpecMap = {}; + for (var i = 0; i < varList.length; i++) { + var varName = varList[i]; + var truncate = null; + if (varName.indexOf(":") !== -1) { + var parts = varName.split(":"); + varName = parts[0]; + truncate = parseInt(parts[1], 10); + } + var suffices = {}; + while (uriTemplateSuffices[varName.charAt(varName.length - 1)]) { + suffices[varName.charAt(varName.length - 1)] = true; + varName = varName.substring(0, varName.length - 1); + } + var varSpec = { + truncate: truncate, + name: varName, + suffices: suffices + }; + varSpecs.push(varSpec); + varSpecMap[varName] = varSpec; + varNames.push(varName); + } + var subFunction = function (valueFunction) { + var result = ""; + var startIndex = 0; + for (var i = 0; i < varSpecs.length; i++) { + var varSpec = varSpecs[i]; + var value = valueFunction(varSpec.name); + if (value === null || value === undefined || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0)) { + startIndex++; + continue; + } + if (i === startIndex) { + result += prefix; + } else { + result += (separator || ","); + } + if (Array.isArray(value)) { + if (showVariables) { + result += varSpec.name + "="; + } + for (var j = 0; j < value.length; j++) { + if (j > 0) { + result += varSpec.suffices['*'] ? (separator || ",") : ","; + if (varSpec.suffices['*'] && showVariables) { + result += varSpec.name + "="; + } + } + result += shouldEscape ? encodeURIComponent(value[j]).replace(/!/g, "%21") : notReallyPercentEncode(value[j]); + } + } else if (typeof value === "object") { + if (showVariables && !varSpec.suffices['*']) { + result += varSpec.name + "="; + } + var first = true; + for (var key in value) { + if (!first) { + result += varSpec.suffices['*'] ? (separator || ",") : ","; + } + first = false; + result += shouldEscape ? encodeURIComponent(key).replace(/!/g, "%21") : notReallyPercentEncode(key); + result += varSpec.suffices['*'] ? '=' : ","; + result += shouldEscape ? encodeURIComponent(value[key]).replace(/!/g, "%21") : notReallyPercentEncode(value[key]); + } + } else { + if (showVariables) { + result += varSpec.name; + if (!trimEmptyString || value !== "") { + result += "="; + } + } + if (varSpec.truncate != null) { + value = value.substring(0, varSpec.truncate); + } + result += shouldEscape ? encodeURIComponent(value).replace(/!/g, "%21"): notReallyPercentEncode(value); + } + } + return result; + }; + subFunction.varNames = varNames; + return { + prefix: prefix, + substitution: subFunction + }; +} + +function UriTemplate(template) { + if (!(this instanceof UriTemplate)) { + return new UriTemplate(template); + } + var parts = template.split("{"); + var textParts = [parts.shift()]; + var prefixes = []; + var substitutions = []; + var varNames = []; + while (parts.length > 0) { + var part = parts.shift(); + var spec = part.split("}")[0]; + var remainder = part.substring(spec.length + 1); + var funcs = uriTemplateSubstitution(spec); + substitutions.push(funcs.substitution); + prefixes.push(funcs.prefix); + textParts.push(remainder); + varNames = varNames.concat(funcs.substitution.varNames); + } + this.fill = function (valueFunction) { + var result = textParts[0]; + for (var i = 0; i < substitutions.length; i++) { + var substitution = substitutions[i]; + result += substitution(valueFunction); + result += textParts[i + 1]; + } + return result; + }; + this.varNames = varNames; + this.template = template; +} +UriTemplate.prototype = { + toString: function () { + return this.template; + }, + fillFromObject: function (obj) { + return this.fill(function (varName) { + return obj[varName]; + }); + } +}; +var ValidatorContext = function ValidatorContext(parent, collectMultiple, errorReporter, checkRecursive, trackUnknownProperties) { + this.missing = []; + this.missingMap = {}; + this.formatValidators = parent ? Object.create(parent.formatValidators) : {}; + this.schemas = parent ? Object.create(parent.schemas) : {}; + this.collectMultiple = collectMultiple; + this.errors = []; + this.handleError = collectMultiple ? this.collectError : this.returnError; + if (checkRecursive) { + this.checkRecursive = true; + this.scanned = []; + this.scannedFrozen = []; + this.scannedFrozenSchemas = []; + this.scannedFrozenValidationErrors = []; + this.validatedSchemasKey = 'tv4_validation_id'; + this.validationErrorsKey = 'tv4_validation_errors_id'; + } + if (trackUnknownProperties) { + this.trackUnknownProperties = true; + this.knownPropertyPaths = {}; + this.unknownPropertyPaths = {}; + } + this.errorReporter = errorReporter || defaultErrorReporter('en'); + if (typeof this.errorReporter === 'string') { + throw new Error('debug'); + } + this.definedKeywords = {}; + if (parent) { + for (var key in parent.definedKeywords) { + this.definedKeywords[key] = parent.definedKeywords[key].slice(0); + } + } +}; +ValidatorContext.prototype.defineKeyword = function (keyword, keywordFunction) { + this.definedKeywords[keyword] = this.definedKeywords[keyword] || []; + this.definedKeywords[keyword].push(keywordFunction); +}; +ValidatorContext.prototype.createError = function (code, messageParams, dataPath, schemaPath, subErrors, data, schema) { + var error = new ValidationError(code, messageParams, dataPath, schemaPath, subErrors); + error.message = this.errorReporter(error, data, schema); + return error; +}; +ValidatorContext.prototype.returnError = function (error) { + return error; +}; +ValidatorContext.prototype.collectError = function (error) { + if (error) { + this.errors.push(error); + } + return null; +}; +ValidatorContext.prototype.prefixErrors = function (startIndex, dataPath, schemaPath) { + for (var i = startIndex; i < this.errors.length; i++) { + this.errors[i] = this.errors[i].prefixWith(dataPath, schemaPath); + } + return this; +}; +ValidatorContext.prototype.banUnknownProperties = function (data, schema) { + for (var unknownPath in this.unknownPropertyPaths) { + var error = this.createError(ErrorCodes.UNKNOWN_PROPERTY, {path: unknownPath}, unknownPath, "", null, data, schema); + var result = this.handleError(error); + if (result) { + return result; + } + } + return null; +}; + +ValidatorContext.prototype.addFormat = function (format, validator) { + if (typeof format === 'object') { + for (var key in format) { + this.addFormat(key, format[key]); + } + return this; + } + this.formatValidators[format] = validator; +}; +ValidatorContext.prototype.resolveRefs = function (schema, urlHistory) { + if (schema['$ref'] !== undefined) { + urlHistory = urlHistory || {}; + if (urlHistory[schema['$ref']]) { + return this.createError(ErrorCodes.CIRCULAR_REFERENCE, {urls: Object.keys(urlHistory).join(', ')}, '', '', null, undefined, schema); + } + urlHistory[schema['$ref']] = true; + schema = this.getSchema(schema['$ref'], urlHistory); + } + return schema; +}; +ValidatorContext.prototype.getSchema = function (url, urlHistory) { + var schema; + if (this.schemas[url] !== undefined) { + schema = this.schemas[url]; + return this.resolveRefs(schema, urlHistory); + } + var baseUrl = url; + var fragment = ""; + if (url.indexOf('#') !== -1) { + fragment = url.substring(url.indexOf("#") + 1); + baseUrl = url.substring(0, url.indexOf("#")); + } + if (typeof this.schemas[baseUrl] === 'object') { + schema = this.schemas[baseUrl]; + var pointerPath = decodeURIComponent(fragment); + if (pointerPath === "") { + return this.resolveRefs(schema, urlHistory); + } else if (pointerPath.charAt(0) !== "/") { + return undefined; + } + var parts = pointerPath.split("/").slice(1); + for (var i = 0; i < parts.length; i++) { + var component = parts[i].replace(/~1/g, "/").replace(/~0/g, "~"); + if (schema[component] === undefined) { + schema = undefined; + break; + } + schema = schema[component]; + } + if (schema !== undefined) { + return this.resolveRefs(schema, urlHistory); + } + } + if (this.missing[baseUrl] === undefined) { + this.missing.push(baseUrl); + this.missing[baseUrl] = baseUrl; + this.missingMap[baseUrl] = baseUrl; + } +}; +ValidatorContext.prototype.searchSchemas = function (schema, url) { + if (Array.isArray(schema)) { + for (var i = 0; i < schema.length; i++) { + this.searchSchemas(schema[i], url); + } + } else if (schema && typeof schema === "object") { + if (typeof schema.id === "string") { + if (isTrustedUrl(url, schema.id)) { + if (this.schemas[schema.id] === undefined) { + this.schemas[schema.id] = schema; + } + } + } + for (var key in schema) { + if (key !== "enum") { + if (typeof schema[key] === "object") { + this.searchSchemas(schema[key], url); + } else if (key === "$ref") { + var uri = getDocumentUri(schema[key]); + if (uri && this.schemas[uri] === undefined && this.missingMap[uri] === undefined) { + this.missingMap[uri] = uri; + } + } + } + } + } +}; +ValidatorContext.prototype.addSchema = function (url, schema) { + //overload + if (typeof url !== 'string' || typeof schema === 'undefined') { + if (typeof url === 'object' && typeof url.id === 'string') { + schema = url; + url = schema.id; + } + else { + return; + } + } + if (url === getDocumentUri(url) + "#") { + // Remove empty fragment + url = getDocumentUri(url); + } + this.schemas[url] = schema; + delete this.missingMap[url]; + // schema normalisation and downloading are disabled because already done by us. + // and current realisation not support CIRCULAR_REFERENCE + // normSchema(schema, url); + // this.searchSchemas(schema, url); +}; + +ValidatorContext.prototype.getSchemaMap = function () { + var map = {}; + for (var key in this.schemas) { + map[key] = this.schemas[key]; + } + return map; +}; + +ValidatorContext.prototype.getSchemaUris = function (filterRegExp) { + var list = []; + for (var key in this.schemas) { + if (!filterRegExp || filterRegExp.test(key)) { + list.push(key); + } + } + return list; +}; + +ValidatorContext.prototype.getMissingUris = function (filterRegExp) { + var list = []; + for (var key in this.missingMap) { + if (!filterRegExp || filterRegExp.test(key)) { + list.push(key); + } + } + return list; +}; + +ValidatorContext.prototype.dropSchemas = function () { + this.schemas = {}; + this.reset(); +}; +ValidatorContext.prototype.reset = function () { + this.missing = []; + this.missingMap = {}; + this.errors = []; +}; + +ValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) { + var topLevel; + if (!schema) { + return null; + } else if (schema instanceof ValidationError) { + this.errors.push(schema); + return schema; + } + + var startErrorCount = this.errors.length; + var frozenIndex, scannedFrozenSchemaIndex = null, scannedSchemasIndex = null; + if (this.checkRecursive && data && typeof data === 'object') { + topLevel = !this.scanned.length; + if (data[this.validatedSchemasKey]) { + var schemaIndex = data[this.validatedSchemasKey].indexOf(schema); + if (schemaIndex !== -1) { + this.errors = this.errors.concat(data[this.validationErrorsKey][schemaIndex]); + return null; + } + } + if (Object.isFrozen(data)) { + frozenIndex = this.scannedFrozen.indexOf(data); + if (frozenIndex !== -1) { + var frozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].indexOf(schema); + if (frozenSchemaIndex !== -1) { + this.errors = this.errors.concat(this.scannedFrozenValidationErrors[frozenIndex][frozenSchemaIndex]); + return null; + } + } + } + this.scanned.push(data); + if (Object.isFrozen(data)) { + if (frozenIndex === -1) { + frozenIndex = this.scannedFrozen.length; + this.scannedFrozen.push(data); + this.scannedFrozenSchemas.push([]); + } + scannedFrozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].length; + this.scannedFrozenSchemas[frozenIndex][scannedFrozenSchemaIndex] = schema; + this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = []; + } else { + if (!data[this.validatedSchemasKey]) { + try { + Object.defineProperty(data, this.validatedSchemasKey, { + value: [], + configurable: true + }); + Object.defineProperty(data, this.validationErrorsKey, { + value: [], + configurable: true + }); + } catch (e) { + //IE 7/8 workaround + data[this.validatedSchemasKey] = []; + data[this.validationErrorsKey] = []; + } + } + scannedSchemasIndex = data[this.validatedSchemasKey].length; + data[this.validatedSchemasKey][scannedSchemasIndex] = schema; + data[this.validationErrorsKey][scannedSchemasIndex] = []; + } + } + + var errorCount = this.errors.length; + var error = this.validateBasic(data, schema, dataPointerPath) + || this.validateNumeric(data, schema, dataPointerPath) + || this.validateString(data, schema, dataPointerPath) + || this.validateArray(data, schema, dataPointerPath) + || this.validateObject(data, schema, dataPointerPath) + || this.validateCombinations(data, schema, dataPointerPath) + || this.validateHypermedia(data, schema, dataPointerPath) + || this.validateFormat(data, schema, dataPointerPath) + || this.validateDefinedKeywords(data, schema, dataPointerPath) + || null; + + if (topLevel) { + while (this.scanned.length) { + var item = this.scanned.pop(); + delete item[this.validatedSchemasKey]; + } + this.scannedFrozen = []; + this.scannedFrozenSchemas = []; + } + + if (error || errorCount !== this.errors.length) { + while ((dataPathParts && dataPathParts.length) || (schemaPathParts && schemaPathParts.length)) { + var dataPart = (dataPathParts && dataPathParts.length) ? "" + dataPathParts.pop() : null; + var schemaPart = (schemaPathParts && schemaPathParts.length) ? "" + schemaPathParts.pop() : null; + if (error) { + error = error.prefixWith(dataPart, schemaPart); + } + this.prefixErrors(errorCount, dataPart, schemaPart); + } + } + + if (scannedFrozenSchemaIndex !== null) { + this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = this.errors.slice(startErrorCount); + } else if (scannedSchemasIndex !== null) { + data[this.validationErrorsKey][scannedSchemasIndex] = this.errors.slice(startErrorCount); + } + + return this.handleError(error); +}; +ValidatorContext.prototype.validateFormat = function (data, schema) { + if (typeof schema.format !== 'string' || !this.formatValidators[schema.format]) { + return null; + } + var errorMessage = this.formatValidators[schema.format].call(null, data, schema); + if (typeof errorMessage === 'string' || typeof errorMessage === 'number') { + return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage}, '', '/format', null, data, schema); + } else if (errorMessage && typeof errorMessage === 'object') { + return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage.message || "?"}, errorMessage.dataPath || '', errorMessage.schemaPath || "/format", null, data, schema); + } + return null; +}; +ValidatorContext.prototype.validateDefinedKeywords = function (data, schema, dataPointerPath) { + for (var key in this.definedKeywords) { + if (typeof schema[key] === 'undefined') { + continue; + } + var validationFunctions = this.definedKeywords[key]; + for (var i = 0; i < validationFunctions.length; i++) { + var func = validationFunctions[i]; + var result = func(data, schema[key], schema, dataPointerPath); + if (typeof result === 'string' || typeof result === 'number') { + return this.createError(ErrorCodes.KEYWORD_CUSTOM, {key: key, message: result}, '', '', null, data, schema).prefixWith(null, key); + } else if (result && typeof result === 'object') { + var code = result.code; + if (typeof code === 'string') { + if (!ErrorCodes[code]) { + throw new Error('Undefined error code (use defineError): ' + code); + } + code = ErrorCodes[code]; + } else if (typeof code !== 'number') { + code = ErrorCodes.KEYWORD_CUSTOM; + } + var messageParams = (typeof result.message === 'object') ? result.message : {key: key, message: result.message || "?"}; + var schemaPath = result.schemaPath || ("/" + key.replace(/~/g, '~0').replace(/\//g, '~1')); + return this.createError(code, messageParams, result.dataPath || null, schemaPath, null, data, schema); + } + } + } + return null; +}; + +function recursiveCompare(A, B) { + if (A === B) { + return true; + } + if (A && B && typeof A === "object" && typeof B === "object") { + if (Array.isArray(A) !== Array.isArray(B)) { + return false; + } else if (Array.isArray(A)) { + if (A.length !== B.length) { + return false; + } + for (var i = 0; i < A.length; i++) { + if (!recursiveCompare(A[i], B[i])) { + return false; + } + } + } else { + var key; + for (key in A) { + if (B[key] === undefined && A[key] !== undefined) { + return false; + } + } + for (key in B) { + if (A[key] === undefined && B[key] !== undefined) { + return false; + } + } + for (key in A) { + if (!recursiveCompare(A[key], B[key])) { + return false; + } + } + } + return true; + } + return false; +} + +ValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) { + var error; + if (error = this.validateType(data, schema, dataPointerPath)) { + return error.prefixWith(null, "type"); + } + if (error = this.validateEnum(data, schema, dataPointerPath)) { + return error.prefixWith(null, "type"); + } + return null; +}; + +ValidatorContext.prototype.validateType = function validateType(data, schema) { + if (schema.type === undefined) { + return null; + } + var dataType = typeof data; + if (data === null) { + dataType = "null"; + } else if (Array.isArray(data)) { + dataType = "array"; + } + var allowedTypes = schema.type; + if (!Array.isArray(allowedTypes)) { + allowedTypes = [allowedTypes]; + } + + for (var i = 0; i < allowedTypes.length; i++) { + var type = allowedTypes[i]; + if (type === dataType || (type === "integer" && dataType === "number" && (data % 1 === 0))) { + return null; + } + } + return this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join("/")}, '', '', null, data, schema); +}; + +ValidatorContext.prototype.validateEnum = function validateEnum(data, schema) { + if (schema["enum"] === undefined) { + return null; + } + for (var i = 0; i < schema["enum"].length; i++) { + var enumVal = schema["enum"][i]; + if (recursiveCompare(data, enumVal)) { + return null; + } + } + return this.createError(ErrorCodes.ENUM_MISMATCH, {value: (typeof JSON !== 'undefined') ? JSON.stringify(data) : data}, '', '', null, data, schema); +}; + +ValidatorContext.prototype.validateNumeric = function validateNumeric(data, schema, dataPointerPath) { + return this.validateMultipleOf(data, schema, dataPointerPath) + || this.validateMinMax(data, schema, dataPointerPath) + || this.validateNaN(data, schema, dataPointerPath) + || null; +}; + +var CLOSE_ENOUGH_LOW = Math.pow(2, -51); +var CLOSE_ENOUGH_HIGH = 1 - CLOSE_ENOUGH_LOW; +ValidatorContext.prototype.validateMultipleOf = function validateMultipleOf(data, schema) { + var multipleOf = schema.multipleOf || schema.divisibleBy; + if (multipleOf === undefined) { + return null; + } + if (typeof data === "number") { + var remainder = (data/multipleOf)%1; + if (remainder >= CLOSE_ENOUGH_LOW && remainder < CLOSE_ENOUGH_HIGH) { + return this.createError(ErrorCodes.NUMBER_MULTIPLE_OF, {value: data, multipleOf: multipleOf}, '', '', null, data, schema); + } + } + return null; +}; + +ValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema) { + if (typeof data !== "number") { + return null; + } + if (schema.minimum !== undefined) { + if (data < schema.minimum) { + return this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}, '', '/minimum', null, data, schema); + } + if (schema.exclusiveMinimum && data === schema.minimum) { + return this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}, '', '/exclusiveMinimum', null, data, schema); + } + } + if (schema.maximum !== undefined) { + if (data > schema.maximum) { + return this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}, '', '/maximum', null, data, schema); + } + if (schema.exclusiveMaximum && data === schema.maximum) { + return this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}, '', '/exclusiveMaximum', null, data, schema); + } + } + return null; +}; + +ValidatorContext.prototype.validateNaN = function validateNaN(data, schema) { + if (typeof data !== "number") { + return null; + } + if (isNaN(data) === true || data === Infinity || data === -Infinity) { + return this.createError(ErrorCodes.NUMBER_NOT_A_NUMBER, {value: data}, '', '/type', null, data, schema); + } + return null; +}; + +ValidatorContext.prototype.validateString = function validateString(data, schema, dataPointerPath) { + return this.validateStringLength(data, schema, dataPointerPath) + || this.validateStringPattern(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateStringLength = function validateStringLength(data, schema) { + if (typeof data !== "string") { + return null; + } + if (schema.minLength !== undefined) { + if (data.length < schema.minLength) { + return this.createError(ErrorCodes.STRING_LENGTH_SHORT, {length: data.length, minimum: schema.minLength}, '', '/minLength', null, data, schema); + } + } + if (schema.maxLength !== undefined) { + if (data.length > schema.maxLength) { + return this.createError(ErrorCodes.STRING_LENGTH_LONG, {length: data.length, maximum: schema.maxLength}, '', '/maxLength', null, data, schema); + } + } + return null; +}; + +ValidatorContext.prototype.validateStringPattern = function validateStringPattern(data, schema) { + if (typeof data !== "string" || (typeof schema.pattern !== "string" && !(schema.pattern instanceof RegExp))) { + return null; + } + var regexp; + if (schema.pattern instanceof RegExp) { + regexp = schema.pattern; + } + else { + var body, flags = ''; + // Check for regular expression literals + // @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5 + var literal = schema.pattern.match(/^\/(.+)\/([img]*)$/); + if (literal) { + body = literal[1]; + flags = literal[2]; + } + else { + body = schema.pattern; + } + regexp = new RegExp(body, flags); + } + if (!regexp.test(data)) { + return this.createError(ErrorCodes.STRING_PATTERN, {pattern: schema.pattern}, '', '/pattern', null, data, schema); + } + return null; +}; + +ValidatorContext.prototype.validateArray = function validateArray(data, schema, dataPointerPath) { + if (!Array.isArray(data)) { + return null; + } + return this.validateArrayLength(data, schema, dataPointerPath) + || this.validateArrayUniqueItems(data, schema, dataPointerPath) + || this.validateArrayItems(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateArrayLength = function validateArrayLength(data, schema) { + var error; + if (schema.minItems !== undefined) { + if (data.length < schema.minItems) { + error = this.createError(ErrorCodes.ARRAY_LENGTH_SHORT, {length: data.length, minimum: schema.minItems}, '', '/minItems', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + if (schema.maxItems !== undefined) { + if (data.length > schema.maxItems) { + error = this.createError(ErrorCodes.ARRAY_LENGTH_LONG, {length: data.length, maximum: schema.maxItems}, '', '/maxItems', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + return null; +}; + +ValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) { + if (schema.uniqueItems) { + for (var i = 0; i < data.length; i++) { + for (var j = i + 1; j < data.length; j++) { + if (recursiveCompare(data[i], data[j])) { + var error = this.createError(ErrorCodes.ARRAY_UNIQUE, {match1: i, match2: j}, '', '/uniqueItems', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + } + } + return null; +}; + +ValidatorContext.prototype.validateArrayItems = function validateArrayItems(data, schema, dataPointerPath) { + if (schema.items === undefined) { + return null; + } + var error, i; + if (Array.isArray(schema.items)) { + for (i = 0; i < data.length; i++) { + if (i < schema.items.length) { + if (error = this.validateAll(data[i], schema.items[i], [i], ["items", i], dataPointerPath + "/" + i)) { + return error; + } + } else if (schema.additionalItems !== undefined) { + if (typeof schema.additionalItems === "boolean") { + if (!schema.additionalItems) { + error = (this.createError(ErrorCodes.ARRAY_ADDITIONAL_ITEMS, {}, '/' + i, '/additionalItems', null, data, schema)); + if (this.handleError(error)) { + return error; + } + } + } else if (error = this.validateAll(data[i], schema.additionalItems, [i], ["additionalItems"], dataPointerPath + "/" + i)) { + return error; + } + } + } + } else { + for (i = 0; i < data.length; i++) { + if (error = this.validateAll(data[i], schema.items, [i], ["items"], dataPointerPath + "/" + i)) { + return error; + } + } + } + return null; +}; + +ValidatorContext.prototype.validateObject = function validateObject(data, schema, dataPointerPath) { + if (typeof data !== "object" || data === null || Array.isArray(data)) { + return null; + } + return this.validateObjectMinMaxProperties(data, schema, dataPointerPath) + || this.validateObjectRequiredProperties(data, schema, dataPointerPath) + || this.validateObjectProperties(data, schema, dataPointerPath) + || this.validateObjectDependencies(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateObjectMinMaxProperties = function validateObjectMinMaxProperties(data, schema) { + var keys = Object.keys(data); + var error; + if (schema.minProperties !== undefined) { + if (keys.length < schema.minProperties) { + error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MINIMUM, {propertyCount: keys.length, minimum: schema.minProperties}, '', '/minProperties', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + if (schema.maxProperties !== undefined) { + if (keys.length > schema.maxProperties) { + error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MAXIMUM, {propertyCount: keys.length, maximum: schema.maxProperties}, '', '/maxProperties', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + return null; +}; + +ValidatorContext.prototype.validateObjectRequiredProperties = function validateObjectRequiredProperties(data, schema) { + if (schema.required !== undefined) { + for (var i = 0; i < schema.required.length; i++) { + var key = schema.required[i]; + if (data[key] === undefined) { + var error = this.createError(ErrorCodes.OBJECT_REQUIRED, {key: key}, '', '/required/' + i, null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + } + return null; +}; + +ValidatorContext.prototype.validateObjectProperties = function validateObjectProperties(data, schema, dataPointerPath) { + var error; + for (var key in data) { + var keyPointerPath = dataPointerPath + "/" + key.replace(/~/g, '~0').replace(/\//g, '~1'); + var foundMatch = false; + if (schema.properties !== undefined && schema.properties[key] !== undefined) { + foundMatch = true; + if (error = this.validateAll(data[key], schema.properties[key], [key], ["properties", key], keyPointerPath)) { + return error; + } + } + if (schema.patternProperties !== undefined) { + for (var patternKey in schema.patternProperties) { + var regexp = new RegExp(patternKey); + if (regexp.test(key)) { + foundMatch = true; + if (error = this.validateAll(data[key], schema.patternProperties[patternKey], [key], ["patternProperties", patternKey], keyPointerPath)) { + return error; + } + } + } + } + if (!foundMatch) { + if (schema.additionalProperties !== undefined) { + if (this.trackUnknownProperties) { + this.knownPropertyPaths[keyPointerPath] = true; + delete this.unknownPropertyPaths[keyPointerPath]; + } + if (typeof schema.additionalProperties === "boolean") { + if (!schema.additionalProperties) { + error = this.createError(ErrorCodes.OBJECT_ADDITIONAL_PROPERTIES, {key: key}, '', '/additionalProperties', null, data, schema).prefixWith(key, null); + if (this.handleError(error)) { + return error; + } + } + } else { + if (error = this.validateAll(data[key], schema.additionalProperties, [key], ["additionalProperties"], keyPointerPath)) { + return error; + } + } + } else if (this.trackUnknownProperties && !this.knownPropertyPaths[keyPointerPath]) { + this.unknownPropertyPaths[keyPointerPath] = true; + } + } else if (this.trackUnknownProperties) { + this.knownPropertyPaths[keyPointerPath] = true; + delete this.unknownPropertyPaths[keyPointerPath]; + } + } + return null; +}; + +ValidatorContext.prototype.validateObjectDependencies = function validateObjectDependencies(data, schema, dataPointerPath) { + var error; + if (schema.dependencies !== undefined) { + for (var depKey in schema.dependencies) { + if (data[depKey] !== undefined) { + var dep = schema.dependencies[depKey]; + if (typeof dep === "string") { + if (data[dep] === undefined) { + error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: dep}, '', '', null, data, schema).prefixWith(null, depKey).prefixWith(null, "dependencies"); + if (this.handleError(error)) { + return error; + } + } + } else if (Array.isArray(dep)) { + for (var i = 0; i < dep.length; i++) { + var requiredKey = dep[i]; + if (data[requiredKey] === undefined) { + error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: requiredKey}, '', '/' + i, null, data, schema).prefixWith(null, depKey).prefixWith(null, "dependencies"); + if (this.handleError(error)) { + return error; + } + } + } + } else { + if (error = this.validateAll(data, dep, [], ["dependencies", depKey], dataPointerPath)) { + return error; + } + } + } + } + } + return null; +}; + +ValidatorContext.prototype.validateCombinations = function validateCombinations(data, schema, dataPointerPath) { + return this.validateAllOf(data, schema, dataPointerPath) + || this.validateAnyOf(data, schema, dataPointerPath) + || this.validateOneOf(data, schema, dataPointerPath) + || this.validateNot(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateAllOf = function validateAllOf(data, schema, dataPointerPath) { + if (schema.allOf === undefined) { + return null; + } + var error; + for (var i = 0; i < schema.allOf.length; i++) { + var subSchema = schema.allOf[i]; + if (error = this.validateAll(data, subSchema, [], ["allOf", i], dataPointerPath)) { + return error; + } + } + return null; +}; + +ValidatorContext.prototype.validateAnyOf = function validateAnyOf(data, schema, dataPointerPath) { + if (schema.anyOf === undefined) { + return null; + } + var errors = []; + var startErrorCount = this.errors.length; + var oldUnknownPropertyPaths, oldKnownPropertyPaths; + if (this.trackUnknownProperties) { + oldUnknownPropertyPaths = this.unknownPropertyPaths; + oldKnownPropertyPaths = this.knownPropertyPaths; + } + var errorAtEnd = true; + for (var i = 0; i < schema.anyOf.length; i++) { + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = {}; + this.knownPropertyPaths = {}; + } + var subSchema = schema.anyOf[i]; + + var errorCount = this.errors.length; + var error = this.validateAll(data, subSchema, [], ["anyOf", i], dataPointerPath); + + if (error === null && errorCount === this.errors.length) { + this.errors = this.errors.slice(0, startErrorCount); + + if (this.trackUnknownProperties) { + for (var knownKey in this.knownPropertyPaths) { + oldKnownPropertyPaths[knownKey] = true; + delete oldUnknownPropertyPaths[knownKey]; + } + for (var unknownKey in this.unknownPropertyPaths) { + if (!oldKnownPropertyPaths[unknownKey]) { + oldUnknownPropertyPaths[unknownKey] = true; + } + } + // We need to continue looping so we catch all the property definitions, but we don't want to return an error + errorAtEnd = false; + continue; + } + + return null; + } + if (error) { + errors.push(error.prefixWith(null, "" + i).prefixWith(null, "anyOf")); + } + } + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = oldUnknownPropertyPaths; + this.knownPropertyPaths = oldKnownPropertyPaths; + } + if (errorAtEnd) { + errors = errors.concat(this.errors.slice(startErrorCount)); + this.errors = this.errors.slice(0, startErrorCount); + return this.createError(ErrorCodes.ANY_OF_MISSING, {}, "", "/anyOf", errors, data, schema); + } +}; + +ValidatorContext.prototype.validateOneOf = function validateOneOf(data, schema, dataPointerPath) { + if (schema.oneOf === undefined) { + return null; + } + var validIndex = null; + var errors = []; + var startErrorCount = this.errors.length; + var oldUnknownPropertyPaths, oldKnownPropertyPaths; + if (this.trackUnknownProperties) { + oldUnknownPropertyPaths = this.unknownPropertyPaths; + oldKnownPropertyPaths = this.knownPropertyPaths; + } + for (var i = 0; i < schema.oneOf.length; i++) { + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = {}; + this.knownPropertyPaths = {}; + } + var subSchema = schema.oneOf[i]; + + var errorCount = this.errors.length; + var error = this.validateAll(data, subSchema, [], ["oneOf", i], dataPointerPath); + + if (error === null && errorCount === this.errors.length) { + if (validIndex === null) { + validIndex = i; + } else { + this.errors = this.errors.slice(0, startErrorCount); + return this.createError(ErrorCodes.ONE_OF_MULTIPLE, {index1: validIndex, index2: i}, "", "/oneOf", null, data, schema); + } + if (this.trackUnknownProperties) { + for (var knownKey in this.knownPropertyPaths) { + oldKnownPropertyPaths[knownKey] = true; + delete oldUnknownPropertyPaths[knownKey]; + } + for (var unknownKey in this.unknownPropertyPaths) { + if (!oldKnownPropertyPaths[unknownKey]) { + oldUnknownPropertyPaths[unknownKey] = true; + } + } + } + } else if (error) { + errors.push(error); + } + } + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = oldUnknownPropertyPaths; + this.knownPropertyPaths = oldKnownPropertyPaths; + } + if (validIndex === null) { + errors = errors.concat(this.errors.slice(startErrorCount)); + this.errors = this.errors.slice(0, startErrorCount); + return this.createError(ErrorCodes.ONE_OF_MISSING, {}, "", "/oneOf", errors, data, schema); + } else { + this.errors = this.errors.slice(0, startErrorCount); + } + return null; +}; + +ValidatorContext.prototype.validateNot = function validateNot(data, schema, dataPointerPath) { + if (schema.not === undefined) { + return null; + } + var oldErrorCount = this.errors.length; + var oldUnknownPropertyPaths, oldKnownPropertyPaths; + if (this.trackUnknownProperties) { + oldUnknownPropertyPaths = this.unknownPropertyPaths; + oldKnownPropertyPaths = this.knownPropertyPaths; + this.unknownPropertyPaths = {}; + this.knownPropertyPaths = {}; + } + var error = this.validateAll(data, schema.not, null, null, dataPointerPath); + var notErrors = this.errors.slice(oldErrorCount); + this.errors = this.errors.slice(0, oldErrorCount); + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = oldUnknownPropertyPaths; + this.knownPropertyPaths = oldKnownPropertyPaths; + } + if (error === null && notErrors.length === 0) { + return this.createError(ErrorCodes.NOT_PASSED, {}, "", "/not", null, data, schema); + } + return null; +}; + +ValidatorContext.prototype.validateHypermedia = function validateCombinations(data, schema, dataPointerPath) { + if (!schema.links) { + return null; + } + var error; + for (var i = 0; i < schema.links.length; i++) { + var ldo = schema.links[i]; + if (ldo.rel === "describedby") { + var template = new UriTemplate(ldo.href); + var allPresent = true; + for (var j = 0; j < template.varNames.length; j++) { + if (!(template.varNames[j] in data)) { + allPresent = false; + break; + } + } + if (allPresent) { + var schemaUrl = template.fillFromObject(data); + var subSchema = {"$ref": schemaUrl}; + if (error = this.validateAll(data, subSchema, [], ["links", i], dataPointerPath)) { + return error; + } + } + } + } +}; + +// parseURI() and resolveUrl() are from https://gist.github.com/1088850 +// - released as public domain by author ("Yaffle") - see comments on gist + +function parseURI(url) { + var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); + // authority = '//' + user + ':' + pass '@' + hostname + ':' port + return (m ? { + href : m[0] || '', + protocol : m[1] || '', + authority: m[2] || '', + host : m[3] || '', + hostname : m[4] || '', + port : m[5] || '', + pathname : m[6] || '', + search : m[7] || '', + hash : m[8] || '' + } : null); +} + +function resolveUrl(base, href) {// RFC 3986 + + function removeDotSegments(input) { + var output = []; + input.replace(/^(\.\.?(\/|$))+/, '') + .replace(/\/(\.(\/|$))+/g, '/') + .replace(/\/\.\.$/, '/../') + .replace(/\/?[^\/]*/g, function (p) { + if (p === '/..') { + output.pop(); + } else { + output.push(p); + } + }); + return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); + } + + href = parseURI(href || ''); + base = parseURI(base || ''); + + return !href || !base ? null : (href.protocol || base.protocol) + + (href.protocol || href.authority ? href.authority : base.authority) + + removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) + + (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + + href.hash; +} + +function getDocumentUri(uri) { + return uri.split('#')[0]; +} +function normSchema(schema, baseUri) { + if (schema && typeof schema === "object") { + if (baseUri === undefined) { + baseUri = schema.id; + } else if (typeof schema.id === "string") { + baseUri = resolveUrl(baseUri, schema.id); + schema.id = baseUri; + } + if (Array.isArray(schema)) { + for (var i = 0; i < schema.length; i++) { + normSchema(schema[i], baseUri); + } + } else { + if (typeof schema['$ref'] === "string") { + schema['$ref'] = resolveUrl(baseUri, schema['$ref']); + } + for (var key in schema) { + if (key !== "enum") { + normSchema(schema[key], baseUri); + } + } + } + } +} + +function defaultErrorReporter(language) { + language = language || 'en'; + + var errorMessages = languages[language]; + + return function (error) { + var messageTemplate = errorMessages[error.code] || ErrorMessagesDefault[error.code]; + if (typeof messageTemplate !== 'string') { + return "Unknown error code " + error.code + ": " + JSON.stringify(error.messageParams); + } + var messageParams = error.params; + // Adapted from Crockford's supplant() + return messageTemplate.replace(/\{([^{}]*)\}/g, function (whole, varName) { + var subValue = messageParams[varName]; + return typeof subValue === 'string' || typeof subValue === 'number' ? subValue : whole; + }); + }; +} + +var ErrorCodes = { + INVALID_TYPE: 0, + ENUM_MISMATCH: 1, + ANY_OF_MISSING: 10, + ONE_OF_MISSING: 11, + ONE_OF_MULTIPLE: 12, + NOT_PASSED: 13, + // Numeric errors + NUMBER_MULTIPLE_OF: 100, + NUMBER_MINIMUM: 101, + NUMBER_MINIMUM_EXCLUSIVE: 102, + NUMBER_MAXIMUM: 103, + NUMBER_MAXIMUM_EXCLUSIVE: 104, + NUMBER_NOT_A_NUMBER: 105, + // String errors + STRING_LENGTH_SHORT: 200, + STRING_LENGTH_LONG: 201, + STRING_PATTERN: 202, + // Object errors + OBJECT_PROPERTIES_MINIMUM: 300, + OBJECT_PROPERTIES_MAXIMUM: 301, + OBJECT_REQUIRED: 302, + OBJECT_ADDITIONAL_PROPERTIES: 303, + OBJECT_DEPENDENCY_KEY: 304, + // Array errors + ARRAY_LENGTH_SHORT: 400, + ARRAY_LENGTH_LONG: 401, + ARRAY_UNIQUE: 402, + ARRAY_ADDITIONAL_ITEMS: 403, + // Custom/user-defined errors + FORMAT_CUSTOM: 500, + KEYWORD_CUSTOM: 501, + // Schema structure + CIRCULAR_REFERENCE: 600, + // Non-standard validation options + UNKNOWN_PROPERTY: 1000 +}; +var ErrorCodeLookup = {}; +for (var key in ErrorCodes) { + ErrorCodeLookup[ErrorCodes[key]] = key; +} +var ErrorMessagesDefault = { + INVALID_TYPE: "Invalid type: {type} (expected {expected})", + ENUM_MISMATCH: "No enum match for: {value}", + ANY_OF_MISSING: "Data does not match any schemas from \"anyOf\"", + ONE_OF_MISSING: "Data does not match any schemas from \"oneOf\"", + ONE_OF_MULTIPLE: "Data is valid against more than one schema from \"oneOf\": indices {index1} and {index2}", + NOT_PASSED: "Data matches schema from \"not\"", + // Numeric errors + NUMBER_MULTIPLE_OF: "Value {value} is not a multiple of {multipleOf}", + NUMBER_MINIMUM: "Value {value} is less than minimum {minimum}", + NUMBER_MINIMUM_EXCLUSIVE: "Value {value} is equal to exclusive minimum {minimum}", + NUMBER_MAXIMUM: "Value {value} is greater than maximum {maximum}", + NUMBER_MAXIMUM_EXCLUSIVE: "Value {value} is equal to exclusive maximum {maximum}", + NUMBER_NOT_A_NUMBER: "Value {value} is not a valid number", + // String errors + STRING_LENGTH_SHORT: "String is too short ({length} chars), minimum {minimum}", + STRING_LENGTH_LONG: "String is too long ({length} chars), maximum {maximum}", + STRING_PATTERN: "String does not match pattern: {pattern}", + // Object errors + OBJECT_PROPERTIES_MINIMUM: "Too few properties defined ({propertyCount}), minimum {minimum}", + OBJECT_PROPERTIES_MAXIMUM: "Too many properties defined ({propertyCount}), maximum {maximum}", + OBJECT_REQUIRED: "Missing required property: {key}", + OBJECT_ADDITIONAL_PROPERTIES: "Additional properties not allowed", + OBJECT_DEPENDENCY_KEY: "Dependency failed - key must exist: {missing} (due to key: {key})", + // Array errors + ARRAY_LENGTH_SHORT: "Array is too short ({length}), minimum {minimum}", + ARRAY_LENGTH_LONG: "Array is too long ({length}), maximum {maximum}", + ARRAY_UNIQUE: "Array items are not unique (indices {match1} and {match2})", + ARRAY_ADDITIONAL_ITEMS: "Additional items not allowed", + // Format errors + FORMAT_CUSTOM: "Format validation failed ({message})", + KEYWORD_CUSTOM: "Keyword failed: {key} ({message})", + // Schema structure + CIRCULAR_REFERENCE: "Circular $refs: {urls}", + // Non-standard validation options + UNKNOWN_PROPERTY: "Unknown property (not in schema)" +}; + +function ValidationError(code, params, dataPath, schemaPath, subErrors) { + Error.call(this); + if (code === undefined) { + throw new Error ("No error code supplied: " + schemaPath); + } + this.message = ''; + this.params = params; + this.code = code; + this.dataPath = dataPath || ""; + this.schemaPath = schemaPath || ""; + this.subErrors = subErrors || null; + + var err = new Error(this.message); + this.stack = err.stack || err.stacktrace; + if (!this.stack) { + try { + throw err; + } + catch(err) { + this.stack = err.stack || err.stacktrace; + } + } +} +ValidationError.prototype = Object.create(Error.prototype); +ValidationError.prototype.constructor = ValidationError; +ValidationError.prototype.name = 'ValidationError'; + +ValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) { + if (dataPrefix !== null) { + dataPrefix = dataPrefix.replace(/~/g, "~0").replace(/\//g, "~1"); + this.dataPath = "/" + dataPrefix + this.dataPath; + } + if (schemaPrefix !== null) { + schemaPrefix = schemaPrefix.replace(/~/g, "~0").replace(/\//g, "~1"); + this.schemaPath = "/" + schemaPrefix + this.schemaPath; + } + if (this.subErrors !== null) { + for (var i = 0; i < this.subErrors.length; i++) { + this.subErrors[i].prefixWith(dataPrefix, schemaPrefix); + } + } + return this; +}; + +function isTrustedUrl(baseUrl, testUrl) { + if(testUrl.substring(0, baseUrl.length) === baseUrl){ + var remainder = testUrl.substring(baseUrl.length); + if ((testUrl.length > 0 && testUrl.charAt(baseUrl.length - 1) === "/") + || remainder.charAt(0) === "#" + || remainder.charAt(0) === "?") { + return true; + } + } + return false; +} + +var languages = {}; +function createApi(language) { + var globalContext = new ValidatorContext(); + var currentLanguage; + var customErrorReporter; + var api = { + setErrorReporter: function (reporter) { + if (typeof reporter === 'string') { + return this.language(reporter); + } + customErrorReporter = reporter; + return true; + }, + addFormat: function () { + globalContext.addFormat.apply(globalContext, arguments); + }, + language: function (code) { + if (!code) { + return currentLanguage; + } + if (!languages[code]) { + code = code.split('-')[0]; // fall back to base language + } + if (languages[code]) { + currentLanguage = code; + return code; // so you can tell if fall-back has happened + } + return false; + }, + addLanguage: function (code, messageMap) { + var key; + for (key in ErrorCodes) { + if (messageMap[key] && !messageMap[ErrorCodes[key]]) { + messageMap[ErrorCodes[key]] = messageMap[key]; + } + } + var rootCode = code.split('-')[0]; + if (!languages[rootCode]) { // use for base language if not yet defined + languages[code] = messageMap; + languages[rootCode] = messageMap; + } else { + languages[code] = Object.create(languages[rootCode]); + for (key in messageMap) { + if (typeof languages[rootCode][key] === 'undefined') { + languages[rootCode][key] = messageMap[key]; + } + languages[code][key] = messageMap[key]; + } + } + return this; + }, + freshApi: function (language) { + var result = createApi(); + if (language) { + result.language(language); + } + return result; + }, + validate: function (data, schema, checkRecursive, banUnknownProperties) { + var def = defaultErrorReporter(currentLanguage); + var errorReporter = customErrorReporter ? function (error, data, schema) { + return customErrorReporter(error, data, schema) || def(error, data, schema); + } : def; + var context = new ValidatorContext(globalContext, false, errorReporter, checkRecursive, banUnknownProperties); + if (typeof schema === "string") { + schema = {"$ref": schema}; + } + context.addSchema("", schema); + var error = context.validateAll(data, schema, null, null, ""); + if (!error && banUnknownProperties) { + error = context.banUnknownProperties(data, schema); + } + this.error = error; + this.missing = context.missing; + this.valid = (error === null); + + this.toString = function () { + if (this.error) { + return this.error.message; + } else { + return 'Object passed schema validation'; + } + }; + + return this.valid; + }, + validateResult: function () { + var result = {}; + this.validate.apply(result, arguments); + return result; + }, + validateMultiple: function (data, schema, checkRecursive, banUnknownProperties) { + var def = defaultErrorReporter(currentLanguage); + var errorReporter = customErrorReporter ? function (error, data, schema) { + return customErrorReporter(error, data, schema) || def(error, data, schema); + } : def; + var context = new ValidatorContext(globalContext, true, errorReporter, checkRecursive, banUnknownProperties); + if (typeof schema === "string") { + schema = {"$ref": schema}; + } + context.addSchema("", schema); + context.validateAll(data, schema, null, null, ""); + if (banUnknownProperties) { + context.banUnknownProperties(data, schema); + } + var result = {}; + result.errors = context.errors; + result.missing = context.missing; + result.valid = (result.errors.length === 0); + return result; + }, + addSchema: function () { + return globalContext.addSchema.apply(globalContext, arguments); + }, + getSchema: function () { + return globalContext.getSchema.apply(globalContext, arguments); + }, + getSchemaMap: function () { + return globalContext.getSchemaMap.apply(globalContext, arguments); + }, + getSchemaUris: function () { + return globalContext.getSchemaUris.apply(globalContext, arguments); + }, + getMissingUris: function () { + return globalContext.getMissingUris.apply(globalContext, arguments); + }, + dropSchemas: function () { + globalContext.dropSchemas.apply(globalContext, arguments); + }, + defineKeyword: function () { + globalContext.defineKeyword.apply(globalContext, arguments); + }, + defineError: function (codeName, codeNumber, defaultMessage) { + if (typeof codeName !== 'string' || !/^[A-Z]+(_[A-Z]+)*$/.test(codeName)) { + throw new Error('Code name must be a string in UPPER_CASE_WITH_UNDERSCORES'); + } + if (typeof codeNumber !== 'number' || codeNumber%1 !== 0 || codeNumber < 10000) { + throw new Error('Code number must be an integer > 10000'); + } + if (typeof ErrorCodes[codeName] !== 'undefined') { + throw new Error('Error already defined: ' + codeName + ' as ' + ErrorCodes[codeName]); + } + if (typeof ErrorCodeLookup[codeNumber] !== 'undefined') { + throw new Error('Error code already used: ' + ErrorCodeLookup[codeNumber] + ' as ' + codeNumber); + } + ErrorCodes[codeName] = codeNumber; + ErrorCodeLookup[codeNumber] = codeName; + ErrorMessagesDefault[codeName] = ErrorMessagesDefault[codeNumber] = defaultMessage; + for (var langCode in languages) { + var language = languages[langCode]; + if (language[codeName]) { + language[codeNumber] = language[codeNumber] || language[codeName]; + } + } + }, + reset: function () { + globalContext.reset(); + this.error = null; + this.missing = []; + this.valid = true; + }, + missing: [], + error: null, + valid: true, + normSchema: normSchema, + resolveUrl: resolveUrl, + getDocumentUri: getDocumentUri, + errorCodes: ErrorCodes + }; + api.language(language || 'en'); + return api; +} + +var tv4 = createApi(); +tv4.addLanguage('en-gb', ErrorMessagesDefault); + +//legacy property +tv4.tv4 = tv4; + +return tv4; // used by _header.js to globalise. + +})); diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.xml new file mode 100644 index 00000000000..af0ecfd7f37 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.xml @@ -0,0 +1,28 @@ + + + + + + + + + + __name__ + tv4.js + + + content_type + application/javascript + + + precondition + + + + title + tv4.js + + + + + diff --git a/bt5/erp5_json_form/bt/comment b/bt5/erp5_json_form/bt/comment new file mode 100644 index 00000000000..58718d3dc1d --- /dev/null +++ b/bt5/erp5_json_form/bt/comment @@ -0,0 +1,2 @@ +jsonform is available at: +https://lab.nexedi.com/bk/rjs_json_form \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/dependency_list b/bt5/erp5_json_form/bt/dependency_list new file mode 100644 index 00000000000..db80eea7f74 --- /dev/null +++ b/bt5/erp5_json_form/bt/dependency_list @@ -0,0 +1 @@ +erp5_view_style \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/description b/bt5/erp5_json_form/bt/description new file mode 100644 index 00000000000..26febe9f694 --- /dev/null +++ b/bt5/erp5_json_form/bt/description @@ -0,0 +1 @@ +Form generation based on http://json-schema.org/ \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/maintainer_list b/bt5/erp5_json_form/bt/maintainer_list new file mode 100644 index 00000000000..452d733bbab --- /dev/null +++ b/bt5/erp5_json_form/bt/maintainer_list @@ -0,0 +1 @@ +bk \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/template_format_version b/bt5/erp5_json_form/bt/template_format_version new file mode 100644 index 00000000000..56a6051ca2b --- /dev/null +++ b/bt5/erp5_json_form/bt/template_format_version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/template_skin_id_list b/bt5/erp5_json_form/bt/template_skin_id_list new file mode 100644 index 00000000000..d1e8bf126ce --- /dev/null +++ b/bt5/erp5_json_form/bt/template_skin_id_list @@ -0,0 +1 @@ +erp5_json_form \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/title b/bt5/erp5_json_form/bt/title new file mode 100644 index 00000000000..d1e8bf126ce --- /dev/null +++ b/bt5/erp5_json_form/bt/title @@ -0,0 +1 @@ +erp5_json_form \ No newline at end of file diff --git a/bt5/erp5_json_form/bt/version b/bt5/erp5_json_form/bt/version new file mode 100644 index 00000000000..48360de846a --- /dev/null +++ b/bt5/erp5_json_form/bt/version @@ -0,0 +1 @@ +5.4.7 \ No newline at end of file -- 2.30.9 From 7385e43c876d43df8d35280ab3b70e0fc4e89c12 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 11 Jun 2018 18:41:35 +0000 Subject: [PATCH 03/49] erp5_web_renderjs_ui: add design for erp5_json_form --- .../rjs_gadget_erp5_nojqm_css.css | 33 +++++++++++++++++ .../erp5_web_renderjs_ui/erp5css.less.txt | 36 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css index 28976ae0d76..cabde9d7097 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_nojqm_css.css @@ -1802,6 +1802,39 @@ div[data-gadget-url$="gadget_erp5_page_front.html"] > ul > li li { padding: 3pt 6pt; } /********************************************** +* JSONForm +**********************************************/ +fieldset > .jsonformfield { + padding-left: 0; +} +.jsonformfield { + display: flex; + /*padding-left: 20px;*/ + padding-top: 3px; + /*margin-left: 15px;*/ +} +.jsonformfield button { + display: block; + vertical-align: top; +} +.jsonformfield .ui-btn-icon-top::before { + vertical-align: top; +} +.jsonformfield label { + word-break: keep-all; + hyphens: none; +} +.jsonformfield span { + color: #5e7f8d; +} +.jsonformfield .error { + color: #E82525; + font-weight: 600; +} +.jsonformfield input[type=number] { + text-align: right; +} +/********************************************** * Icons **********************************************/ .ui-btn-icon-top::before, diff --git a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt index a89dd34ce48..fcd6358b7fe 100644 --- a/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt +++ b/bt5/erp5_web_renderjs_ui/SkinTemplateItem/portal_skins/erp5_web_renderjs_ui/erp5css.less.txt @@ -2045,6 +2045,42 @@ div[data-gadget-url$="gadget_erp5_page_front.html"] { } } +/********************************************** +* JSONForm +**********************************************/ + +fieldset > .jsonformfield { + padding-left: 0 +} + +.jsonformfield { + display: flex; + /*padding-left: 20px;*/ + padding-top: 3px; + /*margin-left: 15px;*/ + button { + display: block; + vertical-align: top; + } + .ui-btn-icon-top::before { + vertical-align: top; + } + label { + word-break: keep-all; + hyphens: none; + } + span { + color: rgb(94, 127, 141) + } + .error { + color: #E82525; + font-weight: 600; + } + input[type=number] { + text-align:right; + } +} + /********************************************** * Icons **********************************************/ -- 2.30.9 From 2591a526cea1f9a25514bc4f337bbf664b4a2d7f Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 11 Jun 2018 15:19:47 +0000 Subject: [PATCH 04/49] erp5_officejs: add schema_editor --- .../gadget_erp5_ojs_schema_panel.html.html | 73 ++ .../gadget_erp5_ojs_schema_panel.html.xml | 321 ++++++++ .../gadget_erp5_ojs_schema_panel.js.js | 317 ++++++++ .../gadget_erp5_ojs_schema_panel.js.xml | 321 ++++++++ .../gadget_erp5_ojs_schema_router.html.html | 26 + .../gadget_erp5_ojs_schema_router.html.xml | 325 ++++++++ ...p5_page_ojs_schema_document_list.html.html | 19 + ...rp5_page_ojs_schema_document_list.html.xml | 321 ++++++++ ...t_erp5_page_ojs_schema_document_list.js.js | 138 ++++ ..._erp5_page_ojs_schema_document_list.js.xml | 321 ++++++++ ...et_officejs_jio_json_schema_view.html.html | 26 + ...get_officejs_jio_json_schema_view.html.xml | 321 ++++++++ ...gadget_officejs_jio_json_schema_view.js.js | 170 +++++ ...adget_officejs_jio_json_schema_view.js.xml | 321 ++++++++ .../gadget_officejs_schema.appcache.xml | 470 ++++++++++++ .../web_site_module/officejs_schema.xml | 718 ++++++++++++++++++ .../web_site_module/officejs_schema/app.xml | 666 ++++++++++++++++ bt5/erp5_officejs/bt/dependency_list | 1 + ..._keep_last_workflow_history_only_path_list | 4 + .../bt/template_keep_workflow_path_list | 4 + bt5/erp5_officejs/bt/template_path_list | 4 + 21 files changed, 4887 insertions(+) create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.html create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.html create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html new file mode 100644 index 00000000000..1ef70611acd --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html @@ -0,0 +1,73 @@ + + + + + + ERP5 Schema Panel + + + + + + + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.xml new file mode 100644 index 00000000000..15273ceac57 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.xml @@ -0,0 +1,321 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_erp5_ojs_schema_panel.html + + + description + + + + + + id + gadget_erp5_ojs_schema_panel.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528361035.49 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.3755.60725.37512 + + + state + current + + + time + + + + + + + + + + + 1528473429.83 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528309343.96 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js new file mode 100644 index 00000000000..916a25b826c --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js @@ -0,0 +1,317 @@ +/*jslint nomen: true, indent: 2, maxerr: 3, unparam: true */ +/*global window, document, rJS, Handlebars, RSVP, Node, loopEventListener */ +(function (window, document, rJS, Handlebars, RSVP, Node, loopEventListener) { + "use strict"; + + ///////////////////////////////////////////////////////////////// + // temlates + ///////////////////////////////////////////////////////////////// + // Precompile templates while loading the first gadget instance + var gadget_klass = rJS(window), + template_element = gadget_klass.__template_element, + panel_template_header = Handlebars.compile(template_element + .getElementById("panel-template-header") + .innerHTML), + panel_template_body = Handlebars.compile(template_element + .getElementById("panel-template-body") + .innerHTML), + panel_template_body_list = Handlebars.compile(template_element + .getElementById("panel-template-body-list") + .innerHTML), + panel_template_body_desktop = Handlebars.compile(template_element + .getElementById("panel-template-body-desktop") + .innerHTML); + + gadget_klass + .setState({ + visible: false, + desktop: false + }) + ////////////////////////////////////////////// + // acquired method + ////////////////////////////////////////////// + .declareAcquiredMethod("getUrlFor", "getUrlFor") + .declareAcquiredMethod("translateHtml", "translateHtml") + .declareAcquiredMethod("translate", "translate") + .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("getUrlParameter", "getUrlParameter") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + .declareMethod('toggle', function () { + return this.changeState({ + visible: !this.state.visible + }); + }) + .declareMethod('close', function () { + return this.changeState({ + visible: false + }); + }) + + .declareMethod('render', function (options) { + var erp5_document = options.erp5_document, + workflow_list, + view_list, + context = this; + if (erp5_document !== undefined) { + workflow_list = erp5_document._links.action_workflow || []; + view_list = erp5_document._links.action_object_view || []; + if (workflow_list.constructor !== Array) { + workflow_list = [workflow_list]; + } + if (view_list.constructor !== Array) { + view_list = [view_list]; + } + // Prevent has much as possible to modify the DOM panel + // stateChange prefer to compare strings + workflow_list = JSON.stringify(workflow_list); + view_list = JSON.stringify(view_list); + } + return context.getUrlParameter('editable') + .push(function (editable) { + return context.changeState({ + workflow_list: workflow_list, + view_list: view_list, + global: true, + editable: options.editable || editable || false + }); + }); + }) + + .onStateChange(function (modification_dict) { + var context = this, + gadget = this, + queue = new RSVP.Queue(), + tmp_element; + + if (modification_dict.hasOwnProperty("visible")) { + if (this.state.visible) { + if (!this.element.classList.contains('visible')) { + this.element.classList.toggle('visible'); + } + } else { + if (this.element.classList.contains('visible')) { + this.element.classList.remove('visible'); + } + } + } + + if (modification_dict.hasOwnProperty("global")) { + queue + .push(function () { + // XXX: Customize panel header! + return context.translateHtml( + panel_template_header() + + panel_template_body() + ); + }) + .push(function (my_translated_or_plain_html) { + tmp_element = document.createElement('div'); + tmp_element.innerHTML = my_translated_or_plain_html; + + return context.declareGadget('gadget_erp5_searchfield.html', { + scope: "erp5_searchfield", + element: tmp_element.querySelector('[data-gadget-scope="erp5_searchfield"]') + }); + }) + .push(function (search_gadget) { + return search_gadget.render({ + focus: false + }); + }) + + .push(function () { + context.element.querySelector("div").appendChild(tmp_element); + return context.listenResize(); + }); + } + + if (modification_dict.hasOwnProperty("editable")) { + queue + // Update the global links + .push(function () { + return RSVP.all([ + context.getUrlFor({command: 'display', options: {page: "ojs_schema_document_list"}}), + context.getUrlFor({command: 'display', options: {page: "ojs_configurator"}}), + context.getUrlFor({command: 'display', options: {page: "ojs_sync", 'auto_repair': true}}), + context.getUrlFor({command: 'index', options: {page: "ojs_multi_upload"}}) + ]); + }) + .push(function (result_list) { + return context.translateHtml( + panel_template_body_list({ + "document_list_href": result_list[0], + "storage_href": result_list[1], + "sync_href": result_list[2], + "multi_upload_href": result_list[3] + }) + ); + }) + + .push(function (result) { + context.element.querySelector("ul").innerHTML = result; + }); + } + + if ((this.state.global === true) && + (modification_dict.hasOwnProperty("desktop") || + modification_dict.hasOwnProperty("editable") || + modification_dict.hasOwnProperty("workflow_list") || + modification_dict.hasOwnProperty("view_list"))) { + if (!(this.state.desktop && (this.state.view_list !== undefined))) { + queue + .push(function () { + gadget.element.querySelector("dl").textContent = ''; + }); + } else { + queue + .push(function () { + var i = 0, + promise_list = [], + workflow_list = JSON.parse(gadget.state.workflow_list), + view_list = JSON.parse(gadget.state.view_list); + + for (i = 0; i < workflow_list.length; i += 1) { + promise_list.push( + gadget.getUrlFor({ + command: 'change', + options: { + view: workflow_list[i].href, + page: undefined + } + }) + ); + } + for (i = 0; i < view_list.length; i += 1) { + promise_list.push( + gadget.getUrlFor({ + command: 'change', + options: { + view: view_list[i].href, + page: undefined + } + }) + ); + } + return RSVP.all(promise_list); + }) + .push(function (result_list) { + var i, + result_workflow_list = [], + result_view_list = [], + workflow_list = JSON.parse(gadget.state.workflow_list), + view_list = JSON.parse(gadget.state.view_list); + + for (i = 0; i < workflow_list.length; i += 1) { + result_workflow_list.push({ + title: workflow_list[i].title, + href: result_list[i] + }); + } + for (i = 0; i < view_list.length; i += 1) { + result_view_list.push({ + title: view_list[i].title, + href: result_list[i + workflow_list.length] + }); + } + gadget.element.querySelector("dl").innerHTML = panel_template_body_desktop({ + workflow_list: result_workflow_list, + view_list: result_view_list + }); + }); + } + } + + return queue; + }) + + ///////////////////////////////////////////////////////////////// + // declared services + ///////////////////////////////////////////////////////////////// + .onEvent('click', function (evt) { + if ((evt.target.nodeType === Node.ELEMENT_NODE) && + (evt.target.tagName === 'BUTTON')) { + return this.toggle(); + } + }, false, false) + + .declareJob('listenResize', function () { + // resize should be only trigger after the render method + // as displaying the panel rely on external gadget (for translation for example) + var result, + event, + context = this; + function extractSizeAndDispatch() { + if (window.matchMedia("(min-width: 85em)").matches) { + return context.changeState({ + desktop: true + }); + } + return context.changeState({ + desktop: false + }); + } + result = loopEventListener(window, 'resize', false, + extractSizeAndDispatch); + event = document.createEvent("Event"); + event.initEvent('resize', true, true); + window.dispatchEvent(event); + return result; + }) + + .allowPublicAcquisition('notifyChange', function (argument_list, scope) { + if (scope === 'erp5_checkbox') { + var context = this; + return context.getDeclaredGadget('erp5_checkbox') + .push(function (gadget) { + return gadget.getContent(); + }) + .push(function (result) { + var options = {editable: undefined}; + if (result.editable.length === 1) { + options.editable = true; + } + return context.redirect({command: 'change', options: options}); + }); + } + // Typing a search query should not modify the header status + return; + }) + .allowPublicAcquisition('notifyValid', function () { + // Typing a search query should not modify the header status + return; + }) + + .onEvent('submit', function () { + var gadget = this; + + return gadget.getDeclaredGadget("erp5_searchfield") + .push(function (search_gadget) { + return search_gadget.getContent(); + }) + .push(function (data) { + var options = { + page: "ojs_schema_document_list" + }; + if (data.search) { + options.extended_search = data.search; + } + // Remove focus from the search field + document.activeElement.blur(); + return gadget.redirect({command: 'display', options: options}); + }); + + }, false, true) + + .onEvent('blur', function (evt) { + // XXX Horrible hack to clear the search when focus is lost + // This does not follow renderJS design, as a gadget should not touch + // another gadget content + if (evt.target.type === 'search') { + evt.target.value = ""; + } + }, true, false); + +}(window, document, rJS, Handlebars, RSVP, Node, loopEventListener)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.xml new file mode 100644 index 00000000000..9082b81ed85 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.xml @@ -0,0 +1,321 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_erp5_ojs_schema_panel.js + + + description + + + + + + id + gadget_erp5_ojs_schema_panel.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528361027.63 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.5915.6298.25190 + + + state + current + + + time + + + + + + + + + + + 1528741133.22 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528310368.01 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html new file mode 100644 index 00000000000..1f9627c81b7 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html @@ -0,0 +1,26 @@ + + + + + + OfficeJS Schema Router Gadget + + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.xml new file mode 100644 index 00000000000..fcfa3b65324 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.xml @@ -0,0 +1,325 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_erp5_ojs_schema_router.html + + + description + + + + + + id + gadget_erp5_ojs_schema_router.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + title + gadget_erp5_ojs_schema_router.html + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528361019.52 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.3755.43319.6656 + + + state + current + + + time + + + + + + + + + + + 1528473447.8 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528311094.78 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.html new file mode 100644 index 00000000000..484477c7374 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.html @@ -0,0 +1,19 @@ + + + + + + + + OfficeJS Jio Schema Document List + + + + + + + + +
+ + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.xml new file mode 100644 index 00000000000..327ea3428bb --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.html.xml @@ -0,0 +1,321 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_erp5_page_ojs_schema_document_list.html + + + description + + + + + + id + gadget_erp5_page_ojs_schema_document_list.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528361012.65 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.3755.35782.24098 + + + state + current + + + time + + + + + + + + + + + 1528473464.7 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528311178.97 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js new file mode 100644 index 00000000000..19c7abae562 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js @@ -0,0 +1,138 @@ +/*global window, rJS, RSVP */ +/*jslint nomen: true, indent: 2, maxerr: 3 */ +(function (window, rJS, RSVP) { + "use strict"; + + rJS(window) + ///////////////////////////////////////////////////////////////// + // Acquired methods + ///////////////////////////////////////////////////////////////// + .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("getUrlParameter", "getUrlParameter") + .declareAcquiredMethod("getUrlFor", "getUrlFor") + .declareAcquiredMethod("jio_allDocs", "jio_allDocs") + .declareAcquiredMethod("getSetting", "getSetting") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + + .allowPublicAcquisition("jio_allDocs", function (param_list) { + var gadget = this; + return gadget.jio_allDocs(param_list[0]) + .push(function (result) { + var i, date, len = result.data.total_rows; + for (i = 0; i < len; i += 1) { + if (result.data.rows[i].value.hasOwnProperty("modification_date")) { + date = new Date(result.data.rows[i].value.modification_date); + result.data.rows[i].value.modification_date = { + field_gadget_param: { + allow_empty_time: 0, + ampm_time_style: 0, + css_class: "date_field", + date_only: 0, + description: "The Date", + editable: 0, + hidden: 0, + hidden_day_is_last_day: 0, + "default": date.toUTCString(), + key: "modification_date", + required: 0, + timezone_style: 0, + title: "Modification Date", + type: "DateTimeField" + } + }; + result.data.rows[i].value["listbox_uid:list"] = { + key: "listbox_uid:list", + value: 2713 + }; + } + } + return result; + }); + }) + + .allowPublicAcquisition('notifySubmit', function () { + return this.triggerSubmit(); + }) + + .declareMethod("triggerSubmit", function () { + var argument_list = arguments; + return this.getDeclaredGadget('form_list') + .push(function (gadget) { + return gadget.triggerSubmit.apply(gadget, argument_list); + }); + }) + + .declareMethod("render", function () { + var gadget = this; + + return new RSVP.Queue() + .push(function () { + return RSVP.all([ + gadget.getDeclaredGadget('form_list'), + gadget.getSetting("portal_type") + ]); + }) + .push(function (result) { + var column_list = [ + ['title', 'Title'], + ['reference', 'Reference'], + ['language', 'Language'], + ['description', 'Description'], + ['version', 'Version'], + ['modification_date', 'Modification Date'] + ]; + return result[0].render({ + erp5_document: { + "_embedded": {"_view": { + "listbox": { + "column_list": column_list, + "show_anchor": 0, + "default_params": {}, + "editable": 1, + "editable_column_list": [], + "key": "field_listbox", + "lines": 30, + "list_method": "portal_catalog", + "query": "urn:jio:allDocs?query=portal_type%3A%22" + + result[1] + "%22", + "portal_type": [], + "search_column_list": column_list, + "sort_column_list": column_list, + "sort": [['modification_date', 'descending']], + "title": "Schemas", + "type": "ListBox" + } + }}, + "_links": { + "type": { + // form_list display portal_type in header + name: "" + } + } + }, + form_definition: { + group_list: [[ + "bottom", + [["listbox"]] + ]] + } + }); + }) + .push(function () { + return RSVP.all([ + gadget.getUrlFor({command: "index", options: {"page": "ojs_multi_upload"}}), + gadget.getSetting('document_title_plural') + ]); + }) + .push(function (result) { + return gadget.updateHeader({ + page_title: result[1], + filter_action: true, + add_url: result[0] + }); + }); + }); +}(window, rJS, RSVP)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.xml new file mode 100644 index 00000000000..70818e1e67d --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.xml @@ -0,0 +1,321 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_erp5_page_ojs_schema_document_list.js + + + description + + + + + + id + gadget_erp5_page_ojs_schema_document_list.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528361005.14 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.2945.55875.51438 + + + state + current + + + time + + + + + + + + + + + 1528312444.69 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528312422.54 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.html new file mode 100644 index 00000000000..4145b1a952d --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.html @@ -0,0 +1,26 @@ + + + + + + + OfficeJS Jio Schema View + + + + + + + + + +
+ +
+
+
+ + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.xml new file mode 100644 index 00000000000..a6ddf7c2395 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.html.xml @@ -0,0 +1,321 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_officejs_jio_json_schema_view.html + + + description + + + + + + id + gadget_officejs_jio_json_schema_view.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528360995.81 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.3755.17326.23210 + + + state + current + + + time + + + + + + + + + + + 1528473480.92 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528312462.14 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js new file mode 100644 index 00000000000..1e02747457c --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js @@ -0,0 +1,170 @@ +/*global window, rJS, RSVP, jIO, URL, + promiseEventListener, document*/ +/*jslint nomen: true, indent: 2, maxerr: 3 */ +(function (window, jIO, rJS, RSVP) { + "use strict"; + + rJS(window) + ///////////////////////////////////////////////////////////////// + // Acquired methods + ///////////////////////////////////////////////////////////////// + .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("getUrlParameter", "getUrlParameter") + .declareAcquiredMethod("getUrlFor", "getUrlFor") + .declareAcquiredMethod("updateDocument", "updateDocument") + .declareAcquiredMethod("notifySubmitting", "notifySubmitting") + .declareAcquiredMethod("notifySubmitted", 'notifySubmitted') + .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("jio_get", "jio_get") + .declareAcquiredMethod("jio_put", "jio_put") + .declareAcquiredMethod("jio_getAttachment", "jio_getAttachment") + .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + .declareMethod("render", function (options) { + var gadget = this; + return gadget.changeState({ + jio_key: options.jio_key, + doc: options.doc + }); + }) + + .onEvent('submit', function () { + var gadget = this; + return gadget.notifySubmitting() + .push(function () { + return gadget.getDeclaredGadget('form_view'); + }) + .push(function (form_gadget) { + return form_gadget.getContent(); + }) + .push(function (content) { + var list = [], + blob; + if (content.data_file_upload) { + blob = jIO.util.dataURItoBlob(content.data_file_upload.url); + content.title = content.data_file_upload.file_name; + delete content.data_file_upload; + list = [ + gadget.updateDocument(content), + gadget.jio_putAttachment(gadget.state.jio_key, 'data', blob) + ]; + } else if (content.data) { + blob = new Blob([content.data]); + delete content.data; + list = [ + gadget.updateDocument(content), + gadget.jio_putAttachment(gadget.state.jio_key, 'data', blob) + ]; + } else { + list = [gadget.updateDocument(content)]; + } + return RSVP.all(list); + }) + .push(function () { + return gadget.notifySubmitted({message: 'Data Updated', status: 'success'}); + }, function (error) { + if (error.target && error.target.error.name === 'NotReadableError') { + return gadget.notifySubmitted({message: error.target.error.message, status: 'fail'}); + } + throw error; + }).push(function () { + return gadget.redirect({ + command: 'reload' + }); + }); + }) + + .declareMethod("triggerSubmit", function () { + return this.element.querySelector('button[type="submit"]').click(); + }) + + .onStateChange(function () { + var gadget = this; + return RSVP.Queue() + .push(function () { + return RSVP.all([ + gadget.getDeclaredGadget('form_view'), + gadget.jio_getAttachment(gadget.state.jio_key, 'data', {format: "json"}) + ]); + }) + .push(function (result) { + return result[0].render({ + erp5_document: { + "_embedded": { + "_view": { + "my_title": { + "description": "", + "title": "Title", + "default": gadget.state.doc.title, + "css_class": "", + "required": 1, + "editable": 1, + "key": "title", + "hidden": 0, + "type": "StringField" + }, + "my_file": { + "description": "", + "title": "Upload and rewrite this document", + "default": "", + "css_class": "", + "required": 0, + "editable": 1, + "key": "data_file_upload", + "hidden": 0, + "accept": "application/json", + "type": "FileField" + }, + "my_content": { + "default": result[1], + "css_class": "", + "required": 0, + "editable": 1, + "key": "data", + "hidden": 0, + "type": "GadgetField", + "renderjs_extra": '{"name": "data"}', + "url": "jsonform.gadget.html", + "sandbox": "public" + } + } + }, + "_links": { + "type": { + // form_list display portal_type in header + name: "" + } + } + }, + form_definition: { + group_list: [[ + "left", + [["my_title"], ["my_file"]] + ], [ + "bottom", + [["my_content"]] + ]] + } + }); + }) + .push(function () { + return RSVP.all([ + gadget.getUrlFor({command: 'history_previous'}), + gadget.getUrlFor({command: 'selection_previous'}), + gadget.getUrlFor({command: 'selection_next'}) + ]); + }) + .push(function (url_list) { + return gadget.updateHeader({ + page_title: gadget.state.doc.title, + save_action: true, + selection_url: url_list[0], + previous_url: url_list[1], + next_url: url_list[2] + }); + }); + }); +}(window, jIO, rJS, RSVP)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.xml new file mode 100644 index 00000000000..4ec720277f4 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.xml @@ -0,0 +1,321 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_officejs_jio_json_schema_view.js + + + description + + + + + + id + gadget_officejs_jio_json_schema_view.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528360876.11 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.4203.52459.13892 + + + state + current + + + time + + + + + + + + + + + 1528478452.62 + UTC + + + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + empty + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528312499.11 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml new file mode 100644 index 00000000000..faeb38c60e3 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml @@ -0,0 +1,470 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + categories + + + contributor/person_module/1 + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_officejs_schema.appcache + + + description + + + + + + id + gadget_officejs_schema.appcache + + + language + en + + + portal_type + Web Manifest + + + short_title + + + + + + text_content + CACHE MANIFEST\n +# generated on Fri, 25 Jun 2016 11:45:33 +0000\n +# XXX + fonts\n +# images/ajax-loader.gif\n +CACHE:\n +#officejs\n +app/\n +font-awesome/font-awesome.css\n +font-awesome/font-awesome-webfont.eot\n +font-awesome/font-awesome-webfont.woff\n +font-awesome/font-awesome-webfont.woff2\n +font-awesome/font-awesome-webfont.ttf\n +font-awesome/font-awesome-webfont.svg\n +gadget_erp5_nojqm.css\n +jio_ojs_storage.js\n +gadget_erp5_global.js\n +URI.js\n +dygraph.js\n +handlebars.js\n +jiodev.js\n +renderjs.js\n +rsvp.js\n +gadget_global.js\n +erp5_launcher_nojqm.js\n +gadget_officejs_router.js\n +gadget_erp5_router.html\n +gadget_erp5_router.js\n +gadget_jio.html\n +gadget_jio.js\n +gadget_translate.html\n +gadget_translate.js\n +gadget_translation.html\n +gadget_translation.js\n +gadget_translation_data.js\n +gadget_erp5_editor_panel.html\n +gadget_erp5_editor_panel.js\n +gadget_erp5_ojs_panel.html\n +gadget_erp5_ojs_panel.js\n +gadget_erp5_header.html\n +gadget_erp5_header.js\n +gadget_ojs_jio.html\n +gadget_ojs_jio.js\n +gadget_erp5_page_ojs_controller.html\n +gadget_erp5_page_ojs_controller.js\n +gadget_erp5_page_ojs_add_document.html\n +gadget_erp5_page_ojs_add_document.js\n +gadget_erp5_page_ojs_configurator.html\n +gadget_erp5_page_ojs_configurator.js\n +gadget_erp5_page_ojs_dav_configurator.html\n +gadget_erp5_page_ojs_dav_configurator.js\n +gadget_erp5_page_ojs_erp5_configurator.html\n +gadget_erp5_page_ojs_erp5_configurator.js\n +gadget_erp5_page_ojs_dropbox_configurator.html\n +gadget_erp5_page_ojs_dropbox_configurator.js\n +gadget_erp5_page_ojs_sync.html\n +gadget_erp5_page_ojs_sync.js\n +gadget_erp5_page_ojs_document_list.html\n +gadget_erp5_page_ojs_document_list.js\n +gadget_ojs_configurator_access.html\n +gadget_ojs_configurator_access.js\n +gadget_html5_input.html\n +gadget_html5_input.js\n +gadget_erp5_field_multicheckbox.html\n +gadget_erp5_field_multicheckbox.js\n +gadget_erp5_searchfield.html\n +gadget_erp5_searchfield.js\n +gadget_erp5_pt_form_list.html\n +gadget_erp5_pt_form_list.js\n +gadget_erp5_form.html\n +gadget_erp5_form.js\n +gadget_erp5_label_field.html\n +gadget_erp5_label_field.js\n +gadget_erp5_field_listbox.html\n +gadget_erp5_field_listbox.js\n +gadget_erp5_field_datetime.html\n +gadget_erp5_field_datetime.js\n +gadget_html5_element.html\n +gadget_html5_element.js\n +gadget_erp5_notification.html\n +gadget_erp5_notification.js\n +gadget_erp5_field_string.html\n +gadget_erp5_field_string.js\n +gadget_erp5_field_editor.html\n +gadget_erp5_field_editor.js\n +gadget_erp5_field_gadget.html\n +gadget_erp5_field_gadget.js\n +gadget_erp5_field_file.html\n +gadget_erp5_field_file.js\n +gadget_erp5_search_editor.html\n +gadget_erp5_search_editor.js\n +gadget_erp5_sort_editor.html\n +gadget_erp5_sort_editor.js\n +gadget_erp5_field_password.html\n +gadget_erp5_field_password.js\n +gadget_erp5_field_textarea.html\n +gadget_erp5_field_textarea.js\n +gadget_html5_textarea.html\n +gadget_html5_textarea.js\n +gadget_editor.html\n +gadget_editor.js\n +gadget_button_maximize.html\n +gadget_button_maximize.js\n +gadget_erp5_configure_editor.html\n +gadget_erp5_configure_editor.js\n +gadget_erp5_ojs_schema_router.html\n +gadget_erp5_ojs_schema_panel.html\n +gadget_erp5_ojs_schema_panel.js\n +gadget_officejs_jio_json_schema_view.html\n +gadget_officejs_jio_json_schema_view.js\n +gadget_erp5_page_ojs_multi_upload.html\n +gadget_erp5_page_ojs_multi_upload.js\n +gadget_erp5_page_ojs_schema_document_list.html\n +gadget_erp5_page_ojs_schema_document_list.js\n +\n +#jsonform\n +jio.js\n +gadget_html5_select.html\n +gadget_html5_select.js\n +json-schema/schema4.json\n +json-schema/schema6.json\n +json-schema/schema7.json\n +jsonform.gadget.html\n +jsonform.gadget.js\n +jsonform/gadget_json_generated_form_child.html\n +jsonform/gadget_json_generated_form_child.js\n +jsonform/tv4.js\n +\n +#setting\n +gadget_officejs_setting.js\n +gadget_officejs_setting.html\n +\n +\n +NETWORK:\n +* + + + title + gadget_officejs_schema.appcache + + + url_string + + + + + + version + 001 + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528361044.61 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.9700.26907.3566 + + + state + current + + + time + + + + + + + + + + + 1528717715.13 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1528316831.84 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml new file mode 100644 index 00000000000..4b2fef241d6 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml @@ -0,0 +1,718 @@ + + + + + + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Add_portal_folders_Permission + + + Assignor + Manager + + + + + _Copy_or_Move_Permission + + + Assignor + Manager + + + + + _Delete_objects_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Assignee + Assignor + Manager + Owner + + + + + __before_publishing_traverse__ + + + + + + + + + + _defined_in_class + 1 + + + _hookname + __before_publishing_traverse__ + + + _list + + + AAAAAAAAAAI= + + + + + _prior + + + + + + + + + + + __before_traverse__ + + + + + + 99 + ERP5 Web Site/officejs_schema + + + + AAAAAAAAAAI= + + + + + + + _count + + AAAAAAAAAAM= + + + + _identity_criterion + + AAAAAAAAAAQ= + + + + _local_properties + + + + + id + frontpage_gadget_url + + + type + string + + + + + id + configuration_frontpage_gadget_url + + + type + string + + + + + id + configuration_application_title + + + type + string + + + + + id + configuration_hateoas_url + + + type + string + + + + + id + configuration_view_action_category + + + type + string + + + + + id + configuration_default_view_action_reference + + + type + string + + + + + id + configuration_panel_gadget_url + + + type + string + + + + + id + configuration_router_gadget_url + + + type + string + + + + + id + configuration_jio_gadget_url + + + type + string + + + + + id + configuration_translation_gadget_url + + + type + string + + + + + id + configuration_manifest_url + + + type + string + + + + + id + configuration_header_gadget_url + + + type + string + + + + + id + configuration_content_security_policy + + + type + string + + + + + id + configuration_x_frame_options + + + type + string + + + + + id + configuration_latest_document_version + + + type + string + + + + + id + configuration_latest_version + + + type + string + + + + + id + configuration_cache_file + + + type + string + + + + + id + configuration_redirect_url + + + type + string + + + + + id + configuration_landing_page + + + type + string + + + + + id + configuration_sub_gadget_installer + + + type + string + + + + + + + _mt_index + + AAAAAAAAAAU= + + + + _range_criterion + + AAAAAAAAAAY= + + + + _tree + + AAAAAAAAAAc= + + + + available_language + + + en + + + + + categories + + + caching_policy/must-revalidate + aggregate/web_page_module/gadget_officejs_bootloader.html + + + + + configuration_application_title + Text Editor + + + configuration_cache_file + gadget_officejs_schema.appcache + + + configuration_content_security_policy + default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data: + + + configuration_default_view_action_reference + + + + + + configuration_frontpage_gadget_url + + + + + + configuration_hateoas_url + hateoas/ + + + configuration_header_gadget_url + gadget_officejs_header.html + + + configuration_jio_gadget_url + gadget_officejs_jio.html + + + configuration_landing_page + + + + + + configuration_latest_document_version + 001 + + + configuration_latest_version + app + + + configuration_manifest_url + gadget_officejs.appcache + + + configuration_panel_gadget_url + gadget_officejs_application_panel.html + + + configuration_redirect_url + app + + + configuration_router_gadget_url + gadget_officejs_text_editor_router.html + + + configuration_sub_gadget_installer + + + + + + configuration_translation_gadget_url + gadget_translation.html + + + configuration_view_action_category + + + + + + configuration_x_frame_options + SAMEORIGIN + + + container_layout + WebSection_renderOfficeJSApplicationPage + + + content_layout + WebSection_renderOfficeJSApplicationPage + + + custom_render_method_id + WebSection_renderOfficeJSApplicationPage + + + description + + + + + + frontpage_gadget_url + gadget_woelfel_pt_frontpage.html + + + id + officejs_schema + + + layout_configuration_form_id + WebSection_viewOfficeJSApplicationPreference + + + portal_type + Web Site + + + short_title + + + + + + skin_selection_name + Officejs + + + static_language_selection + 0 + + + title + OfficeJS Schema Editor + + + visible + 1 + + + workflow_history + + AAAAAAAAAAg= + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + data + + + + + + + + + + + + + + + + + + + + + + + data + + + + + + + + + + + + + + + + + + + + + + + data + + + + category_publication_workflow + + AAAAAAAAAAk= + + + + edit_workflow + + AAAAAAAAAAo= + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528355166.78 + UTC + + + + + + + validation_state + embedded + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.9516.24741.45312 + + + state + current + + + time + + + + + + + + + + + 1528722116.43 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml new file mode 100644 index 00000000000..019ee156661 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml @@ -0,0 +1,666 @@ + + + + + + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Add_portal_folders_Permission + + + Assignor + Manager + + + + + _Copy_or_Move_Permission + + + Assignor + Manager + + + + + _Delete_objects_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Assignee + Assignor + Manager + Owner + + + + + __before_publishing_traverse__ + + + + + + + + + + _defined_in_class + 1 + + + _hookname + __before_publishing_traverse__ + + + _list + + + AAAAAAAAAAI= + + + + + _prior + + + + + + + + + + + __before_traverse__ + + + + + + 99 + ERP5 Web Section/app + + + + AAAAAAAAAAI= + + + + + + + __translation_dict + + + + + + _count + + AAAAAAAAAAM= + + + + _identity_criterion + + AAAAAAAAAAQ= + + + + _local_properties + + + + + id + configuration_router_gadget_url + + + type + string + + + + + id + configuration_application_title + + + type + string + + + + + id + configuration_jio_gadget_url + + + type + string + + + + + id + configuration_content_security_policy + + + type + string + + + + + id + configuration_panel_gadget_url + + + type + string + + + + + id + configuration_translation_gadget_url + + + type + string + + + + + id + configuration_header_gadget_url + + + type + string + + + + + id + configuration_hateoas_url + + + type + string + + + + + id + configuration_manifest_url + + + type + string + + + + + id + configuration_x_frame_options + + + type + string + + + + + id + configuration_default_jio_document_page_gadget_url + + + type + string + + + + + id + configuration_default_view_action_reference + + + type + string + + + + + id + configuration_frontpage_gadget_url + + + type + string + + + + + id + configuration_view_action_category + + + type + string + + + + + id + configuration_stylesheet_url + + + type + string + + + + + + + _mt_index + + AAAAAAAAAAU= + + + + _range_criterion + + AAAAAAAAAAY= + + + + _tree + + AAAAAAAAAAc= + + + + categories + + + caching_policy/must-revalidate + aggregate/web_page_module/rjs_gadget_erp5_launcher_html + + + + + configuration_application_title + Schema Editor + + + configuration_content_security_policy + default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data: + + + configuration_default_jio_document_page_gadget_url + ojs_controller + + + configuration_default_view_action_reference + jio_view + + + configuration_frontpage_gadget_url + ojs_schema_document_list + + + configuration_hateoas_url + ../hateoas/ + + + configuration_header_gadget_url + gadget_erp5_header.html + + + configuration_jio_gadget_url + gadget_ojs_jio.html + + + configuration_manifest_url + gadget_officejs_schema.appcache + + + configuration_panel_gadget_url + gadget_erp5_ojs_schema_panel.html + + + configuration_router_gadget_url + gadget_erp5_ojs_schema_router.html + + + configuration_stylesheet_url + + + + + + configuration_translation_gadget_url + + + + + + configuration_view_action_category + + + + + + configuration_x_frame_options + SAMEORIGIN + + + container_layout + WebSection_renderDefaultPageAsGadget + + + content_layout + WebSection_renderDefaultPageAsGadget + + + custom_render_method_id + WebSection_renderDefaultPageAsGadget + + + description + + + + + + empty_criterion_valid + 1 + + + id + app + + + int_index + + + + + + layout_configuration_form_id + WebSection_viewRenderJSPreference + + + membership_criterion_category + + + + + + portal_type + Web Section + + + short_title + + + + + + skin_selection_name + RJS + + + string_index + + + + + + test_method_id + + + + + + title + app + + + visible + 0 + + + workflow_history + + AAAAAAAAAAg= + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + data + + + + + + + + + + + + + + + + + + + + + + + data + + + + + + + + + + + + + + + + + + + + + + + data + + + + category_publication_workflow + + AAAAAAAAAAk= + + + + edit_workflow + + AAAAAAAAAAo= + + + + + + + + + + + + + + + + + + + action + + + + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1528355166.8 + UTC + + + + + + + validation_state + embedded + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.10031.58855.19404 + + + state + current + + + time + + + + + + + + + + + 1528737611.59 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/bt/dependency_list b/bt5/erp5_officejs/bt/dependency_list index 21d3ddb98a5..acdf8b6ac1e 100644 --- a/bt5/erp5_officejs/bt/dependency_list +++ b/bt5/erp5_officejs/bt/dependency_list @@ -1,5 +1,6 @@ erp5_web_renderjs_ui erp5_code_mirror +erp5_json_form erp5_multimedia erp5_notebook erp5_smart_assistant \ No newline at end of file diff --git a/bt5/erp5_officejs/bt/template_keep_last_workflow_history_only_path_list b/bt5/erp5_officejs/bt/template_keep_last_workflow_history_only_path_list index 1e07a43d03c..9f759160bc9 100644 --- a/bt5/erp5_officejs/bt/template_keep_last_workflow_history_only_path_list +++ b/bt5/erp5_officejs/bt/template_keep_last_workflow_history_only_path_list @@ -7,6 +7,8 @@ image_module/officejs_todomvc_* image_module/wallsearch_icon_svg web_page_module/dhtmlx_gantt_* web_page_module/fb_sdk_js +web_page_module/gadget_erp5_ojs_* +web_page_module/gadget_erp5_page_ojs_* web_page_module/gadget_field_* web_page_module/gadget_officejs_* web_page_module/jio_* @@ -32,6 +34,8 @@ web_site_module/officejs_notebook web_site_module/officejs_notebook/** web_site_module/officejs_pdf_viewer web_site_module/officejs_pdf_viewer/** +web_site_module/officejs_schema +web_site_module/officejs_schema/** web_site_module/officejs_svg_editor web_site_module/officejs_svg_editor/** web_site_module/officejs_text_editor diff --git a/bt5/erp5_officejs/bt/template_keep_workflow_path_list b/bt5/erp5_officejs/bt/template_keep_workflow_path_list index d595038c4cf..5f86f468c97 100644 --- a/bt5/erp5_officejs/bt/template_keep_workflow_path_list +++ b/bt5/erp5_officejs/bt/template_keep_workflow_path_list @@ -7,6 +7,8 @@ image_module/officejs_todomvc_* image_module/wallsearch_icon_svg web_page_module/dhtmlx_gantt_* web_page_module/fb_sdk_js +web_page_module/gadget_erp5_ojs_* +web_page_module/gadget_erp5_page_ojs_* web_page_module/gadget_field_* web_site_module/officejs_media_player web_page_module/gadget_officejs_* @@ -32,6 +34,8 @@ web_site_module/officejs_notebook web_site_module/officejs_notebook/** web_site_module/officejs_pdf_viewer web_site_module/officejs_pdf_viewer/** +web_site_module/officejs_schema +web_site_module/officejs_schema/** web_site_module/officejs_svg_editor web_site_module/officejs_svg_editor/** web_site_module/officejs_text_editor diff --git a/bt5/erp5_officejs/bt/template_path_list b/bt5/erp5_officejs/bt/template_path_list index cd9a8ebdcfa..95a92147f01 100644 --- a/bt5/erp5_officejs/bt/template_path_list +++ b/bt5/erp5_officejs/bt/template_path_list @@ -7,6 +7,8 @@ image_module/officejs_todomvc_* image_module/wallsearch_icon_svg web_page_module/dhtmlx_gantt_* web_page_module/fb_sdk_js +web_page_module/gadget_erp5_ojs_* +web_page_module/gadget_erp5_page_ojs_* web_page_module/gadget_field_* web_page_module/gadget_officejs_* web_page_module/jio_* @@ -33,6 +35,8 @@ web_site_module/officejs_notebook web_site_module/officejs_notebook/** web_site_module/officejs_pdf_viewer web_site_module/officejs_pdf_viewer/** +web_site_module/officejs_schema +web_site_module/officejs_schema/** web_site_module/officejs_smart_assistant web_site_module/officejs_smart_assistant/** web_site_module/officejs_svg_editor -- 2.30.9 From dec0dccefe63a8b3d7a8820642f2da94dfa85a89 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Sat, 16 Jun 2018 16:58:18 +0300 Subject: [PATCH 05/49] erp5_officejs: add `reference` in scheme editing form --- .../gadget_officejs_jio_json_schema_view.js.js | 13 ++++++++++++- .../gadget_officejs_jio_multi_upload_js.js | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js index 1e02747457c..6c96d6b520b 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js @@ -106,6 +106,17 @@ "hidden": 0, "type": "StringField" }, + "my_reference": { + "description": "", + "title": "Reference", + "default": gadget.state.doc.reference, + "css_class": "", + "required": 1, + "editable": 1, + "key": "reference", + "hidden": 0, + "type": "StringField" + }, "my_file": { "description": "", "title": "Upload and rewrite this document", @@ -142,7 +153,7 @@ form_definition: { group_list: [[ "left", - [["my_title"], ["my_file"]] + [["my_title"], ["my_reference"], ["my_file"]] ], [ "bottom", [["my_content"]] diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_multi_upload_js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_multi_upload_js.js index 4bcf4b3a66b..c9f8206a805 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_multi_upload_js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_multi_upload_js.js @@ -46,6 +46,9 @@ }; post_variables.title = data.file_name || post_variables.title; + if (data.file_name) { + post_variables.reference = data.file_name; + } return gadget.jio_post(post_variables) .push(function (id) { return gadget.jio_putAttachment(id, 'data', blob); -- 2.30.9 From be0c98c3a6fd4a0a6fabd9ea0edc54790677d414 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Sat, 16 Jun 2018 17:35:01 +0300 Subject: [PATCH 06/49] erp5_officejs: schema editor: make dynamic panel --- .../gadget_erp5_ojs_schema_panel.html.html | 9 +-- .../gadget_erp5_ojs_schema_panel.js.js | 68 +++++++++++++++++-- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html index 1ef70611acd..4f5284bb55a 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html @@ -41,10 +41,11 @@ + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.html.xml new file mode 100644 index 00000000000..37ccd668aa3 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.html.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_erp5_page_ojs_add_json_document.html + + + description + + + + + + id + gadget_erp5_page_ojs_add_json_document.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1529312559.88 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.19604.62909.57139 + + + state + current + + + time + + + + + + + + + + + 1529311989.6 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1529311949.17 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js new file mode 100644 index 00000000000..655ba101580 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js @@ -0,0 +1,62 @@ +/*global window, rJS, RSVP */ +/*jslint nomen: true, indent: 2, maxerr: 3 */ +(function (window, rJS, RSVP, Blob) { + "use strict"; + + var content_type = { + Spreadsheet: 'application/x-asc-spreadsheet', + Presentation: 'application/x-asc-presentation', + Text: 'application/x-asc-text' + }; + + var file_ext = { + Spreadsheet: 'xlsy', + Presentation: 'ppty', + Text: 'docy' + }; + + rJS(window) + ///////////////////////////////////////////////////////////////// + // Acquired methods + ///////////////////////////////////////////////////////////////// + .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("getSetting", "getSetting") + .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") + .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("jio_post", "jio_post") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + .declareMethod("render", function (options) { + var gadget = this; + return RSVP.Queue() + .push(function () { + var portal_type = options.portal_type, + ext = file_ext[portal_type], + ret = { + title: "Untitled Document", + portal_type: "JSON Document", + schema: options.schema, + parent_relative_url: "document_module", + content_type: content_type[portal_type] || undefined + }; + if (ext) { + ret.filename = "default." + ext; + } + return gadget.jio_post(ret); + }) + .push(function (id) { + return gadget.jio_putAttachment(id, 'data', new Blob(["{}"])) + .push(function () { + return gadget.redirect({ + command: 'display', + options: { + jio_key: id, + editable: true + } + }); + }); + }); + }); +}(window, rJS, RSVP, Blob)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.xml new file mode 100644 index 00000000000..2bd7c36571c --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_erp5_page_ojs_add_json_document.js + + + description + + + + + + id + gadget_erp5_page_ojs_add_json_document.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1529312550.04 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.19606.36848.59733 + + + state + current + + + time + + + + + + + + + + + 1529312523.59 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1529312001.47 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js index 19c7abae562..95595b5d27b 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js @@ -65,14 +65,14 @@ }); }) - .declareMethod("render", function () { + .declareMethod("render", function (options) { var gadget = this; - return new RSVP.Queue() .push(function () { + var portal_type = options.portal_type || gadget.getSetting("portal_type"); return RSVP.all([ gadget.getDeclaredGadget('form_list'), - gadget.getSetting("portal_type") + portal_type ]); }) .push(function (result) { @@ -83,7 +83,12 @@ ['description', 'Description'], ['version', 'Version'], ['modification_date', 'Modification Date'] - ]; + ], + query = 'portal_type:"' + result[1] + '"'; + if (options.schema) { + query += ' AND schema:"' + options.schema + '"'; + } + query = encodeURIComponent(query); return result[0].render({ erp5_document: { "_embedded": {"_view": { @@ -96,13 +101,12 @@ "key": "field_listbox", "lines": 30, "list_method": "portal_catalog", - "query": "urn:jio:allDocs?query=portal_type%3A%22" + - result[1] + "%22", + "query": "urn:jio:allDocs?query=" + query, "portal_type": [], "search_column_list": column_list, "sort_column_list": column_list, "sort": [['modification_date', 'descending']], - "title": "Schemas", + "title": options.schema_title || "Schemas", "type": "ListBox" } }}, @@ -122,17 +126,29 @@ }); }) .push(function () { - return RSVP.all([ - gadget.getUrlFor({command: "index", options: {"page": "ojs_multi_upload"}}), - gadget.getSetting('document_title_plural') - ]); + var tasks; + if (options.portal_type === "JSON Document") { + tasks = [ + gadget.getUrlFor({command: "index", options: { + page: "ojs_add_json_document", + schema: options.schema + }}), + gadget.getSetting('document_title_plural') + ]; + } else { + tasks = [ + gadget.getUrlFor({command: "index", options: {"page": "ojs_multi_upload"}}), + gadget.getSetting('document_title_plural') + ]; + } + return RSVP.all(tasks); }) .push(function (result) { return gadget.updateHeader({ - page_title: result[1], + page_title: options.schema_title || result[1], filter_action: true, add_url: result[0] }); }); }); -}(window, rJS, RSVP)); +}(window, rJS, RSVP)); \ No newline at end of file diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.html.html new file mode 100644 index 00000000000..c10b856a6aa --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.html.html @@ -0,0 +1,26 @@ + + + + + + + OfficeJS Jio Document View + + + + + + + + + +
+ +
+
+
+ + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.html.xml new file mode 100644 index 00000000000..dc5b73ec5f7 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.html.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_officejs_jio_json_document_view.html + + + description + + + + + + id + gadget_officejs_jio_json_document_view.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1529312245.83 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.19572.63845.39133 + + + state + current + + + time + + + + + + + + + + + 1529310065.14 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1529309725.59 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js new file mode 100644 index 00000000000..ba0206d2b25 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js @@ -0,0 +1,202 @@ +/*global window, rJS, RSVP, jIO, URL, + promiseEventListener, document*/ +/*jslint nomen: true, indent: 2, maxerr: 3 */ +(function (window, jIO, rJS, RSVP) { + "use strict"; + + rJS(window) + ///////////////////////////////////////////////////////////////// + // Acquired methods + ///////////////////////////////////////////////////////////////// + .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("getUrlParameter", "getUrlParameter") + .declareAcquiredMethod("getUrlFor", "getUrlFor") + .declareAcquiredMethod("updateDocument", "updateDocument") + .declareAcquiredMethod("notifySubmitting", "notifySubmitting") + .declareAcquiredMethod("notifySubmitted", 'notifySubmitted') + .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("jio_get", "jio_get") + .declareAcquiredMethod("jio_put", "jio_put") + .declareAcquiredMethod("jio_allDocs", "jio_allDocs") + .declareAcquiredMethod("jio_getAttachment", "jio_getAttachment") + .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + .declareMethod("render", function (options) { + var gadget = this; + return gadget.changeState({ + jio_key: options.jio_key, + doc: options.doc + }); + }) + + .onEvent('submit', function () { + var gadget = this; + return gadget.notifySubmitting() + .push(function () { + return gadget.getDeclaredGadget('form_view'); + }) + .push(function (form_gadget) { + return form_gadget.getContent(); + }) + .push(function (content) { + var list = [], + blob; + if (content.file) { + blob = jIO.util.dataURItoBlob(content.file.url); + content.title = content.file.file_name; + delete content.file; + list = [ + gadget.updateDocument(content), + gadget.jio_putAttachment(gadget.state.jio_key, 'data', blob) + ]; + } else if (content.data) { + blob = new Blob([content.data]); + delete content.data; + list = [ + gadget.updateDocument(content), + gadget.jio_putAttachment(gadget.state.jio_key, 'data', blob) + ]; + } else { + list = [gadget.updateDocument(content)]; + } + return RSVP.all(list); + }) + .push(function () { + return gadget.notifySubmitted({message: 'Data Updated', status: 'success'}); + }, function (error) { + if (error.target && error.target.error.name === 'NotReadableError') { + return gadget.notifySubmitted({message: error.target.error.message, status: 'fail'}); + } + throw error; + }).push(function () { + // debugger; + return gadget.redirect({ + command: 'reload' + }); + }); + }) + + .declareMethod("triggerSubmit", function () { + return this.element.querySelector('button[type="submit"]').click(); + }) + + .allowPublicAcquisition("downloadJSON", function (arr) { + var g = this, + url = arr[0], + reference, + args; + // return g.jio_getAttachment(id, "data", {format: "json"}); + if (url.startsWith("urn:jio:reference?")) { + reference = decodeURIComponent(url.replace("urn:jio:reference?", "")); + args = { + query: '(portal_type: "Json Schema") AND ((reference: "' + reference + '"))', + limit: [0, 1], + select_list: [], + sort_on: [["modification_date", "descending"]] + }; + return g.jio_allDocs(args) + .push(function (result) { + return g.jio_getAttachment(result.data.rows[0].id, "data", {format: "json"}); + }); + } + }) + + .onStateChange(function () { + var gadget = this, + schema_obj; + return RSVP.Queue() + .push(function () { + return RSVP.all([ + gadget.getDeclaredGadget('form_view'), + gadget.jio_getAttachment(gadget.state.jio_key, 'data', {format: "json"}), + gadget.jio_get(gadget.state.doc.schema) + ]); + }) + .push(function (result) { + schema_obj = result[2]; + return result[0].render({ + erp5_document: { + "_embedded": { + "_view": { + "my_title": { + "description": "", + "title": "Title", + "default": gadget.state.doc.title, + "css_class": "", + "required": 1, + "editable": 1, + "key": "title", + "hidden": 0, + "type": "StringField" + }, + "my_file": { + "description": "", + "title": "Upload", + "default": "", + "css_class": "", + "required": 0, + "editable": 1, + "key": "file", + "hidden": 0, + "accept": "application/json", + "type": "FileField" + }, + "my_content": { + "default": result[1], + "css_class": "", + "required": 0, + "editable": 1, + "key": "data", + "hidden": 0, + "type": "GadgetField", + "renderjs_extra": '{"name": "data",' + + ' "schema_url": "urn:jio:reference?' + schema_obj.reference + '"}', + "url": "jsonform.gadget.html", + "sandbox": "public" + } + } + }, + "_links": { + "type": { + // form_list display portal_type in header + name: "" + } + } + }, + form_definition: { + group_list: [[ + "left", + [["my_title"], ["my_reference"], ["my_file"]] + ], [ + "bottom", + [["my_content"]] + ]] + } + }); + }) + .push(function () { + return RSVP.all([ + gadget.getUrlFor({command: 'display', options: { + page: "ojs_schema_document_list", + portal_type: "JSON Document", + schema: gadget.state.doc.schema, + schema_title: schema_obj.title + }}), + gadget.getUrlFor({command: 'selection_previous'}), + gadget.getUrlFor({command: 'selection_next'}) + ]); + }) + .push(function (url_list) { + return gadget.updateHeader({ + page_title: gadget.state.doc.title, + save_action: true, + selection_url: url_list[0], + previous_url: url_list[1], + next_url: url_list[2] + }); + }); + }); +}(window, jIO, rJS, RSVP)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.xml new file mode 100644 index 00000000000..7defc5d4ad9 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_officejs_jio_json_document_view.js + + + description + + + + + + id + gadget_officejs_jio_json_document_view.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1529312206.16 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.19585.54009.7782 + + + state + current + + + time + + + + + + + + + + + 1529310839.13 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1529310542.24 + UTC + + + + + + + + + + + -- 2.30.9 From d64711d5e4e6722e57b4be208965c550d981e3bf Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 18 Jun 2018 14:34:56 +0000 Subject: [PATCH 08/49] erp5_json_form: 'urn:jio:reference?' url schema supported --- .../erp5_json_form/jsonform.gadget.js.js | 82 +++++++++++++++---- .../erp5_json_form/jsonform.gadget.js.xml | 2 +- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index 2701dfdb0a4..80b18e2ec57 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -5,6 +5,36 @@ "use strict"; var expandSchema; + function URLwithJio(url, base_url) { + var urn_prefix, + pathname, + fake_prefix = "https://jio_urn_prefix/"; + // XXX urn: can any case + if (url.startsWith("urn:jio:reference?")) { + urn_prefix = url.indexOf("?") + 1; + urn_prefix = url.slice(0, urn_prefix); + url = fake_prefix + decodeURIComponent(url.replace(urn_prefix, "")); + } + if (typeof base_url === "string" && base_url.startsWith("urn:jio:reference?")) { + if (!urn_prefix) { + urn_prefix = base_url.indexOf("?") + 1; + urn_prefix = base_url.slice(0, urn_prefix); + } + base_url = fake_prefix + decodeURIComponent(base_url.replace(urn_prefix, "")); + } + url = new URL(url, base_url); + if (urn_prefix) { + pathname = url.pathname.slice(1); + return { + href: urn_prefix + encodeURIComponent(pathname + url.search + url.hash), + origin: urn_prefix, + pathname: encodeURIComponent(pathname), + hash: url.hash + }; + } + return url; + } + function decodeJsonPointer(_str) { // https://tools.ietf.org/html/rfc6901#section-5 return _str.replace(/~1/g, '/').replace(/~0/g, '~'); @@ -87,9 +117,9 @@ base_url = convertToRealWorldSchemaPath(g, path), absolute_url; if (base_url === "" || base_url.indexOf("#") === 0) { - absolute_url = new URL(url, base_url_failback); + absolute_url = URLwithJio(url, base_url_failback); } else { - absolute_url = new URL(url, base_url); + absolute_url = URLwithJio(url, base_url); } return absolute_url; } @@ -154,7 +184,8 @@ url, download_url, hash, - schema_url_map; + schema_url_map, + queue; // XXX need use `id` property if (!path) { path = "/"; @@ -179,7 +210,18 @@ } hash = url.hash; url = url.href; - return downloadJSON(download_url) + if (download_url.startsWith("urn:jio:")) { + queue = RSVP.Queue() + .push(function () { + return g.downloadJSON(download_url); + }); + } else { + queue = RSVP.Queue() + .push(function () { + return downloadJSON(download_url); + }); + } + return queue .push(function (json) { checkCircular(g, path, url); return resolveLocalReference(json, hash); @@ -192,9 +234,9 @@ schema_a = document.createElement("a"), pointed_a = document.createElement("a"); schema_a.setAttribute("href", download_url); - schema_a.text = (new URL(download_url)).pathname; + schema_a.text = (URLwithJio(download_url)).pathname; pointed_a.setAttribute("href", url_from_pointed); - pointed_a.text = (new URL(url_from_pointed)).pathname; + pointed_a.text = (URLwithJio(url_from_pointed)).pathname; g.props.schema_resolve_errors[url_from_pointed] = { schemaPath: path, message: [ @@ -373,6 +415,7 @@ g.props = {}; g.options = {}; }) + .declareAcquiredMethod("downloadJSON", "downloadJSON") .declareAcquiredMethod("notifyChange", "notifyChange") .allowPublicAcquisition("notifyChange", function () { return this.notifyChange(); @@ -500,14 +543,19 @@ .declareMethod('render', function (options) { return this.changeState({ key: options.key, - value: options.value || "", - schema: options.schema, + value: JSON.stringify(options.value) || '""', + schema: JSON.stringify(options.schema), schema_url: options.schema_url, editable: options.editable === undefined ? true : options.editable }); }) - .onStateChange(function (options) { - var g = this; + .onStateChange(function () { + var g = this, + json_document = JSON.parse(g.state.value), + schema; + if (g.state.schema !== undefined) { + schema = JSON.parse(g.state.schema); + } g.props.toplevel = true; // contain map of current normalized schema // json pointer and corresponding url @@ -537,11 +585,11 @@ } }) .push(function () { - if (options.schema) { - return options.schema; + if (schema) { + return schema; } - var schema_url = options.schema_url || - (options.value && options.value.$schema); + var schema_url = g.state.schema_url || + (json_document && json_document.$schema); if (schema_url) { return loadJSONSchema(g, schema_url) .push(function (schema_arr) { @@ -551,11 +599,10 @@ return {}; }) .push(function (schema) { - g.options.schema = schema; return g.props.form_gadget.renderForm({ schema: schema, schema_path: "", - document: options.value, + document: json_document, required: true, top: true }); @@ -603,7 +650,8 @@ // This will prevent the gadget to be changed if // its parent call render with the same value // (as ERP5 does in case of formulator error) - g.state.value = value; + g.state.value = JSON.stringify(value); + console.log(g.state.value); if (g.state.key) { var form_data = {}; value = JSON.stringify(value); diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml index 15b61f4d1bd..e74857f8664 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.xml @@ -20,7 +20,7 @@ title - schema.gadget.js + jsonform.gadget.js -- 2.30.9 From 17374838a9d313c1325808d0961896b2bdfd9371 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Tue, 19 Jun 2018 17:56:29 +0300 Subject: [PATCH 09/49] erp5_officejs: rename 'Json Schema' to JSON Schema --- .../web_page_module/gadget_erp5_ojs_schema_panel.js.js | 2 +- .../web_page_module/gadget_erp5_ojs_schema_router.html.html | 2 +- .../gadget_officejs_jio_json_document_view.js.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js index a0b54a209f5..fef18c1743f 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js @@ -148,7 +148,7 @@ // Update the global links .push(function () { return context.jio_allDocs({ - "query": 'portal_type:"Json Schema"', + "query": 'portal_type:"JSON Schema"', "limit": [0, 31], "select_list": ["title", "reference"], "sort_on": [["title", "descending"]] diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html index 1f9627c81b7..e9e8820e064 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_router.html.html @@ -14,7 +14,7 @@ - + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js index ba0206d2b25..b670b5c86b4 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js @@ -92,7 +92,7 @@ if (url.startsWith("urn:jio:reference?")) { reference = decodeURIComponent(url.replace("urn:jio:reference?", "")); args = { - query: '(portal_type: "Json Schema") AND ((reference: "' + reference + '"))', + query: '(portal_type: "JSON Schema") AND ((reference: "' + reference + '"))', limit: [0, 1], select_list: [], sort_on: [["modification_date", "descending"]] -- 2.30.9 From 70988b11a8dbb4bd3e3ad0d84acea3d80898909c Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Tue, 19 Jun 2018 17:57:39 +0300 Subject: [PATCH 10/49] erp5_officejs: schema_editor: fix title --- .../gadget_officejs_jio_json_document_view.js.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js index b670b5c86b4..0881c10b8c0 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js @@ -134,7 +134,7 @@ }, "my_file": { "description": "", - "title": "Upload", + "title": "Upload and rewrite this document", "default": "", "css_class": "", "required": 0, -- 2.30.9 From f358497c0e510135f064d27e7de8ef7d3c7aee3c Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 20 Jun 2018 08:38:17 +0000 Subject: [PATCH 11/49] erp5_json_form: fix download http* $ref links --- .../portal_skins/erp5_json_form/jsonform.gadget.js.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index 80b18e2ec57..9aeb3929e0b 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -15,7 +15,9 @@ urn_prefix = url.slice(0, urn_prefix); url = fake_prefix + decodeURIComponent(url.replace(urn_prefix, "")); } - if (typeof base_url === "string" && base_url.startsWith("urn:jio:reference?")) { + if (typeof base_url === "string" && + !(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//")) && + base_url.startsWith("urn:jio:reference?")) { if (!urn_prefix) { urn_prefix = base_url.indexOf("?") + 1; urn_prefix = base_url.slice(0, urn_prefix); @@ -200,14 +202,15 @@ }; if (schema_url_map.hasOwnProperty(download_url)) { url = new URL(schema_url_map[download_url], g.__path); - download_url = url.origin + url.pathname; } protocol = url.protocol; if (protocol === "http:" || protocol === "https:") { if (window.location.protocol !== protocol) { - throw new Error("You cannot mixed http and https calls"); + url = new URL($ref.replace(protocol + "//", window.location.protocol + "//")); + // throw new Error("You cannot mixed http and https calls"); } } + download_url = url.origin + url.pathname; hash = url.hash; url = url.href; if (download_url.startsWith("urn:jio:")) { -- 2.30.9 From 3559b1c75b83528b3f257f72441454a4aaa4e586 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 20 Jun 2018 14:14:13 +0300 Subject: [PATCH 12/49] erp5_officejs: schema_editor: add gadget_erp5_page_ojs_add_json_schema.* --- ...et_erp5_page_ojs_add_json_schema.html.html | 18 + ...get_erp5_page_ojs_add_json_schema.html.xml | 319 ++++++++++++++++++ ...gadget_erp5_page_ojs_add_json_schema.js.js | 62 ++++ ...adget_erp5_page_ojs_add_json_schema.js.xml | 319 ++++++++++++++++++ ...t_erp5_page_ojs_schema_document_list.js.js | 4 +- 5 files changed, 721 insertions(+), 1 deletion(-) create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.html create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.xml create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js create mode 100644 bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.xml diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.html new file mode 100644 index 00000000000..83f6adab2f4 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.html @@ -0,0 +1,18 @@ + + + + + + + + OfficeJS Add JSON Schema + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.xml new file mode 100644 index 00000000000..620331a1602 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.html.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_erp5_page_ojs_add_json_schema.html + + + description + + + + + + id + gadget_erp5_page_ojs_add_json_schema.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1529423472.58 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.21463.13805.56115 + + + state + current + + + time + + + + + + + + + + + 1529423544.97 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1529422971.29 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js new file mode 100644 index 00000000000..c1d91854298 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js @@ -0,0 +1,62 @@ +/*global window, rJS, RSVP */ +/*jslint nomen: true, indent: 2, maxerr: 3 */ +(function (window, rJS, RSVP, Blob) { + "use strict"; + + var content_type = { + Spreadsheet: 'application/x-asc-spreadsheet', + Presentation: 'application/x-asc-presentation', + Text: 'application/x-asc-text' + }; + + var file_ext = { + Spreadsheet: 'xlsy', + Presentation: 'ppty', + Text: 'docy' + }; + + rJS(window) + ///////////////////////////////////////////////////////////////// + // Acquired methods + ///////////////////////////////////////////////////////////////// + .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("getSetting", "getSetting") + .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") + .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("jio_post", "jio_post") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + .declareMethod("render", function (options) { + var gadget = this; + return RSVP.Queue() + .push(function () { + var portal_type = options.portal_type, + ext = file_ext[portal_type], + ret = { + title: "Untitled Document", + portal_type: "JSON Schema", + parent_relative_url: "schema_module", + content_type: content_type[portal_type] || undefined + }; + if (ext) { + ret.filename = "default." + ext; + } + return gadget.jio_post(ret); + }) + .push(function (id) { + return gadget.jio_putAttachment(id, 'data', + new Blob(['{"$schema": "http://json-schema.org/draft-04/schema#" }'])) + .push(function () { + return gadget.redirect({ + command: 'display', + options: { + jio_key: id, + editable: true + } + }); + }); + }); + }); +}(window, rJS, RSVP, Blob)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.xml new file mode 100644 index 00000000000..e3d3f901f1e --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_erp5_page_ojs_add_json_schema.js + + + description + + + + + + id + gadget_erp5_page_ojs_add_json_schema.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1529422852.29 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.21427.35485.43758 + + + state + current + + + time + + + + + + + + + + + 1529422814.82 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1529421291.26 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js index 95595b5d27b..4b3dbcfb6e7 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_schema_document_list.js.js @@ -137,7 +137,9 @@ ]; } else { tasks = [ - gadget.getUrlFor({command: "index", options: {"page": "ojs_multi_upload"}}), + gadget.getUrlFor({command: "index", options: { + page: "ojs_add_json_schema" + }}), gadget.getSetting('document_title_plural') ]; } -- 2.30.9 From 764720efc7d4f25f6172e4bb99eddb0830c592e4 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 20 Jun 2018 18:36:33 +0300 Subject: [PATCH 13/49] erp5_web_renderjs_ui: html5_select: event option for notifyChange added. needs for determine event.type on parent gadget --- .../web_page_module/rjs_gadget_html5_select_js.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_html5_select_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_html5_select_js.js index def1b3120e5..76f2718b0fd 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_html5_select_js.js +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_html5_select_js.js @@ -136,16 +136,16 @@ }) .declareAcquiredMethod("notifyChange", "notifyChange") - .onEvent('change', function change() { + .onEvent('change', function change(e) { return RSVP.all([ this.checkValidity(), - this.notifyChange() + this.notifyChange(e) ]); }, false, false) - .onEvent('input', function input() { + .onEvent('input', function input(e) { return RSVP.all([ this.checkValidity(), - this.notifyChange() + this.notifyChange(e) ]); }, false, false) -- 2.30.9 From 7b537266c151121786fb1357843c9438d2737a45 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 25 Jun 2018 11:29:09 +0000 Subject: [PATCH 14/49] erp5_json_form: add filter property in `schema_mode` for property selector --- .../gadget_json_generated_form_child.js.js | 153 ++++++++++++++++-- 1 file changed, 143 insertions(+), 10 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 2b7aa497730..2033673ba60 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -834,10 +834,118 @@ }); } + function checkSchemaIsMetaSchema(schema) { + if (schema instanceof Array) { + var i, + sch; + for (i = 0; i < schema.length; i += 1) { + sch = schema[i].schema; + if (sch.hasOwnProperty("properties") && + sch.properties.hasOwnProperty("$schema")) { + return true; + } + } + return false; + } + return schema.hasOwnProperty("properties") && + schema.properties.hasOwnProperty("$schema"); + } + + function checkSchemaType(type, check) { + if (type instanceof Array) { + return type.indexOf(check) >= 0; + } + return type === check; + } + + // filter property for schema editor mode + function filterPropery(property_name, current_document) { + if (current_document.hasOwnProperty("type")) { + switch (property_name) { + case "allOf": + case "anyOf": + case "oneOf": + return false; + case "additionalItems": + case "items": + case "maxItems": + case "minItems": + case "uniqueItems": + if (!checkSchemaType(current_document.type, "array")) { + return false; + } + break; + case "required": + case "maxProperties": + case "minProperties": + case "additionalProperties": + case "properties": + case "patternProperties": + case "propertyNames": + if (!checkSchemaType(current_document.type, "object")) { + return false; + } + break; + case "maxLength": + case "minLength": + case "pattern": + if (!checkSchemaType(current_document.type, "string")) { + return false; + } + break; + case "multipleOf": + case "maximum": + case "exclusiveMaximum": + case "minimum": + case "exclusiveMinimum": + if (!(checkSchemaType(current_document.type, "number") || + checkSchemaType(current_document.type, "integer"))) { + return false; + } + break; + } + } else { + if (current_document.hasOwnProperty("allOf") || + current_document.hasOwnProperty("anyOf") || + current_document.hasOwnProperty("oneOf")) { + switch (property_name) { + case "type": + case "allOf": + case "anyOf": + case "oneOf": + return false; + } + } + switch (property_name) { + case "additionalItems": + case "items": + case "maxItems": + case "minItems": + case "uniqueItems": + case "required": + case "maxProperties": + case "minProperties": + case "additionalProperties": + case "properties": + case "patternProperties": + case "propertyNames": + case "maxLength": + case "minLength": + case "pattern": + case "multipleOf": + case "maximum": + case "exclusiveMaximum": + case "minimum": + case "exclusiveMinimum": + return false; + } + } + return true; + } + render_object = function (g, json_field, default_dict, root, path, schema_path) { var required = json_field.required || [], - schema_editor = json_field.hasOwnProperty("properties") && - json_field.properties.hasOwnProperty("$schema"), + schema_editor = checkSchemaIsMetaSchema(json_field), used_properties = {}, properties, selector = {}; @@ -930,11 +1038,14 @@ function (gadget_s, schema_alternatives) { var x, item_list = [["add property", "add property"]], - item; + item, + current_document = g.props.current_document; if (schema_alternatives) { for (x = 0; x < schema_alternatives.length; x += 1) { item = schema_alternatives[x]; - if (!used_properties.hasOwnProperty(item.value.property_name)) { + if (!used_properties.hasOwnProperty(item.value.property_name) && + !(schema_editor && current_document && + !filterPropery(item.value.property_name, current_document))) { item_list.push([item.title, x]); } } @@ -1369,6 +1480,10 @@ while (root.firstChild) { root.removeChild(root.firstChild); } + if (checkSchemaIsMetaSchema(schema)) { + g.props.updatePropertySelectors = true; + g.props.current_document = options.document; + } return render_field(g, property_name, "", schema, options.document, root, options.schema_path, { @@ -1378,7 +1493,6 @@ top: options.top }) .push(function () { - g.listenEvents(); return g.element; }); }) @@ -1411,20 +1525,39 @@ var field_list = this.props.inputs, i; + // on form data field for (i = 0; i < field_list.length; i = i + 1) { if (evt.target === field_list[i]) { return checkValidityAndNotifyChange(this); } } }) - .declareJob('listenEvents', function () { - // XXX Disable - return; - }) .declareMethod('getContent', function () { var g = this; - return getFormValuesAsJSONDict(g); + return getFormValuesAsJSONDict(g) + .push(function (data) { + if (g.props.updatePropertySelectors) { + g.props.current_document = data; + var key, + tasks = []; + for (key in g.props.add_custom_data) { + if (g.props.add_custom_data.hasOwnProperty(key)) { + tasks.push(g.props.add_custom_data[key].rerender()); + } + } + if (tasks.length > 0) { + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }) + .push(function () { + return data; + }); + } + } + return data; + }); }); }(window, document, location, rJS, RSVP, jIO, tv4)); \ No newline at end of file -- 2.30.9 From b36561230f9ddbddaab24b49a8d58a0ccbf92a94 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Tue, 26 Jun 2018 12:43:22 +0300 Subject: [PATCH 15/49] erp5_officejs: erp5_web_renderjs_ui: schema_editor: autoupdate gadget panel on schema added --- .../gadget_erp5_page_ojs_add_json_schema.js.js | 4 ++++ .../web_page_module/rjs_gadget_erp5_launcher_js.js | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js index c1d91854298..5d4769276ec 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js @@ -20,6 +20,7 @@ // Acquired methods ///////////////////////////////////////////////////////////////// .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("updatePanel", "updatePanel") .declareAcquiredMethod("getSetting", "getSetting") .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") .declareAcquiredMethod("redirect", "redirect") @@ -48,6 +49,9 @@ .push(function (id) { return gadget.jio_putAttachment(id, 'data', new Blob(['{"$schema": "http://json-schema.org/draft-04/schema#" }'])) + .push(function () { + return gadget.updatePanel({editable: true}); + }) .push(function () { return gadget.redirect({ command: 'display', diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js index 04a77484b11..8214deb7999 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js @@ -472,10 +472,11 @@ }); }) - .allowPublicAcquisition("updatePanel", function updatePanel(param_list) { + .allowPublicAcquisition("updatePanel", function (param_list) { var gadget = this; initPanelOptions(gadget); gadget.props.panel_argument_list = param_list[0]; + return updatePanel(gadget); }) .allowPublicAcquisition('hidePanel', function hidePanel(param_list) { -- 2.30.9 From edc9ab4264cedb4b18ed0dd4df06741b175dd0dd Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Tue, 26 Jun 2018 10:13:07 +0000 Subject: [PATCH 16/49] erp5_officejs: schema_editor: change title new created schema --- .../web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js index 5d4769276ec..109c564ca6f 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js @@ -36,7 +36,7 @@ var portal_type = options.portal_type, ext = file_ext[portal_type], ret = { - title: "Untitled Document", + title: "Untitled Schema", portal_type: "JSON Schema", parent_relative_url: "schema_module", content_type: content_type[portal_type] || undefined -- 2.30.9 From 1f0c33c18ad0a5f2f2476771969cd4bf37e3f56b Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 29 Jun 2018 11:47:30 +0300 Subject: [PATCH 17/49] erp5_officejs: schema_editor fix panel rendering, add developer mode checkbox --- .../gadget_erp5_ojs_schema_panel.html.html | 9 +- .../gadget_erp5_ojs_schema_panel.js.js | 154 ++++++++++-------- 2 files changed, 90 insertions(+), 73 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html index 4f5284bb55a..230f70ac803 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html @@ -36,16 +36,15 @@
    +
    + + + + + + + + +
    +
    + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.html.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.html.xml new file mode 100644 index 00000000000..f80b2607827 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.html.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/html + + + default_reference + gadget_erp5_page_ojs_zip_upload.html + + + description + + + + + + id + gadget_erp5_page_ojs_zip_upload.html + + + language + + + + + + portal_type + Web Page + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1531858269.29 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.63483.10177.13550 + + + state + current + + + time + + + + + + + + + + + 1531858473.45 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1531848195.02 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js new file mode 100644 index 00000000000..76da5d1e7bf --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js @@ -0,0 +1,241 @@ +/*global window, rJS, RSVP, loopEventListener, + jIO, document */ +/*jslint nomen: true, indent: 2, maxerr: 3 */ +(function (window, rJS, jIO, RSVP) { + "use strict"; + + var content_type = { + Spreadsheet: 'application/x-asc-spreadsheet', + Presentation: 'application/x-asc-presentation', + Text: 'application/x-asc-text' + }; + + function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + function generateMetadata(id, filename, path, body) { + // it's core of upload of zip gadget + // in this function can be added support another formats + var ret; + if (endsWith(filename, ".json")) { + ret = { + id: id, + content_type: "application/json", + reference: path + }; + if (body) { + if (body.$schema && body.$schema !== "") { + ret.portal_type = "JSON Schema"; + ret.parent_relative_url = "schema_module"; + ret.title = body.title || ""; + } else { + // XXX need schema relation property + ret.portal_type = "JSON Document"; + ret.parent_relative_url = "document_module"; + ret.title = body.filename || ""; + } + } else { + ret.format = "json"; + } + // used for detect supported extension + return ret; + } + } + + rJS(window) + ///////////////////////////////////////////////////////////////// + // Acquired methods + ///////////////////////////////////////////////////////////////// + .declareAcquiredMethod("updateHeader", "updateHeader") + .declareAcquiredMethod("getUrlFor", "getUrlFor") + .declareAcquiredMethod("getSetting", "getSetting") + .declareAcquiredMethod("notifySubmitting", "notifySubmitting") + .declareAcquiredMethod("notifySubmitted", "notifySubmitted") + .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") + .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("jio_post", "jio_post") + .declareAcquiredMethod("jio_put", "jio_put") + .declareAcquiredMethod("jio_putAttachment", "jio_putAttachment") + + ///////////////////////////////////////////////////////////////// + // declared methods + ///////////////////////////////////////////////////////////////// + .declareMethod("render", function () { + var gadget = this; + return gadget.changeState({ + title: 'Untitled Document' + }); + }) + + .declareMethod('putIntoDB', function (id, file_name, path, blob) { + var gadget = this, + queue = RSVP.Queue(), + // first run generateMetadata for check file support + // and detect document format + file_supported = generateMetadata(id, file_name, path); + if (file_supported) { + if (file_supported.format === "json") { + queue + .push(function () { + return jIO.util.readBlobAsText(blob); + }) + .push(function (evt) { + return JSON.parse(evt.target.result); + }); + } else { + queue.push(function () { + return blob; + }); + } + queue + .push(function (data) { + return gadget.jio_post(generateMetadata(id, file_name, path, data)) + .push(function (added_id) { + return gadget.jio_putAttachment(added_id, 'data', blob); + }); + }); + } + return queue; + }) + + .declareMethod('triggerSubmit', function () { + var gadget = this; + return gadget.notifySubmitting() + .push(function () { + return gadget.getDeclaredGadget('form_view'); + }) + .push(function (form_gadget) { + return form_gadget.getContent(); + }) + .push(function (content) { + return new RSVP.Queue() + .push(function () { + return RSVP.all([ + gadget.getSetting('jio_storage_name'), + gadget.getSetting('jio_storage_description') + ]); + }) + .push(function (result) { + var promiseArray = [], + data_array = content.data, + i, + blob, + storage_name = result[0], + storage_description = result[1], + storage, + local_database, + configuration; + + // XXX support other type of storage + if (storage_name === "LOCAL") { + local_database = storage_description.sub_storage.sub_storage.database; + } + + for (i = 0; i < data_array.length; i += 1) { + blob = jIO.util.dataURItoBlob(data_array[i].url); + if (endsWith(data_array[i].file_name, ".zip")) { + configuration = { + type: "replicate", + conflict_handling: 2, + check_local_attachment_creation: false, + check_local_creation: false, + check_local_modification: false, + check_local_deletion: false, + check_remote_attachment_creation: true, + check_remote_creation: true, + check_remote_modification: true, + check_remote_deletion: true, + local_sub_storage: { + type: "indexeddb", + database: local_database + }, + signature_sub_storage: { + type: "query", + sub_storage: { + type: "memory" + } + }, + remote_sub_storage: { + type: "ziptodocuments", + generateMetadata: generateMetadata, + sub_storage: { + type: "zipfile", + file: blob + } + } + }; + storage = jIO.createJIO(configuration); + promiseArray.push(storage.repair()); + } else { + promiseArray.push(gadget.putIntoDB("", data_array[i].file_name, data_array[i].file_name, blob)); + } + } + return RSVP.all(promiseArray); + }); + }) + .push(function () { + return RSVP.all([ + gadget.notifySubmitted({message: 'Data Updated', status: 'success'}), + gadget.redirect({command: 'history_previous'}) + ]); + }); + }) + + .onStateChange(function () { + var gadget = this; + return RSVP.Queue() + .push(function () { + return RSVP.all([ + gadget.getDeclaredGadget('form_view'), + gadget.getSetting('upload_content_type') + ]); + }) + .push(function (result) { + return result[0].render({ + erp5_document: { + "_embedded": { + "_view": { + "my_file": { + "description": "", + "title": "Upload files and Zip archive containing files", + "default": "", + "css_class": "", + "required": 1, + "editable": 1, + "key": "data", + "hidden": 0, + "multiple": "true", + "accept": "application/zip," + result[1], + "type": "FileField" + } + } + }, + "_links": { + "type": { + // form_list display portal_type in header + name: "" + } + } + }, + form_definition: { + group_list: [[ + "left", + [["my_file"]] + ]] + } + }); + }) + .push(function () { + return gadget.getUrlFor({command: 'history_previous'}); + }) + .push(function (result) { + return gadget.updateHeader({ + page_title: 'Document(s)', + back_field: true, + selection_url: result, + save_action: true + }); + }); + }); +}(window, rJS, jIO, RSVP)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.xml new file mode 100644 index 00000000000..5b2150969b7 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + gadget_erp5_page_ojs_zip_upload.js + + + description + + + + + + id + gadget_erp5_page_ojs_zip_upload.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1531858278.36 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.63287.21360.10154 + + + state + current + + + time + + + + + + + + + + + 1531846571.54 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1531846497.56 + UTC + + + + + + + + + + + diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml index faeb38c60e3..3d83446bde2 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml @@ -126,6 +126,8 @@ URI.js\n dygraph.js\n handlebars.js\n jiodev.js\n +jio_ziptodocuments.js\n +zipfilestorage-with-jszip.js\n renderjs.js\n rsvp.js\n gadget_global.js\n @@ -150,8 +152,10 @@ gadget_ojs_jio.html\n gadget_ojs_jio.js\n gadget_erp5_page_ojs_controller.html\n gadget_erp5_page_ojs_controller.js\n -gadget_erp5_page_ojs_add_document.html\n -gadget_erp5_page_ojs_add_document.js\n +gadget_erp5_page_ojs_add_json_schema.html\n +gadget_erp5_page_ojs_add_json_schema.js\n +gadget_erp5_page_ojs_add_json_document.html\n +gadget_erp5_page_ojs_add_json_document.js\n gadget_erp5_page_ojs_configurator.html\n gadget_erp5_page_ojs_configurator.js\n gadget_erp5_page_ojs_dav_configurator.html\n @@ -217,6 +221,8 @@ gadget_officejs_jio_json_schema_view.html\n gadget_officejs_jio_json_schema_view.js\n gadget_erp5_page_ojs_multi_upload.html\n gadget_erp5_page_ojs_multi_upload.js\n +gadget_erp5_page_ojs_zip_upload.html\n +gadget_erp5_page_ojs_zip_upload.js\n gadget_erp5_page_ojs_schema_document_list.html\n gadget_erp5_page_ojs_schema_document_list.js\n \n @@ -380,7 +386,7 @@ NETWORK:\n serial - 968.9700.26907.3566 + 968.64276.14441.43929 state @@ -398,7 +404,7 @@ NETWORK:\n - 1528717715.13 + 1531905921.42 UTC diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_ziptodocuments.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_ziptodocuments.js.js new file mode 100644 index 00000000000..1ef04cccdc5 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_ziptodocuments.js.js @@ -0,0 +1,268 @@ +/*jslint nomen: true*/ +/*global jIO, RSVP*/ +(function (jIO, RSVP) { + "use strict"; + + function decodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~1/g, '/').replace(/~0/g, '~'); + } + + function encodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~/g, '~0').replace(/\//g, '~1'); + } + + /** + * The jIO ZipToDocumentsBridgeStorage extension + * + * convert set of files provided zip container as + * documents contains metadata for files + * with attachment 'body' as file content + * + * @class ZipToDocumentsBridgeStorage + * @constructor + */ + function ZipToDocumentsBridgeStorage(spec) { + this._sub_storage = jIO.createJIO(spec.sub_storage); + if (spec.generateMetadata) { + this._generateMetadata = spec.generateMetadata; + } else { + throw new jIO.util.jIOError("Need specify generateMetadata function", + 400); + /** + * used for generate metadata for files + * based on extension and file content. + * used for determine supported or not + * supported file by return undefined. + * + * @function generateMetadata + */ + // example generateMetadata function + // function generateMetadata(id, filename, path, body) { + // var ret; + // if (endsWith(filename, ".json")) { + // ret = { + // id: id, + // content_type: "application/json", + // reference: path + // }; + // if (body) { + // if (body.$schema && body.$schema !== "") { + // ret.portal_type = "JSON Schema"; + // ret.parent_relative_url = "schema_module"; + // ret.title = body.title; + // } else { + // // XXX need schema relation property + // ret.portal_type = "JSON Document"; + // ret.parent_relative_url = "document_module"; + // ret.title = body.filename; + // } + // } else { + // ret.format = "json"; + // } + // // used for detect supported extension + // return ret; + // } + // } + } + } + + + ZipToDocumentsBridgeStorage.prototype.get = function (id) { + var context = this, + path = "/" + decodeJsonPointer(id), + idx = path.lastIndexOf('/') + 1, + filename = path.substring(idx), + dirname = path.substring(0, idx), + file_supported; + path = path.substring(1); + file_supported = context._generateMetadata(id, filename, path); + if (!file_supported) { + return new RSVP.Queue() + .push(function () { + throw new jIO.util.jIOError("Cannot find document " + id, + 404); + }); + } + return context._sub_storage.getAttachment(dirname, filename, + {format: file_supported.format} + ) + .push(undefined, function (error) { + if ((error instanceof jIO.util.jIOError) && + (error.status_code === 404)) { + throw new jIO.util.jIOError("Cannot find document " + id, + 404); + + } + throw error; + }) + .push(function (attachment) { + return context._generateMetadata(id, filename, path, attachment); + }); + }; + + ZipToDocumentsBridgeStorage.prototype.allAttachments = function (id) { + var context = this, + path = "/" + decodeJsonPointer(id), + idx = path.lastIndexOf('/') + 1, + filename = path.substring(idx), + dirname = path.substring(0, idx); + return context._sub_storage.getAttachment(dirname, filename) + .push(function () { + return {"data": {}}; + }, function (error) { + if ((error instanceof jIO.util.jIOError) && + (error.status_code === 404)) { + throw new jIO.util.jIOError("Cannot find document " + id, + 404); + } + throw error; + }); + }; + + ZipToDocumentsBridgeStorage.prototype.put = function (doc_id) { + // we can not save file metadata(document in upper storage) + // in zip so do nothing + return RSVP.Queue() + .push(function () { + return doc_id; + }); + }; + + ZipToDocumentsBridgeStorage.prototype.remove = function (id) { + var context = this, + path = "/" + decodeJsonPointer(id), + idx = path.lastIndexOf('/') + 1, + filename = path.substring(idx), + dirname = path.substring(0, idx); + return context._sub_storage.removeAttachment(dirname, filename) + .push(undefined, function (error) { + if ((error instanceof jIO.util.jIOError) && + (error.status_code === 404)) { + throw new jIO.util.jIOError("Cannot find document " + id, + 404); + } + throw error; + }); + + }; + + ZipToDocumentsBridgeStorage.prototype.hasCapacity = function (capacity) { + return ((capacity === "list") || (capacity === "include")); + }; + + ZipToDocumentsBridgeStorage.prototype.buildQuery = function (options) { + var result_dict = {}, + context = this; + return context._sub_storage.allDocs() + .push(function (result) { + var i, + id, + tasks = []; + + function push_doc(k, filename, path) { + return function (json) { + result_dict[k].doc = context._generateMetadata(k, filename, path, json); + }; + } + + function f(dirname) { + return function (dir) { + var k, + path, + filename, + attachment_tasks = []; + + for (filename in dir) { + if (dir.hasOwnProperty(filename)) { + path = dirname.substring(1) + filename; + k = encodeJsonPointer(dirname.substring(1) + filename); + // check file with extension supported + if (context._generateMetadata(k, filename, path)) { + result_dict[k] = { + id: k, + value: {} + }; + if (options.include_docs) { + attachment_tasks.push( + context._sub_storage.getAttachment(id, filename) + .push(push_doc(k, filename, path)) + ); + } + } + } + } + if (attachment_tasks.length > 0) { + return RSVP.all(attachment_tasks); + } + }; + } + + for (i = 0; i < result.data.rows.length; i += 1) { + id = result.data.rows[i].id; + tasks.push(context._sub_storage.allAttachments(id) + .push(f(id))); + } + return RSVP.all(tasks); + }) + .push(function () { + var result = [], + key; + for (key in result_dict) { + if (result_dict.hasOwnProperty(key)) { + result.push(result_dict[key]); + } + } + return result; + }); + }; + + ZipToDocumentsBridgeStorage.prototype.getAttachment = function (id, + name, + options) { + if (name !== "data") { + throw new jIO.util.jIOError("Only support 'data' attachment", + 400); + } + var path = "/" + decodeJsonPointer(id), + idx = path.lastIndexOf('/') + 1, + filename = path.substring(idx), + dirname = path.substring(0, idx); + + return this._sub_storage.getAttachment(dirname, filename, options); + }; + + ZipToDocumentsBridgeStorage.prototype.putAttachment = function (id, + name, + blob) { + if (name !== "data") { + throw new jIO.util.jIOError("Only support 'data' attachment", + 400); + } + + var path = "/" + decodeJsonPointer(id), + idx = path.lastIndexOf('/') + 1, + filename = path.substring(idx), + dirname = path.substring(0, idx); + return this._sub_storage.putAttachment(dirname, filename, blob); + }; + + ZipToDocumentsBridgeStorage.prototype.removeAttachment = function (id, + name) { + if (name !== "data") { + throw new jIO.util.jIOError("Only support 'data' attachment" + + " in document:" + id, + 400); + } + // document(metadata) with attachment === attachment in zip + // so we can do nothing + }; + + ZipToDocumentsBridgeStorage.prototype.repair = function () { + return this._sub_storage.repair.apply(this._sub_storage, arguments); + }; + + jIO.addStorage('ziptodocuments', ZipToDocumentsBridgeStorage); + +}(jIO, RSVP)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_ziptodocuments.js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_ziptodocuments.js.xml new file mode 100644 index 00000000000..c560d6a23c1 --- /dev/null +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_ziptodocuments.js.xml @@ -0,0 +1,319 @@ + + + + + + + + + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + _Add_portal_content_Permission + + + Assignor + Manager + + + + + _Change_local_roles_Permission + + + Assignor + Manager + + + + + _Modify_portal_content_Permission + + + Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Manager + + + + + content_md5 + + + + + + content_type + text/javascript + + + default_reference + jio_ziptodocuments.js + + + description + + + + + + id + jio_ziptodocuments.js + + + language + + + + + + portal_type + Web Script + + + short_title + + + + + + version + + + + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + document_publication_workflow + + AAAAAAAAAAM= + + + + edit_workflow + + AAAAAAAAAAQ= + + + + processing_status_workflow + + AAAAAAAAAAU= + + + + + + + + + + + + + + + + + + + action + publish + + + actor + zope + + + comment + + + + error_message + + + + time + + + + + + + + + + + 1531857837.73 + UTC + + + + + + + validation_state + published + + + + + + + + + + + + + + + + + action + edit + + + actor + zope + + + comment + + + + + + error_message + + + + serial + 968.63397.4495.43707 + + + state + current + + + time + + + + + + + + + + + 1531857455.0 + UTC + + + + + + + + + + + + + + + + + + + + + action + detect_converted_file + + + actor + zope + + + comment + + + + error_message + + + + external_processing_state + converted + + + serial + 0.0.0.0 + + + time + + + + + + + + + + + 1531853065.16 + UTC + + + + + + + + + + + -- 2.30.9 From 21583f455e5c8fc0d2418ea7440499126ad6e7c6 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 20 Jul 2018 12:03:53 +0300 Subject: [PATCH 25/49] erp5_officejs: schema editor: fix appcache --- .../web_page_module/gadget_officejs_schema.appcache.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml index 3d83446bde2..2bc2311dfdb 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_schema.appcache.xml @@ -219,6 +219,8 @@ gadget_erp5_ojs_schema_panel.html\n gadget_erp5_ojs_schema_panel.js\n gadget_officejs_jio_json_schema_view.html\n gadget_officejs_jio_json_schema_view.js\n +gadget_officejs_jio_json_document_view.html\n +gadget_officejs_jio_json_document_view.js\n gadget_erp5_page_ojs_multi_upload.html\n gadget_erp5_page_ojs_multi_upload.js\n gadget_erp5_page_ojs_zip_upload.html\n @@ -386,7 +388,7 @@ NETWORK:\n serial - 968.64276.14441.43929 + 968.64277.23410.35857 state @@ -404,7 +406,7 @@ NETWORK:\n - 1531905921.42 + 1531936654.32 UTC -- 2.30.9 From 1c2f03a3228cf98445b89be26c667c39d7883493 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 20 Jul 2018 12:25:49 +0300 Subject: [PATCH 26/49] update zipfilestorage-with-jszip.js --- .../jio_zipfilestorage-with-jszip_js.js | 28 ++++++++++++++++--- .../jio_zipfilestorage-with-jszip_js.xml | 4 +-- .../zipfilestorage-with-jszip.js.js | 28 ++++++++++++++++--- .../zipfilestorage-with-jszip.js.xml | 8 ++++-- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.js index 8ffc5c143b0..9c6c7062b9d 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.js @@ -139,6 +139,26 @@ for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2 }); }; + ZipFileStorage.prototype.hasCapacity = function (name) { + return (name === "list"); + }; + + ZipFileStorage.prototype.buildQuery = function () { + return loadZip(this) + .push(function (zip) { + var dirname, + dir_list = [{id: '/', value: {}}]; + for (dirname in zip.files) { + if (zip.files.hasOwnProperty(dirname)) { + if (zip.files[dirname].dir) { + dir_list.push({id: '/' + dirname, value: {}}); + } + } + } + return dir_list; + }); + }; + ZipFileStorage.prototype.allAttachments = function (id) { id = restrictDocumentId(id); return loadZip(this) @@ -204,8 +224,8 @@ for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2 throw new jIO.util.jIOError("Cannot find document", 404); } if (!(zip.files.hasOwnProperty(attachId) && !zip.files[attachId].dir)) { - throw new jIO.util.jIOError("Cannot find attachment: " - + '/' + id + " , " + name, + throw new jIO.util.jIOError("Cannot find attachment: " + + '/' + id + " , " + name, 404); } return zip.file(attachId).async('blob'); @@ -222,8 +242,8 @@ for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2 throw new jIO.util.jIOError("Cannot find document", 404); } if (!(zip.files.hasOwnProperty(attachId) && !zip.files[attachId].dir)) { - throw new jIO.util.jIOError("Cannot find attachment: " - + '/' + id + " , " + name, + throw new jIO.util.jIOError("Cannot find attachment: " + + '/' + id + " , " + name, 404); } zip.remove(attachId); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.xml b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.xml index b82ca2e5434..d1346236093 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/jio_zipfilestorage-with-jszip_js.xml @@ -242,7 +242,7 @@ serial - 960.14254.57744.3293 + 968.64417.14775.57582 state @@ -260,7 +260,7 @@ - 1498139912.86 + 1531915725.03 UTC diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.js index 8ffc5c143b0..9c6c7062b9d 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.js @@ -139,6 +139,26 @@ for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2 }); }; + ZipFileStorage.prototype.hasCapacity = function (name) { + return (name === "list"); + }; + + ZipFileStorage.prototype.buildQuery = function () { + return loadZip(this) + .push(function (zip) { + var dirname, + dir_list = [{id: '/', value: {}}]; + for (dirname in zip.files) { + if (zip.files.hasOwnProperty(dirname)) { + if (zip.files[dirname].dir) { + dir_list.push({id: '/' + dirname, value: {}}); + } + } + } + return dir_list; + }); + }; + ZipFileStorage.prototype.allAttachments = function (id) { id = restrictDocumentId(id); return loadZip(this) @@ -204,8 +224,8 @@ for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2 throw new jIO.util.jIOError("Cannot find document", 404); } if (!(zip.files.hasOwnProperty(attachId) && !zip.files[attachId].dir)) { - throw new jIO.util.jIOError("Cannot find attachment: " - + '/' + id + " , " + name, + throw new jIO.util.jIOError("Cannot find attachment: " + + '/' + id + " , " + name, 404); } return zip.file(attachId).async('blob'); @@ -222,8 +242,8 @@ for(d=1;d<=W;d++)f[d]=g=g+c[d-1]<<1;for(e=0;e<=b;e++){var h=a[2*e+1];0!==h&&(a[2 throw new jIO.util.jIOError("Cannot find document", 404); } if (!(zip.files.hasOwnProperty(attachId) && !zip.files[attachId].dir)) { - throw new jIO.util.jIOError("Cannot find attachment: " - + '/' + id + " , " + name, + throw new jIO.util.jIOError("Cannot find attachment: " + + '/' + id + " , " + name, 404); } zip.remove(attachId); diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.xml index 396dab6e6d1..0013f9fc2e5 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.xml +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/zipfilestorage-with-jszip.js.xml @@ -6,13 +6,17 @@ + + _Cacheable__manager_id + http_cache + __name__ zipfilestorage-with-jszip.js content_type - application/javascript + text/javascript precondition @@ -20,7 +24,7 @@ title - zipfilestorage-with-jszip.js + -- 2.30.9 From b6b09964fb57694defc3baca028343348a46aaff Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Tue, 24 Jul 2018 14:49:53 +0300 Subject: [PATCH 27/49] erp5_officejs: schema editor: add fetch and upload field on upload page --- .../gadget_erp5_page_ojs_zip_upload.js.js | 88 ++++++++++++++++--- 1 file changed, 78 insertions(+), 10 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js index 76da5d1e7bf..27544602332 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_zip_upload.js.js @@ -1,5 +1,5 @@ /*global window, rJS, RSVP, loopEventListener, - jIO, document */ + jIO, document, URL */ /*jslint nomen: true, indent: 2, maxerr: 3 */ (function (window, rJS, jIO, RSVP) { "use strict"; @@ -10,6 +10,17 @@ Text: 'application/x-asc-text' }; + function displayError(g, text) { + return g.notifySubmitted({ + message: text, + status: 'fail' + }) + .push(function () { + // return undefined for fail detection + return; + }); + } + function endsWith(str, suffix) { return str.indexOf(suffix, str.length - suffix.length) !== -1; } @@ -109,8 +120,54 @@ return form_gadget.getContent(); }) .push(function (content) { + var data_array, + protocol, + i; + if (!content.data) { + content.data = []; + } + data_array = content.data; + for (i = 0; i < data_array.length; i += 1) { + data_array[i].blob = jIO.util.dataURItoBlob(data_array[i].url); + data_array[i].url = undefined; + } + if (content.data_url) { + protocol = (new URL(content.data_url, gadget.__path)).protocol; + if (protocol === "http:") { + if (window.location.protocol !== protocol) { + return displayError(gadget, "You cannot mixed http and https calls"); + } + } + return RSVP.Queue() + .push(function () { + return jIO.util.ajax({ + dataType: "blob", + url: content.data_url + }); + }) + .push(function (evt) { + content.data.push({ + blob: evt.target.response, + file_name: content.data_url + }); + return content; + }, function () { + return displayError(gadget, 'Download ' + content.data_url + ' Failed'); + }); + } + return content; + }) + .push(function (content) { + if (!content) { + // fail while downloading + return; + } + if (content.data.length === 0) { + return gadget.notifySubmitted({message: 'You need enter data', status: 'fail'}); + } return new RSVP.Queue() .push(function () { + return RSVP.all([ gadget.getSetting('jio_storage_name'), gadget.getSetting('jio_storage_description') @@ -133,7 +190,7 @@ } for (i = 0; i < data_array.length; i += 1) { - blob = jIO.util.dataURItoBlob(data_array[i].url); + blob = data_array[i].blob; if (endsWith(data_array[i].file_name, ".zip")) { configuration = { type: "replicate", @@ -172,13 +229,13 @@ } } return RSVP.all(promiseArray); + }) + .push(function () { + return RSVP.all([ + gadget.notifySubmitted({message: 'Data Updated', status: 'success'}), + gadget.redirect({command: 'history_previous'}) + ]); }); - }) - .push(function () { - return RSVP.all([ - gadget.notifySubmitted({message: 'Data Updated', status: 'success'}), - gadget.redirect({command: 'history_previous'}) - ]); }); }) @@ -201,13 +258,24 @@ "title": "Upload files and Zip archive containing files", "default": "", "css_class": "", - "required": 1, + "required": 0, "editable": 1, "key": "data", "hidden": 0, "multiple": "true", "accept": "application/zip," + result[1], "type": "FileField" + }, + "my_url": { + "description": "", + "title": "Fetch and Upload files and Zip archive containing files", + "default": "", + "css_class": "", + "required": 0, + "editable": 1, + "key": "data_url", + "hidden": 0, + "type": "StringField" } } }, @@ -221,7 +289,7 @@ form_definition: { group_list: [[ "left", - [["my_file"]] + [["my_file"], ["my_url"]] ]] } }); -- 2.30.9 From 3e3bf820ed9b687757293aa6b7cc2fac595fd3bc Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 25 Jul 2018 14:16:59 +0300 Subject: [PATCH 28/49] erp5_officejs: schema editor: fix developer_mode switcher --- .../gadget_erp5_ojs_schema_panel.html.html | 2 +- .../gadget_erp5_ojs_schema_panel.js.js | 77 +++++++++++-------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html index 230f70ac803..3861edf9913 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.html.html @@ -37,7 +37,7 @@
      diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js index 3d56052df82..5dcaf5e3b06 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js @@ -34,6 +34,9 @@ .declareAcquiredMethod("translateHtml", "translateHtml") .declareAcquiredMethod("translate", "translate") .declareAcquiredMethod("redirect", "redirect") + .declareAcquiredMethod("updatePanel", "updatePanel") + .declareAcquiredMethod("getSetting", "getSetting") + .declareAcquiredMethod("setSetting", "setSetting") .declareAcquiredMethod("getUrlParameter", "getUrlParameter") .declareAcquiredMethod("jio_allDocs", "jio_allDocs") @@ -85,18 +88,27 @@ .push(undefined, function () { return "[]"; }), - context.getUrlParameter('editable') + context.getSetting('developer_mode') + .push(undefined, function () { + return true; + }) ]); }) .push(function (ret) { var schema_list = ret[0], - editable = ret[1]; + developer_mode = ret[1]; + if (developer_mode === undefined) { + developer_mode = true; + } + if (developer_mode === "false") { + developer_mode = false; + } return context.changeState({ workflow_list: workflow_list, view_list: view_list, schema_list: schema_list, global: true, - editable: options.editable || editable || false + developer_mode: developer_mode }); }); }) @@ -144,8 +156,8 @@ }) .push(function () { return context.declareGadget('gadget_erp5_field_multicheckbox.html', { - scope: "editable_mode", - element: tmp_element.querySelector('[data-gadget-scope="editable_mode"]') + scope: "developer_mode", + element: tmp_element.querySelector('[data-gadget-scope="developer_mode"]') }); }) .push(function () { @@ -155,7 +167,7 @@ } if (modification_dict.hasOwnProperty("schema_list") || - modification_dict.hasOwnProperty("editable")) { + modification_dict.hasOwnProperty("developer_mode")) { queue .push(function () { function gen_element(element, title, css, accesskey) { @@ -173,24 +185,24 @@ row, tasks = [], schema_list = JSON.parse(context.state.schema_list); - if (context.state.editable) { + if (context.state.developer_mode) { tasks.push(gen_element({command: 'display', options: {page: "ojs_schema_document_list"}}, "Schemas", "search", "s")); } for (i = 0; i < schema_list.length; i += 1) { row = schema_list[i]; tasks.push(gen_element({command: 'display', options: { - page: "ojs_schema_document_list", - portal_type: "JSON Document", - schema: row.id, - schema_title: row.value.title - }}, row.value.title, "search")); + page: "ojs_schema_document_list", + portal_type: "JSON Document", + schema: row.id, + schema_title: row.value.title + }}, row.value.title, "search")); } tasks.push(gen_element({command: 'display', options: {page: "ojs_sync", 'auto_repair': true}}, "Synchronize", "refresh")); tasks.push(gen_element({command: 'display', options: {page: "ojs_configurator"}}, "Storages", "dropbox")); - if (context.state.editable) { + if (context.state.developer_mode) { tasks.push(gen_element({command: 'index', options: {page: "ojs_zip_upload"}}, "Upload", "upload")); } @@ -207,25 +219,25 @@ // Update the checkbox field value return RSVP.all([ - context.getDeclaredGadget("editable_mode"), + context.getDeclaredGadget("developer_mode"), context.translate("Developer Mode") ]); }) .push(function (result_list) { var value = [], - search_gadget = result_list[0], + developer_mode_gadget = result_list[0], title = result_list[1]; - if (context.state.editable) { - value = ['editable']; + if (context.state.developer_mode) { + value = ['developer']; } - return search_gadget.render({field_json: { - editable: true, - name: 'editable', - key: 'editable', - hidden: false, - items: [[title, 'editable']], - default: value - }}); + return developer_mode_gadget.render({field_json: { + editable: true, + name: 'developer', + key: 'developer', + hidden: false, + items: [[title, 'developer']], + default: value + }}); }); } @@ -336,18 +348,21 @@ }) .allowPublicAcquisition('notifyChange', function (argument_list, scope) { - if (scope === 'editable_mode') { + if (scope === 'developer_mode' && argument_list[0] === "change") { var context = this; - return context.getDeclaredGadget('editable_mode') + return context.getDeclaredGadget('developer_mode') .push(function (gadget) { return gadget.getContent(); }) .push(function (result) { - var options = {editable: undefined}; - if (result.editable.length === 1) { - options.editable = true; + var value = "false"; + if (result.developer.length === 1) { + value = true; } - return context.redirect({command: 'change', options: options}); + return context.setSetting("developer_mode", value); + }) + .push(function () { + return context.updatePanel({}); }); } // Typing a search query should not modify the header status -- 2.30.9 From ca7765f28048aa673c93415223fede18abb7d17c Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 25 Jul 2018 21:04:14 +0300 Subject: [PATCH 29/49] erp5_officejs: schema editor: use storage only if storage configured --- .../gadget_erp5_ojs_schema_panel.js.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js index 5dcaf5e3b06..00e275c7550 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js @@ -75,6 +75,12 @@ } return RSVP.Queue() .push(function () { + return context.getSetting('jio_storage_name'); + }) + .push(function (storage_name) { + if (!storage_name) { + return ["[]", true]; + } return RSVP.all([ context.jio_allDocs({ "query": '(portal_type:"JSON Schema") AND (NOT (title:""))', @@ -84,14 +90,8 @@ }) .push(function (result) { return JSON.stringify(result.data.rows); - }) - .push(undefined, function () { - return "[]"; }), context.getSetting('developer_mode') - .push(undefined, function () { - return true; - }) ]); }) .push(function (ret) { -- 2.30.9 From 764cc652dc5810c194b316f449c949ef33b7cf40 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Thu, 26 Jul 2018 11:52:04 +0000 Subject: [PATCH 30/49] erp5_officejs: publicate web_site officejs_schema --- .../web_site_module/officejs_schema.xml | 47 ++++++++++++++++--- .../web_site_module/officejs_schema/app.xml | 6 +-- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml index 4b2fef241d6..629f1f55eb3 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml @@ -6,6 +6,24 @@ + + _Access_contents_information_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Authenticated + Author + Manager + Member + Owner + Reviewer + + + _Add_portal_content_Permission @@ -49,7 +67,24 @@ Assignee Assignor Manager + + + + + _View_Permission + + + Anonymous + Assignee + Assignor + Associate + Auditor + Authenticated + Author + Manager + Member Owner + Reviewer @@ -612,9 +647,7 @@ action - - - + publish actor @@ -640,7 +673,7 @@ - 1528355166.78 + 1532439048.88 UTC @@ -649,7 +682,7 @@ validation_state - embedded + published @@ -685,7 +718,7 @@
      serial - 968.9516.24741.45312 + 968.21791.29852.58675 state @@ -703,7 +736,7 @@ - 1528722116.43 + 1529569812.75 UTC diff --git a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml index 019ee156661..efcf40f5a1c 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml @@ -316,7 +316,7 @@ configuration_content_security_policy - default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data: + default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' http: https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data: configuration_default_jio_document_page_gadget_url @@ -633,7 +633,7 @@ serial - 968.10031.58855.19404 + 968.21792.18763.37393 state @@ -651,7 +651,7 @@ - 1528737611.59 + 1529569802.7 UTC -- 2.30.9 From 0c06ca35096b5d09e302c7e491719657877c33e2 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 27 Jul 2018 20:17:35 +0000 Subject: [PATCH 31/49] erp5_json_form: version up from https://lab.nexedi.com/bk/rjs_json_form --- .../erp5_json_form/jsonform.gadget.js.js | 13 ++++- ...gadget_json_generated_form_child.html.html | 1 - .../gadget_json_generated_form_child.js.js | 55 +++++++++++-------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index 5ad67303cca..2042ec61a7b 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -420,7 +420,8 @@ }) .declareAcquiredMethod("downloadJSON", "downloadJSON") .declareAcquiredMethod("notifyChange", "notifyChange") - .allowPublicAcquisition("notifyChange", function () { + .allowPublicAcquisition("rootNotifyChange", function () { + this.props.changed = true; return this.notifyChange(); }) .declareAcquiredMethod("notifyValid", "notifyValid") @@ -508,6 +509,7 @@ } else { error_message.appendChild(createTextNode(error.message)); } + error_message.appendChild(document.createElement("br")); error_message.hidden = false; a = document.createElement("a"); @@ -643,6 +645,15 @@ // XXX Disable return; }) + .onLoop(function () { + var gadget = this; + if (this.props.changed) { + return this.checkValidity() + .push(function () { + gadget.props.changed = false; + }); + } + }, 500) .declareMethod('getContent', function () { var g = this; diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html index a607a22de3d..6afe6936025 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html @@ -8,7 +8,6 @@ - diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 88c197fb33a..0e0021b0a0a 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -1,7 +1,7 @@ /*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/ /*global window, document, URL, rJS, RSVP, jIO, tv4, location */ -(function (window, document, location, rJS, RSVP, jIO, tv4) { +(function (window, document, location, rJS, RSVP, tv4) { "use strict"; var render_object; @@ -101,13 +101,13 @@ return input; } - function render_textarea(json_field, default_value, data_format) { + function render_textarea(json_document, data_format) { var input = document.createElement("textarea"); - if (default_value !== undefined) { - if (default_value instanceof Array) { - input.value = default_value.join("\n"); + if (json_document !== undefined) { + if (typeof json_document === "object") { + input.value = JSON.stringify(json_document, null, 2); } else { - input.value = default_value; + input.value = json_document; } } input["data-format"] = data_format; @@ -273,13 +273,6 @@ return ret_arr[0]; } - function checkValidityAndNotifyChange(g) { - return RSVP.all([ - g.checkValidity(), - g.notifyChange() - ]); - } - function render_schema_selector(gadget, title, schema_arr, event, rerender) { return RSVP.Queue() .push(function () { @@ -385,7 +378,7 @@ return event(schema_alternatives[value[scope]].value); }) .push(function () { - return checkValidityAndNotifyChange(gadget); + return gadget.rootNotifyChange(); }) .push(function () { if (rerender) { @@ -450,7 +443,7 @@ } else { input.removeAttribute("style"); } - return checkValidityAndNotifyChange(gadget); + return gadget.rootNotifyChange(); }); }, rerender: function () { @@ -681,10 +674,13 @@ if (!input && ["string", "integer", "number"].indexOf(type) >= 0) { if (json_field.contentMediaType === "text/plain") { - input = render_textarea(json_field, default_value, "string"); + input = render_textarea(default_value, "string"); } else { input = document.createElement("input"); if (default_value !== undefined) { + if (typeof default_value === "object") { + default_value = JSON.stringify(default_value); + } input.value = default_value; } @@ -1295,7 +1291,7 @@ g.props = {}; g.options = {}; }) - .declareAcquiredMethod("notifyChange", "notifyChange") + .declareAcquiredMethod("rootNotifyChange", "rootNotifyChange") .declareAcquiredMethod("renameChildrenParent", "renameChildren") .allowPublicAcquisition("renameChildren", function (opt_arr, scope) { var property_name, @@ -1359,7 +1355,7 @@ for (i = 0; i < button_list.length; i = i + 1) { tasks.push(button_list[i].rerender()); } - tasks.push(checkValidityAndNotifyChange(g)); + tasks.push(g.rootNotifyChange()); return RSVP.Queue() .push(function () { return RSVP.all(tasks); @@ -1458,7 +1454,7 @@ if (event_object && opt.type === "change") { return event_object.event(); } - return g.notifyChange(); + return g.rootNotifyChange(); }) .declareMethod('renderForm', function (options) { var g = this, @@ -1485,6 +1481,12 @@ options.delete_button = !options.required; } } + if (options.top && !options.type && !schema.type) { + // XXX use "object" as type for support buggy + // slapos schemas where some times type absent + // i need remove it in future + options.type = "object"; + } while (root.firstChild) { root.removeChild(root.firstChild); } @@ -1526,19 +1528,24 @@ } }) - .onEvent('change', function (evt) { + .onEvent('input', function (evt) { if (evt.target === this.props.property_name_edit) { return this.rename(this.props.property_name_edit.value, evt); } - var field_list = this.props.inputs, - i; + var gadget = this, + field_list = this.props.inputs, + i, + changed = false; // on form data field for (i = 0; i < field_list.length; i = i + 1) { if (evt.target === field_list[i]) { - return checkValidityAndNotifyChange(this); + changed = true; } } + if (changed) { + return gadget.rootNotifyChange(); + } }) .declareMethod('getContent', function () { @@ -1568,4 +1575,4 @@ }); }); -}(window, document, location, rJS, RSVP, jIO, tv4)); \ No newline at end of file +}(window, document, location, rJS, RSVP, tv4)); \ No newline at end of file -- 2.30.9 From 977aab9749d2a14da79cf1c46f614d871b78519b Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 30 Jul 2018 09:43:37 +0000 Subject: [PATCH 32/49] erp5_json_form: changestate mutex added on getContent for preventing data loss on save --- .../portal_skins/erp5_json_form/jsonform.gadget.js.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index 2042ec61a7b..c018bdbb536 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -675,6 +675,6 @@ }); } return {}; - }); + }, {mutex: 'changestate'}); }(window, document, location, rJS, RSVP, jIO, tv4)); \ No newline at end of file -- 2.30.9 From 9acaa833024ba8b3cdb5146a2700f67b07f0ca65 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Mon, 30 Jul 2018 19:44:58 +0300 Subject: [PATCH 33/49] erp5_officejs: schema_editor: fix first automatic sync --- .../gadget_erp5_ojs_schema_panel.js.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js index 00e275c7550..f06cc1c5953 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_ojs_schema_panel.js.js @@ -75,10 +75,15 @@ } return RSVP.Queue() .push(function () { - return context.getSetting('jio_storage_name'); + return RSVP.all([ + context.getSetting('jio_storage_name'), + context.getSetting('sync_reload', false) + ]); }) - .push(function (storage_name) { - if (!storage_name) { + .push(function (result) { + var storage_name = result[0], + sync_reload = result[1]; + if (!storage_name || sync_reload) { return ["[]", true]; } return RSVP.all([ -- 2.30.9 From c67dad31c11ecc92aeaf7296cf610f654db2f71c Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Tue, 28 Aug 2018 16:44:38 +0000 Subject: [PATCH 34/49] erp5_json_form: update version from https://lab.nexedi.com/bk/rjs_json_form --- .../erp5_json_form/jsonform.gadget.js.js | 164 ++++-- .../gadget_json_generated_form_child.js.js | 488 ++++++++++++++---- 2 files changed, 512 insertions(+), 140 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index c018bdbb536..57303850f68 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -27,12 +27,12 @@ url = new URL(url, base_url); if (urn_prefix) { pathname = url.pathname.slice(1); - return { - href: urn_prefix + encodeURIComponent(pathname + url.search + url.hash), - origin: urn_prefix, - pathname: encodeURIComponent(pathname), - hash: url.hash - }; + this.href = urn_prefix + encodeURIComponent(pathname + url.search + url.hash); + this.origin = urn_prefix; + this.pathname = encodeURIComponent(pathname); + this.hash = url.hash; + this.search = ""; + return this; } return url; } @@ -119,9 +119,9 @@ base_url = convertToRealWorldSchemaPath(g, path), absolute_url; if (base_url === "" || base_url.indexOf("#") === 0) { - absolute_url = URLwithJio(url, base_url_failback); + absolute_url = new URLwithJio(url, base_url_failback); } else { - absolute_url = URLwithJio(url, base_url); + absolute_url = new URLwithJio(url, base_url); } return absolute_url; } @@ -181,54 +181,85 @@ } } + function map_url(g, download_url) { + var mapped_url = download_url, + hash = mapped_url.hash, + i, + schemas = g.props.schemas, + next_mapped_url; + // simple defence forever loop + for (i = 0; i < Object.keys(schemas).length; i += 1) { + next_mapped_url = g.props.schemas[mapped_url.origin + mapped_url.pathname + mapped_url.search]; + if (next_mapped_url === undefined) { + break; + } + mapped_url = next_mapped_url; + if (typeof mapped_url !== "string") { + mapped_url = resolveLocalReference(mapped_url, hash); + break; + } + mapped_url = new URL(mapped_url, g.__path); + if (hash[0] === '#') { + hash = hash.slice(1); + } + if (hash === '/') { + hash = ''; + } + hash = mapped_url.hash + hash; + } + return mapped_url; + } + function loadJSONSchema(g, $ref, path) { var protocol, url, download_url, hash, - schema_url_map, + mapped_url, queue; // XXX need use `id` property if (!path) { path = "/"; } - url = convertUrlToAbsolute(g, path, $ref, window.location); - download_url = url.origin + url.pathname; - schema_url_map = { - "http://json-schema.org/draft-04/schema": "json-schema/schema4.json", - "http://json-schema.org/draft-06/schema": "json-schema/schema6.json", - "http://json-schema.org/draft-07/schema": "json-schema/schema7.json", - "http://json-schema.org/schema": "json-schema/schema7.json" - }; - if (schema_url_map.hasOwnProperty(download_url)) { - url = new URL(schema_url_map[download_url], g.__path); + url = convertUrlToAbsolute(g, path, decodeURI($ref), window.location); + mapped_url = map_url(g, url); + if (mapped_url instanceof URL || mapped_url instanceof URLwithJio) { + url = mapped_url; } protocol = url.protocol; if (protocol === "http:" || protocol === "https:") { if (window.location.protocol !== protocol) { - url = new URL($ref.replace(protocol + "//", window.location.protocol + "//")); + url = new URL(decodeURI($ref).replace(protocol + "//", window.location.protocol + "//")); // throw new Error("You cannot mixed http and https calls"); } } - download_url = url.origin + url.pathname; + download_url = url.origin + url.pathname + url.search; hash = url.hash; url = url.href; - if (download_url.startsWith("urn:jio:")) { + if (!(mapped_url instanceof URL || mapped_url instanceof URLwithJio)) { queue = RSVP.Queue() .push(function () { - return g.downloadJSON(download_url); + return mapped_url; }); } else { - queue = RSVP.Queue() - .push(function () { - return downloadJSON(download_url); + if (download_url.startsWith("urn:jio:")) { + queue = RSVP.Queue() + .push(function () { + return g.downloadJSON(download_url); + }); + } else { + queue = RSVP.Queue() + .push(function () { + return downloadJSON(download_url); + }); + } + queue + .push(function (json) { + checkCircular(g, path, url); + return resolveLocalReference(json, hash); }); } return queue - .push(function (json) { - checkCircular(g, path, url); - return resolveLocalReference(json, hash); - }) .push(undefined, function (err) { // XXX it will be great to have ability convert json_pointers(hash) // in line numbers for pointed to line in rich editors. @@ -237,9 +268,9 @@ schema_a = document.createElement("a"), pointed_a = document.createElement("a"); schema_a.setAttribute("href", download_url); - schema_a.text = (URLwithJio(download_url)).pathname; + schema_a.text = (new URLwithJio(download_url)).pathname; pointed_a.setAttribute("href", url_from_pointed); - pointed_a.text = (URLwithJio(url_from_pointed)).pathname; + pointed_a.text = (new URLwithJio(url_from_pointed)).pathname; g.props.schema_resolve_errors[url_from_pointed] = { schemaPath: path, message: [ @@ -377,7 +408,8 @@ // XXX `if then else` construction can be simplify to // anyOf(allOf(if_schema, then_schema), else_schema) // and realized by existed rails - if (schema === undefined) { + if (schema === undefined || + Object.keys(schema).length === 0) { schema = true; } if (schema.anyOf !== undefined) { @@ -389,6 +421,24 @@ if (schema.$ref) { return loadJSONSchema(g, schema.$ref, schema_path); } + if (schema.definitions) { + var key, + d, + url, + mapped_url; + for (key in schema.definitions) { + if (schema.definitions.hasOwnProperty(key)) { + d = schema.definitions[key]; + url = d.$id || d.id; + if (url) { + mapped_url = convertUrlToAbsolute(g, schema_path, '#' + schema_path, window.location); + // XXX /? + mapped_url = mapped_url + 'definitions/' + key; + g.props.schemas[url] = mapped_url; + } + } + } + } return RSVP.Queue() .push(function () { return [{ @@ -499,7 +549,7 @@ a.setAttribute("href", "#" + errorUid); a.text = errorId; element.setAttribute("class", "error-input"); - error_message = element.querySelector("#" + id.replace(/\//g, "\\/") + " > .error"); + error_message = document.getElementById(id).querySelector(".error"); error_message.appendChild(a); error_message.setAttribute("id", errorUid); if (error.message instanceof Array) { @@ -548,16 +598,20 @@ .declareMethod('render', function (options) { return this.changeState({ key: options.key, - value: JSON.stringify(options.value) || '""', + value: JSON.stringify(options.value), schema: JSON.stringify(options.schema), + saveOrigValue: options.saveOrigValue, schema_url: options.schema_url, editable: options.editable === undefined ? true : options.editable }); }) .onStateChange(function () { var g = this, - json_document = JSON.parse(g.state.value), + json_document = g.state.value, schema; + if (json_document !== undefined) { + json_document = JSON.parse(json_document); + } if (g.state.schema !== undefined) { schema = JSON.parse(g.state.schema); } @@ -567,6 +621,12 @@ // it's need for schema uri computation g.props.schema = {}; g.props.schema_map = {}; + g.props.schemas = { + "http://json-schema.org/draft-04/schema": "json-schema/schema4.json", + "http://json-schema.org/draft-06/schema": "json-schema/schema6.json", + "http://json-schema.org/draft-07/schema": "json-schema/schema7.json", + "http://json-schema.org/schema": "json-schema/schema7.json" + }; // schema_required_urls[path] = [ // stack required urls, on every unrequired field stack begining from [] // "url1", @@ -590,14 +650,28 @@ } }) .push(function () { - if (schema) { - return schema; + var schema_url, + queue; + if (schema !== undefined) { + schema_url = g.state.schema_url || + schema.$id || + schema.id || + window.location.toString(); + g.props.schema[""] = schema; + g.props.schema_map["/"] = schema_url; + g.props.schemas[schema_url] = schema; + queue = expandSchemaForField(g, schema, "/", true); + } else { + schema_url = g.state.schema_url || + (json_document && json_document.$schema); + if (schema_url) { + queue = loadJSONSchema(g, schema_url); + } } - var schema_url = g.state.schema_url || - (json_document && json_document.$schema); - if (schema_url) { - return loadJSONSchema(g, schema_url) + if (queue) { + return queue .push(function (schema_arr) { + // XXX for root of form use first schema selection return schema_arr[0].schema; }); } @@ -608,6 +682,7 @@ schema: schema, schema_path: "", document: json_document, + saveOrigValue: g.state.saveOrigValue, required: true, top: true }); @@ -615,6 +690,11 @@ .push(function () { return g.checkValidity(); }) + .push(function () { + if (g.props.form_gadget.props.changed) { + g.notifyChange(); + } + }) .push(function () { return g; }); diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 0e0021b0a0a..859bec414f8 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -5,6 +5,31 @@ "use strict"; var render_object; + function deepEqual(x, y) { + if (x === y) { + return true; + } + if ((typeof x === "object" && x !== null) && (typeof y === "object" && y !== null)) { + if (Object.keys(x).length !== Object.keys(y).length) { + return false; + } + var prop; + for (prop in x) { + if (x.hasOwnProperty(prop)) { + if (y.hasOwnProperty(prop)) { + if (!deepEqual(x[prop], y[prop])) { + return false; + } + } else { + return false; + } + } + } + return true; + } + return false; + } + function decodeJsonPointer(_str) { // https://tools.ietf.org/html/rfc6901#section-5 return _str.replace(/~1/g, '/').replace(/~0/g, '~'); @@ -16,12 +41,60 @@ } function getDocumentType(doc) { + if (doc === undefined) { + return; + } + if (doc === null) { + return "null"; + } if (doc instanceof Array) { return "array"; } return typeof doc; } + function guessSchemaType(schema) { + var property_name; + for (property_name in schema) { + if (schema.hasOwnProperty(property_name)) { + switch (property_name) { + // case "allOf": + // case "anyOf": + // case "oneOf": + // return false; + case "required": + case "maxProperties": + case "minProperties": + case "additionalProperties": + case "properties": + case "patternProperties": + case "dependencies": + case "propertyNames": + return "object"; + case "additionalItems": + case "items": + case "maxItems": + case "minItems": + case "uniqueItems": + case "contains": + return "array"; + case "maxLength": + case "minLength": + case "pattern": + case "contentEncoding": + case "contentMediaType": + return "string"; + case "multipleOf": + case "maximum": + case "exclusiveMaximum": + case "minimum": + case "exclusiveMinimum": + return "number"; + } + } + } + } + function createElement(type, props) { var element = document.createElement(type), key; @@ -48,15 +121,18 @@ return schema; } - function render_selection(schema, json_document) { + function render_enum(g, schema, json_document) { var input = document.createElement("select"), option, i, + ser_value, + selected = false, enum_arr = schema['enum']; input.size = 1; if (schema.default) { if (json_document === undefined) { json_document = schema.default; + g.props.changed = true; } } else { option = document.createElement("option"); @@ -69,18 +145,40 @@ for (i = 0; i < enum_arr.length; i += 1) { if (enum_arr.hasOwnProperty(i)) { option = document.createElement("option"); - option.value = enum_arr[i]; - option.textContent = enum_arr[i]; - if (enum_arr[i] === json_document) { + // XXX use number id for speedup + ser_value = JSON.stringify(enum_arr[i]); + option.value = ser_value; + if (typeof enum_arr[i] === "string") { + option.textContent = enum_arr[i]; + } else { + option.textContent = ser_value; + } + if (deepEqual(enum_arr[i], json_document)) { option.selected = true; + selected = true; } input.appendChild(option); } } + if (json_document !== undefined && !selected) { + // save original json_document even if it + // not support with schema + // XXX element should be removed on first user interact + option = document.createElement("option"); + ser_value = JSON.stringify(json_document); + option.value = ser_value; + if (typeof json_document === "string") { + option.textContent = json_document; + } else { + option.textContent = ser_value; + } + option.selected = true; + input.appendChild(option); + } return input; } - function render_boolean(schema, json_document) { + function render_boolean(g, schema, json_document) { var input, schema_for_selection = { type: "boolean", @@ -96,11 +194,27 @@ if (getDocumentType(schema.default) === "boolean") { schema_for_selection.default = schema.default; } - input = render_selection(schema_for_selection, json_document); + input = render_enum(g, schema_for_selection, json_document); input.setAttribute('data-json-type', "boolean"); return input; } + function render_const(schema, json_document) { + var input = document.createElement("input"), + ser_doc = JSON.stringify(json_document), + ser_const = JSON.stringify(schema.const); + input.setAttribute('readonly', true); + if (json_document === undefined || deepEqual(json_document, schema.const)) { + input.setAttribute('data-origin-value', ser_const); + input.value = ser_const; + } else { + input.value = ser_doc + ' ≠ ' + ser_const; + input.setAttribute('data-origin-value', ser_doc); + input.setAttribute('data-const-value', ser_const); + } + return input; + } + function render_textarea(json_document, data_format) { var input = document.createElement("textarea"); if (json_document !== undefined) { @@ -160,8 +274,30 @@ schema_path: options.schema_path, document: options.default_dict, display_label: options.parent_type !== "array", + saveOrigValue: g.props.saveOrigValue, scope: scope - }); + }) + .push(function () { + if (form_gadget.props.changed) { + g.props.changed = true; + } + return form_gadget.element; + }); + }); + } + + function expandItems(g, items, schema_path, minItems) { + if (!(items instanceof Array)) { + return g.expandSchema(items, schema_path, minItems !== 0); + } + var i, + tasks = []; + for (i = 0; i < items.length; i += 1) { + tasks.push(g.expandSchema(items[i], schema_path + '/' + i, i < minItems)); + } + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); }); } @@ -197,7 +333,9 @@ function checkSchemaArrOneChoise(schema_arr) { if (schema_arr.length === 1) { - if (schema_arr[0].schema === true) { + if (schema_arr[0].schema === true || + !(schema_arr[0].schema.hasOwnProperty('type') || + schema_arr[0].schema.hasOwnProperty('enum'))) { return false; } if (schema_arr[0].schema.type instanceof Array) { @@ -312,7 +450,9 @@ for (i = 0; i < schema_arr.length; i += 1) { schema_item = schema_arr[i]; description = schema_item.title; - if (schema_item.schema === true) { + if (schema_item.schema === true || + !(schema_item.schema.hasOwnProperty('type') || + schema_item.schema.hasOwnProperty('enum'))) { generateItemsForAny(schema_item.property_name, schema_item.schema_path); } else if (getDocumentType(schema_item.schema.type) === "array") { description = description || schema_item.schema.description; @@ -473,46 +613,64 @@ }); } - function render_array(gadget, schema, json_document, root, path, schema_path) { - var div, - div_input, - input, + function render_array(gadget, schema, json_document, div_input, path, schema_path) { + var input, + is_items_arr = schema.items instanceof Array, minItems = schema.minItems || 0; - div = document.createElement("div"); - div.setAttribute("class", "jsonformfield"); - div.title = schema.description; - - div_input = document.createElement("div"); - div_input.setAttribute("class", "input"); + if (schema.default === undefined && + json_document === undefined) { + div_input.setAttribute("data-undefined", "true"); + } function element_append(child) { if (child) { input.parentNode.insertBefore(child, input); + div_input.removeAttribute("data-undefined"); } } function div_append(child) { if (child) { div_input.appendChild(child); + div_input.removeAttribute("data-undefined"); } } // XXX add failback rendering if json_document not array // input = render_textarea(schema, default_value, "array"); - return gadget.expandSchema(schema.items, schema_path + '/items', minItems !== 0) - .push(function (schema_arr) { + return RSVP.Queue() + .push(function () { + return RSVP.all([ + expandItems(gadget, schema.items, schema_path + '/items', minItems), + gadget.expandSchema(schema.additionalItems, schema_path + '/additionalItems', false) + ]); + }) + .push(function (arr) { var queue = RSVP.Queue(), i, + schema_path_item = schema_path + '/items', + schema_arr_arr = arr[0], + additionalItems = arr[1], + schema_arr = schema_arr_arr, len = 0; // XXX rewrite loading document for anyOf schema if (json_document) { for (i = 0; i < json_document.length; i = i + 1) { + if (is_items_arr) { + if (i < schema_arr_arr.length) { + schema_arr = schema_arr_arr[i]; + schema_path_item = schema_path + '/items/' + i; + } else { + schema_arr = additionalItems; + schema_path_item = schema_path + '/additionalItems'; + } + } queue .push( addSubForm.bind(gadget, { gadget: gadget, parent_type: 'array', - schema_path: schema_path + '/items', + schema_path: schema_path_item, schema_part: schema_arr, default_dict: json_document[i], required: i < minItems @@ -523,34 +681,78 @@ len = json_document.length; } - if (checkSchemaArrOneChoise(schema_arr) && minItems > len) { - for (i = 0; i < (minItems - len); i += 1) { - queue - .push( - addSubForm.bind(gadget, { - gadget: gadget, - parent_type: 'array', - schema_path: schema_arr[0].schema_path, - schema_part: schema_arr[0].schema, - required: true - }) - ) - .push(div_append); + if (is_items_arr) { + if (minItems > len) { + for (i; i < (minItems - len); i += 1) { + if (i < schema_arr_arr.length) { + schema_arr = schema_arr_arr[i]; + } else { + schema_arr = additionalItems; + } + if (!checkSchemaArrOneChoise(schema_arr)) { + break; + } + queue + .push( + addSubForm.bind(gadget, { + gadget: gadget, + parent_type: 'array', + schema_path: schema_arr[0].schema_path, + schema_part: schema_arr[0].schema, + required: true + }) + ) + .push(div_append); + } + } + if (i < schema_arr_arr.length) { + schema_arr = schema_arr_arr[i]; + } else { + schema_arr = additionalItems; + } + // XXX rerender on next item in schema.items + queue.push(render_schema_selector.bind(gadget, + gadget, "add item to array", + schema_arr, function (value) { + return addSubForm({ + gadget: gadget, + parent_type: 'array', + type: value.type, + schema_path: value.schema_path, + schema_part: value.schema + }) + .push(element_append); + })); + } else { + if (minItems > len && checkSchemaArrOneChoise(schema_arr)) { + for (i = 0; i < (minItems - len); i += 1) { + queue + .push( + addSubForm.bind(gadget, { + gadget: gadget, + parent_type: 'array', + schema_path: schema_arr[0].schema_path, + schema_part: schema_arr[0].schema, + required: true + }) + ) + .push(div_append); + } } - } - queue.push(render_schema_selector.bind(gadget, - gadget, "add item to array", - schema_arr, function (value) { - return addSubForm({ - gadget: gadget, - parent_type: 'array', - type: value.type, - schema_path: value.schema_path, - schema_part: value.schema - }) - .push(element_append); - })); + queue.push(render_schema_selector.bind(gadget, + gadget, "add item to array", + schema_arr, function (value) { + return addSubForm({ + gadget: gadget, + parent_type: 'array', + type: value.type, + schema_path: value.schema_path, + schema_part: value.schema + }) + .push(element_append); + })); + } return queue; }) .push(function (element) { @@ -559,8 +761,7 @@ // XXX update on every add/delete item // input.hidden = maxItems !== undefined && json_document.length >= maxItems; div_input.appendChild(input); - div.appendChild(div_input); - root.appendChild(div); + gadget.props.arrays[path] = div_input; }); } @@ -575,6 +776,7 @@ error_message, input, first_path, + type_changed, queue = RSVP.Queue(); if (json_field instanceof Array) { @@ -598,20 +800,33 @@ if (getDocumentType(json_field.type) === "string") { type = json_field.type; - } // else json_field.type is array so we use type + } else if (type === undefined && + default_value === undefined && + getDocumentType(json_field.type) === "array") { + type = json_field.type[0]; + } + if (["object", "array"].indexOf(type) >= 0 && + !(path !== "" && default_value === undefined) && + getDocumentType(default_value) !== type) { + if (gadget.props.saveOrigValue) { + // XXX is not useful for user + // only for tests + json_field = { + const: default_value + }; + } else { + gadget.props.changed = true; + } + } if (type === undefined && default_value !== undefined) { type = getDocumentType(default_value); } - // XXX bad peace of code - // i do not sure that type can be computed so - // but our schema in slapos bad - if (!type) { - if (json_field.properties && - json_field.required && - json_field.required.length > 0) { - type = "object"; - } + if (typeof type === "string") { + // it's only for simple types so we not use + // complex type detection + type_changed = default_value !== undefined && + typeof default_value !== type; } div = document.createElement("div"); @@ -664,34 +879,53 @@ div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/'); div_input.setAttribute("class", "input"); - if (json_field.enum !== undefined) { - input = render_selection(json_field, default_value); + if (json_field.const !== undefined) { + input = render_const(json_field, default_value); + } else if (json_field.enum !== undefined) { + input = render_enum(gadget, json_field, default_value); + // XXX take in account existing type with enum + type_changed = false; } - if (type === "boolean") { - input = render_boolean(json_field, default_value); + if (!input && type === "null") { + input = render_const({const: null}, default_value); } - if (!input && ["string", "integer", "number"].indexOf(type) >= 0) { + if (!input && type === "boolean") { + input = render_boolean(gadget, json_field, default_value); + } + + if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) { if (json_field.contentMediaType === "text/plain") { input = render_textarea(default_value, "string"); } else { input = document.createElement("input"); if (default_value !== undefined) { if (typeof default_value === "object") { - default_value = JSON.stringify(default_value); + input.value = JSON.stringify(default_value); + } else { + input.value = default_value; } - input.value = default_value; } if (type === "integer" || type === "number") { if (default_value === undefined && typeof json_field.default === "number") { input.value = json_field.default; + gadget.props.changed = true; } - input.type = "number"; input.setAttribute("data-json-type", type); + if (default_value === undefined || default_value === null || + typeof default_value === "number") { + input.type = "number"; + } if (type === "integer") { input.setAttribute("step", "1"); + if (typeof default_value === "number" && + parseInt(default_value, 10) !== default_value) { + // original json_document contain float schema + // limit integer we can save original document + type_changed = true; + } } if (type === "number") { input.setAttribute("step", "any"); @@ -699,6 +933,7 @@ } else { if (default_value === undefined && typeof json_field.default === "string") { input.value = json_field.default; + gadget.props.changed = true; } input.type = "text"; if (json_field.pattern) { @@ -712,7 +947,7 @@ } } - if (type === "array") { + if (!input && type === "array") { queue = render_array( gadget, json_field, @@ -721,10 +956,9 @@ first_path + '/', schema_path ); - gadget.props.arrays[first_path + '/'] = div; } - if (type === "object") { + if (!input && type === "object") { queue .push(function () { return render_object( @@ -744,6 +978,9 @@ gadget.props.inputs.push(input); input.name = first_path; input.required = options.required; + if (type_changed) { + input.setAttribute('data-origin-value', JSON.stringify(default_value)); + } // XXX for gui //input.setAttribute("class", "slapos-parameter"); div_input.appendChild(input); @@ -831,6 +1068,9 @@ } function checkSchemaIsMetaSchema(schema) { + if (!schema) { + return false; + } if (schema instanceof Array) { var i, sch; @@ -1215,7 +1455,8 @@ array = options.arrays[path] .querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']"); len = array.length; - if (len === 0) { + if (len === 0 && + !options.arrays[path].hasAttribute('data-undefined')) { convertOnMultiLevel(multi_level_dict, path.slice(0, -1), []); } for (i = 0; i < len; i = i + 1) { @@ -1246,26 +1487,33 @@ var json_dict = {}, k; g.props.inputs.forEach(function (input) { - if (input.required || input.value !== "") { - var type = input.getAttribute('data-json-type'); - if (type === 'number') { - json_dict[input.name] = parseFloat(input.value); - } else if (type === "integer") { - json_dict[input.name] = parseInt(input.value, 10); - } else if (type === "boolean") { - if (input.value === "true") { - json_dict[input.name] = true; - } else if (input.value === "false") { - json_dict[input.name] = false; - } - } else if (input.tagName === "TEXTAREA") { - if (input["data-format"] === "string") { - json_dict[input.name] = input.value; + if (input.hasAttribute('data-origin-value')) { + json_dict[input.name] = JSON.parse(input.getAttribute('data-origin-value')); + } else { + if (input.value !== "") { + var type = input.getAttribute('data-json-type'); + if (input.tagName === "SELECT" && input.value) { + // selection used for enums + json_dict[input.name] = JSON.parse(input.value); + } else if (type === 'number') { + json_dict[input.name] = parseFloat(input.value); + } else if (type === "integer") { + json_dict[input.name] = parseInt(input.value, 10); + } else if (type === "boolean") { + if (input.value === "true") { + json_dict[input.name] = true; + } else if (input.value === "false") { + json_dict[input.name] = false; + } + } else if (input.tagName === "TEXTAREA") { + if (input["data-format"] === "string") { + json_dict[input.name] = input.value; + } else { + json_dict[input.name] = input.value.split('\n'); + } } else { - json_dict[input.name] = input.value.split('\n'); + json_dict[input.name] = input.value; } - } else { - json_dict[input.name] = input.value; } } }); @@ -1275,7 +1523,20 @@ } } if (count_of_values === 0) { - return; + switch (g.props.type) { + case "string": + return ""; + case "number": + return null; + case "boolean": + return null; + case "array": + return []; + case "object": + return {}; + default: + return; + } } return multi_level_dict[""]; }); @@ -1322,7 +1583,7 @@ .push(function () { return g.element.setAttribute('data-json-property-name', new_name); }) - .push(undefined, function (error) { + .push(undefined, function () { // XXX notify user event.srcElement.value = name; event.srcElement.focus(); @@ -1443,7 +1704,7 @@ .declareAcquiredMethod("notifyInvalid", "notifyInvalid") .declareAcquiredMethod("checkValidity", "checkValidity") - .allowPublicAcquisition("notifyValid", function (arr, sub_scope) { + .allowPublicAcquisition("notifyValid", function () { return true; }) .allowPublicAcquisition("notifyChange", function (arr, sub_scope) { @@ -1461,6 +1722,8 @@ property_name = g.element.getAttribute('data-json-property-name'), schema = options.schema, root; + g.props.changed = false; + g.props.saveOrigValue = options.saveOrigValue; g.props.inputs = []; g.props.add_buttons = []; g.props.add_custom_data = {}; @@ -1481,12 +1744,12 @@ options.delete_button = !options.required; } } - if (options.top && !options.type && !schema.type) { - // XXX use "object" as type for support buggy - // slapos schemas where some times type absent - // i need remove it in future - options.type = "object"; + if (!options.type && schema && !schema.type) { + options.type = guessSchemaType(schema); } + // used for empty document generation + g.props.type = (schema && typeof schema.type === "string" && schema.type) || + options.type || getDocumentType(options.document); while (root.firstChild) { root.removeChild(root.firstChild); } @@ -1515,6 +1778,9 @@ var link = evt.target.getAttribute("data-error-link"), button_list = this.props.add_buttons, + field_list = this.props.inputs, + input, + changed = false, i; if (link) { location.href = link; @@ -1526,6 +1792,21 @@ return button_list[i].event(evt); } } + + for (i = 0; i < field_list.length; i = i + 1) { + if (evt.target === field_list[i]) { + input = evt.target; + if (input.hasAttribute('data-const-value')) { + input.value = input.getAttribute('data-const-value'); + input.setAttribute('data-origin-value', input.value); + input.removeAttribute('data-const-value'); + changed = true; + } + } + } + if (changed) { + return this.rootNotifyChange(); + } }) .onEvent('input', function (evt) { @@ -1536,10 +1817,21 @@ var gadget = this, field_list = this.props.inputs, i, + input, changed = false; // on form data field for (i = 0; i < field_list.length; i = i + 1) { if (evt.target === field_list[i]) { + input = evt.target; + if (input.hasAttribute('data-origin-value')) { + input.removeAttribute('data-origin-value'); + } + if (!input.hasAttribute("type")) { + if (["integer", "number"] + .indexOf(input.getAttribute('data-json-type')) >= 0) { + input.type = "number"; + } + } changed = true; } } -- 2.30.9 From 0ff97d423d68ec84fe12df0938ebcf56b10dc929 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Thu, 6 Sep 2018 16:46:05 +0300 Subject: [PATCH 35/49] erp5_json_form: update version from https://lab.nexedi.com/bk/rjs_json_form --- .../erp5_json_form/jsonform.gadget.js.js | 253 ++++++++++++++---- .../gadget_json_generated_form_child.js.js | 62 +++-- .../erp5_json_form/jsonform/tv4.js.js | 95 ++++++- 3 files changed, 323 insertions(+), 87 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index 57303850f68..aae09ba6364 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -5,6 +5,12 @@ "use strict"; var expandSchema; + function arrayIntersect(x, y) { + return x.filter(function (value) { + return y.indexOf(value) >= 0; + }); + } + function URLwithJio(url, base_url) { var urn_prefix, pathname, @@ -65,19 +71,40 @@ return target; } - function checkCircular(g, path, url) { - var required_stack, + function checkCircular(urls, path, url) { + var stack, idx, - prev_field_path = getMaxPathInDict(g.props.schema_required_urls, path); - required_stack = g.props.schema_required_urls[prev_field_path] || []; - idx = required_stack.indexOf(url); + prev_field_path = getMaxPathInDict(urls, path); + stack = urls[prev_field_path] || []; + idx = stack.indexOf(url); if (idx >= 0) { if (path === prev_field_path && idx === 0) { return; } - throw new Error("Circular reference detected"); + return true; + } + // copy and add url as first element + urls[path] = [url].concat(stack); + } + + function checkHardCircular(g, path, url) { + return checkCircular(g.props.schema_required_urls, path, url); + } + + function checkAndMarkSoftCircular(g, schema_arr, path, url) { + var ret = true; + // if schema_arr.length > 1 selection rendered in any case + // so we not need checkCircular and have small optimisation + if (schema_arr.length === 1) { + ret = checkCircular(g.props.schema_urls, path, url); + schema_arr[0].circular = ret; + } + if (ret) { + // if schema_arr.length > 1 selection rendered and loop break + // if circular found selection rendered and loop break + // so we can begin from start + g.props.schema_urls[path] = []; } - g.props.schema_required_urls[path] = [url].concat(required_stack); } function convertToRealWorldSchemaPath(g, path) { @@ -255,7 +282,9 @@ } queue .push(function (json) { - checkCircular(g, path, url); + if (checkHardCircular(g, path, url)) { + throw new Error("Circular reference detected"); + } return resolveLocalReference(json, hash); }); } @@ -299,17 +328,146 @@ return expandSchema(g, schema_part, path, $ref); }) .push(function (schema_arr) { - // if length array > 1 form rendered on demand already - // so not needed circular detection - if (schema_arr.length === 1) { - // XXX need smart circular detection in this place - schema_arr[0].circular = true; - } + checkAndMarkSoftCircular(g, schema_arr, path, url); return schema_arr; }); } - function allOf(g, schema_array, schema_path) { + function mergeSchemas(x, y, doesntcopy) { + if (x === true && y === true) { + return true; + } + if (x === false || y === false) { + return false; + } + var key, + p; + if (x === true) { + x = {}; + } else if (!doesntcopy) { + x = JSON.parse(JSON.stringify(x)); + } + if (y === true) { + y = {}; + } + for (key in y) { + if (y.hasOwnProperty(key)) { + if (x.hasOwnProperty(key)) { + switch (key) { + case "maxProperties": + case "maxLength": + case "maxItems": + case "maximum": + case "exclusiveMaximum": + if (y[key] < x[key]) { + x[key] = y[key]; + } + break; + case "minProperties": + case "minItems": + case "minLength": + case "minimum": + case "exclusiveMinimum": + if (x[key] < y[key]) { + x[key] = y[key]; + } + break; + case "additionalProperties": + case "additionalItems": + case "contains": + case "propertyNames": + mergeSchemas(x[key], y[key], true); + break; + case "items": + // XXX items can be array + mergeSchemas(x[key], y[key], true); + break; + case "contentEncoding": + case "contentMediaType": + if (x[key] !== y[key]) { + return false; + } + break; + case "multipleOf": + x[key] = x[key] * y[key]; + break; + case "type": + if (typeof x.type === "string") { + if (typeof y.type === "string") { + if (x.type !== y.type) { + return false; + } + } else if (y.type.indexOf(x.type) === -1) { + return false; + } + } else { + if (typeof y.type === "string") { + if (x.type.indexOf(y.type) === -1) { + return false; + } + } else { + x.type = arrayIntersect(x.type, y.type); + if (x.type.length === 0) { + return false; + } + } + } + break; + case "properties": + case "patternProperties": + for (p in y[key]) { + if (y[key].hasOwnProperty(p)) { + if (x[key].hasOwnProperty(p)) { + mergeSchemas(x[key][p], y[key][p], true); + } else { + x[key][p] = y[key][p]; + } + } + } + break; + case "pattern": + // XXX regex string merge + case "dependencies": + // XXX find solution how merge + x[key] = y[key]; + break; + case "required": + for (p = 0; p < y.required.length; p += 1) { + if (x.required.indexOf(y.required[p]) < 0) { + x.required.push(y.required[p]); + } + } + break; + case "uniqueItems": + x[key] = y[key]; + break; + case "allOf": + case "anyOf": + case "$ref": + case "id": + case "$id": + // XXX + break; + default: + // XXX + x[key] = y[key]; + } + } else { + switch (key) { + case "allOf": + case "anyOf": + case "$ref": + break; + default: + x[key] = y[key]; + } + } + } + } + return x; + } + + function allOf(g, schema_array, schema_path, base_schema) { return RSVP.Queue() .push(function () { var i, @@ -323,10 +481,8 @@ var i, x, y, - key, next_schema, schema, - schema_item, summ_arr; for (i = 0; i < arr.length - 1; i += 1) { summ_arr = []; @@ -334,56 +490,31 @@ for (y = 0; y < arr[i + 1].length; y += 1) { schema = arr[i][x].schema; next_schema = arr[i + 1][y].schema; - if (schema === true && next_schema === true) { - schema_item = { - schema: true, - schema_path: arr[i][x].schema_path - }; - } else if (schema === false || next_schema === false) { - schema_item = { - schema: false, - schema_path: arr[i][x].schema_path - }; - } else { - if (schema === true) { - schema = {}; - } - if (next_schema === true) { - next_schema = {}; - } - // copy before change - schema = JSON.parse(JSON.stringify(schema)); - for (key in next_schema) { - if (next_schema.hasOwnProperty(key)) { - if (schema.hasOwnProperty(key)) { - // XXX need use many many rules for merging - schema[key] = next_schema[key]; - } else { - schema[key] = next_schema[key]; - } - } - } - schema_item = { - schema: schema, - schema_path: arr[i][x].schema_path - }; - } - summ_arr.push(schema_item); + schema = mergeSchemas(schema, next_schema); + summ_arr.push({ + schema: schema, + // XXX we loss path arr[i + 1][y].schema_path + schema_path: arr[i][x].schema_path + }); } } arr[i + 1] = summ_arr; } - return arr[arr.length - 1]; + for (x = 0; x < summ_arr.length; x += 1) { + summ_arr[x].schema = mergeSchemas(summ_arr[x].schema, base_schema); + } + return summ_arr; }); } - function anyOf(g, schema_array, schema_path) { + function anyOf(g, schema, schema_path) { + var schema_array = schema.anyOf; return RSVP.Queue() .push(function () { var i, arr = []; for (i = 0; i < schema_array.length; i += 1) { - arr.push(expandSchema(g, schema_array[i], schema_path + '/anyOf/' + i.toString())); + arr.push(expandSchema(g, mergeSchemas(schema_array[i], schema), schema_path + '/anyOf/' + i.toString())); } return RSVP.all(arr); }) @@ -413,10 +544,10 @@ schema = true; } if (schema.anyOf !== undefined) { - return anyOf(g, schema.anyOf, schema_path); + return anyOf(g, schema, schema_path); } if (schema.allOf !== undefined) { - return allOf(g, schema.allOf, schema_path); + return allOf(g, schema.allOf, schema_path, schema); } if (schema.$ref) { return loadJSONSchema(g, schema.$ref, schema_path); @@ -627,11 +758,19 @@ "http://json-schema.org/draft-07/schema": "json-schema/schema7.json", "http://json-schema.org/schema": "json-schema/schema7.json" }; + // schema_urls[path] = [ + // stack urls + // "url1", + // "url2" + // ] + // used for break soft circular relation of schemas + g.props.schema_urls = {}; // schema_required_urls[path] = [ // stack required urls, on every unrequired field stack begining from [] // "url1", // "url2" // ] + // used for break hard circular relation of schemas g.props.schema_required_urls = {}; // schema_resolve_errors[schema_url] = { // schemaPath: local_schema_path, diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 859bec414f8..5374a265b82 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -199,12 +199,15 @@ return input; } - function render_const(schema, json_document) { + function render_const(g, schema, json_document) { var input = document.createElement("input"), ser_doc = JSON.stringify(json_document), ser_const = JSON.stringify(schema.const); input.setAttribute('readonly', true); if (json_document === undefined || deepEqual(json_document, schema.const)) { + if (json_document === undefined) { + g.props.changed = true; + } input.setAttribute('data-origin-value', ser_const); input.value = ser_const; } else { @@ -636,6 +639,13 @@ } } + if (json_document === undefined) { + if (schema.hasOwnProperty('default')) { + json_document = schema.default; + gadget.props.changed = true; + } + } + // XXX add failback rendering if json_document not array // input = render_textarea(schema, default_value, "array"); return RSVP.Queue() @@ -880,7 +890,7 @@ div_input.setAttribute("class", "input"); if (json_field.const !== undefined) { - input = render_const(json_field, default_value); + input = render_const(gadget, json_field, default_value); } else if (json_field.enum !== undefined) { input = render_enum(gadget, json_field, default_value); // XXX take in account existing type with enum @@ -888,7 +898,7 @@ } if (!input && type === "null") { - input = render_const({const: null}, default_value); + input = render_const(gadget, {const: null}, default_value); } if (!input && type === "boolean") { @@ -1208,7 +1218,12 @@ } if (default_dict === undefined) { - default_dict = {}; + if (json_field.hasOwnProperty('default')) { + default_dict = json_field.default; + g.props.changed = true; + } else { + default_dict = {}; + } } return expandProperties(g, json_field.properties, schema_path + '/properties/', required) @@ -1222,6 +1237,7 @@ if (properties.hasOwnProperty(key)) { schema_arr = properties[key]; s_o = schemaArrFilteredByDocument(schema_arr, default_dict[key]); + // XXX need schema merge with patternProperties passed key if (checkSchemaArrOneChoise(schema_arr)) { if (required.indexOf(key) >= 0) { used_properties[key] = false; @@ -1312,30 +1328,44 @@ }) .push(function () { var queue = RSVP.Queue(), + key, additionalProperties; + // XXX for pattern properties needs schemas merge for + // all passed patterns if (json_field.patternProperties !== undefined) { - // XXX need loop on any pattern properties - if (json_field.patternProperties['.*'] !== undefined) { - queue - .push(render_object_additionalProperty.bind(g, + for (key in json_field.patternProperties) { + if (json_field.patternProperties.hasOwnProperty(key)) { + if (key === ".*" || + key === "^.*$" || + key === ".*$" || + key === "^.*" + ) { + // additionalProperties nether used in this case + additionalProperties = false; + } + queue + .push(render_object_additionalProperty.bind(g, g, - ".* property", + key + " property", default_dict, path, - json_field.patternProperties['.*'], - schema_path + '/patternProperties/.*', + json_field.patternProperties[key], + schema_path + '/patternProperties/' + key, used_properties, element_append )) - .push(root_append); + .push(root_append); + } } } - if (json_field.additionalProperties === undefined) { - additionalProperties = true; - } else { - additionalProperties = json_field.additionalProperties; + if (additionalProperties === undefined) { + if (json_field.additionalProperties === undefined) { + additionalProperties = true; + } else { + additionalProperties = json_field.additionalProperties; + } } if (additionalProperties !== false) { queue diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js index 48513c229a4..820b4ab6fee 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js @@ -6,7 +6,11 @@ This code is released into the "public domain" by its author(s). Anybody may us If you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory. */ +/*global module, define*/ +/*jslint indent: 2, white: true*/ +/*jshint -W014: true, -W089: true, -W084: true, -W069: true*/ (function (global, factory) { + "use strict"; if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], factory); @@ -18,6 +22,7 @@ If you find a bug or make an improvement, it would be courteous to let the autho global.tv4 = factory(); } }(this, function () { +"use strict"; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys if (!Object.keys) { @@ -82,6 +87,7 @@ if(!Array.isArray) { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + /*jslint bitwise: true */ if (this === null) { throw new TypeError(); } @@ -262,7 +268,7 @@ function uriTemplateSubstitution(spec) { result += "="; } } - if (varSpec.truncate != null) { + if (varSpec.truncate !== null) { value = value.substring(0, varSpec.truncate); } result += shouldEscape ? encodeURIComponent(value).replace(/!/g, "%21"): notReallyPercentEncode(value); @@ -533,9 +539,22 @@ ValidatorContext.prototype.reset = function () { this.errors = []; }; +ValidatorContext.prototype.validateAllValidators = function validateAllValidators(data, schema, dataPointerPath) { + return this.validateBasic(data, schema, dataPointerPath) + || this.validateNumeric(data, schema, dataPointerPath) + || this.validateString(data, schema, dataPointerPath) + || this.validateArray(data, schema, dataPointerPath) + || this.validateObject(data, schema, dataPointerPath) + || this.validateCombinations(data, schema, dataPointerPath) + || this.validateHypermedia(data, schema, dataPointerPath) + || this.validateFormat(data, schema, dataPointerPath) + || this.validateDefinedKeywords(data, schema, dataPointerPath) + || null; +}; + ValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) { var topLevel; - if (!schema) { + if (schema === undefined || schema === true) { return null; } else if (schema instanceof ValidationError) { this.errors.push(schema); @@ -597,16 +616,7 @@ ValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, } var errorCount = this.errors.length; - var error = this.validateBasic(data, schema, dataPointerPath) - || this.validateNumeric(data, schema, dataPointerPath) - || this.validateString(data, schema, dataPointerPath) - || this.validateArray(data, schema, dataPointerPath) - || this.validateObject(data, schema, dataPointerPath) - || this.validateCombinations(data, schema, dataPointerPath) - || this.validateHypermedia(data, schema, dataPointerPath) - || this.validateFormat(data, schema, dataPointerPath) - || this.validateDefinedKeywords(data, schema, dataPointerPath) - || null; + var error = this.validateAllValidators(data, schema, dataPointerPath); if (topLevel) { while (this.scanned.length) { @@ -718,10 +728,16 @@ function recursiveCompare(A, B) { } ValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) { + if (schema === false && data !== undefined) { + return this.createError(ErrorCodes.BOOLEAN_SCHEMA_FALSE, {}, '', '', null, data, schema); + } var error; if (error = this.validateType(data, schema, dataPointerPath)) { return error.prefixWith(null, "type"); } + if (error = this.validateConst(data, schema, dataPointerPath)) { + return error.prefixWith(null, "const"); + } if (error = this.validateEnum(data, schema, dataPointerPath)) { return error.prefixWith(null, "type"); } @@ -752,6 +768,14 @@ ValidatorContext.prototype.validateType = function validateType(data, schema) { return this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join("/")}, '', '', null, data, schema); }; +ValidatorContext.prototype.validateConst = function validateConst(data, schema) { + if (schema.const === undefined || + recursiveCompare(data, schema.const)) { + return null; + } + return this.createError(ErrorCodes.CONST_NOT_EQUAL, {}, '', '', null, data, schema); +}; + ValidatorContext.prototype.validateEnum = function validateEnum(data, schema) { if (schema["enum"] === undefined) { return null; @@ -796,18 +820,24 @@ ValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema if (data < schema.minimum) { return this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}, '', '/minimum', null, data, schema); } - if (schema.exclusiveMinimum && data === schema.minimum) { + if (schema.exclusiveMinimum === true && data === schema.minimum) { return this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}, '', '/exclusiveMinimum', null, data, schema); } } + if ((typeof schema.exclusiveMinimum === "number") && data <= schema.exclusiveMinimum) { + return this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.exclusiveMinimum}, '', '/exclusiveMinimum', null, data, schema); + } if (schema.maximum !== undefined) { if (data > schema.maximum) { return this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}, '', '/maximum', null, data, schema); } - if (schema.exclusiveMaximum && data === schema.maximum) { + if (schema.exclusiveMaximum === true && data === schema.maximum) { return this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}, '', '/exclusiveMaximum', null, data, schema); } } + if ((typeof schema.exclusiveMaximum === "number") && data >= schema.exclusiveMaximum) { + return this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.exclusiveMaximum}, '', '/exclusiveMaximum', null, data, schema); + } return null; }; @@ -878,6 +908,7 @@ ValidatorContext.prototype.validateArray = function validateArray(data, schema, } return this.validateArrayLength(data, schema, dataPointerPath) || this.validateArrayUniqueItems(data, schema, dataPointerPath) + || this.validateArrayContains(data, schema, dataPointerPath) || this.validateArrayItems(data, schema, dataPointerPath) || null; }; @@ -903,6 +934,28 @@ ValidatorContext.prototype.validateArrayLength = function validateArrayLength(da return null; }; +ValidatorContext.prototype.validateArrayContains = function validateArrayContains(data, schema, dataPointerPath) { + if ((schema.contains === true && data.length > 0) || schema.contains === undefined) { + return null; + } + var error; + if (data.length === 0 || schema.contains === false) { + error = true; + } else { + for (var i = 0; i < data.length; i++) { + error = this.validateAllValidators(data[i], schema.contains, dataPointerPath + "/" + i); + if (!error) { + return null; + } + } + error = true; + } + if (error) { + return this.createError(ErrorCodes.ARRAY_CONTAINS, {}, '', '/contains', null, data, schema); + } + return null; +}; + ValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) { if (schema.uniqueItems) { for (var i = 0; i < data.length; i++) { @@ -1006,6 +1059,11 @@ ValidatorContext.prototype.validateObjectProperties = function validateObjectPro for (var key in data) { var keyPointerPath = dataPointerPath + "/" + key.replace(/~/g, '~0').replace(/\//g, '~1'); var foundMatch = false; + if (schema.propertyNames !== undefined && schema.propertyNames !== true) { + if (error = this.validateAllValidators(key, schema.propertyNames, keyPointerPath)) { + return this.createError(ErrorCodes.OBJECT_PROPERTY_NAMES, {key: key, error: error.message}, '', '/propertyNames', null, data, schema).prefixWith(key, null); + } + } if (schema.properties !== undefined && schema.properties[key] !== undefined) { foundMatch = true; if (error = this.validateAll(data[key], schema.properties[key], [key], ["properties", key], keyPointerPath)) { @@ -1375,6 +1433,8 @@ var ErrorCodes = { ONE_OF_MISSING: 11, ONE_OF_MULTIPLE: 12, NOT_PASSED: 13, + BOOLEAN_SCHEMA_FALSE: 14, + CONST_NOT_EQUAL: 15, // Numeric errors NUMBER_MULTIPLE_OF: 100, NUMBER_MINIMUM: 101, @@ -1392,11 +1452,13 @@ var ErrorCodes = { OBJECT_REQUIRED: 302, OBJECT_ADDITIONAL_PROPERTIES: 303, OBJECT_DEPENDENCY_KEY: 304, + OBJECT_PROPERTY_NAMES: 305, // Array errors ARRAY_LENGTH_SHORT: 400, ARRAY_LENGTH_LONG: 401, ARRAY_UNIQUE: 402, ARRAY_ADDITIONAL_ITEMS: 403, + ARRAY_CONTAINS: 404, // Custom/user-defined errors FORMAT_CUSTOM: 500, KEYWORD_CUSTOM: 501, @@ -1416,6 +1478,8 @@ var ErrorMessagesDefault = { ONE_OF_MISSING: "Data does not match any schemas from \"oneOf\"", ONE_OF_MULTIPLE: "Data is valid against more than one schema from \"oneOf\": indices {index1} and {index2}", NOT_PASSED: "Data matches schema from \"not\"", + BOOLEAN_SCHEMA_FALSE: "Schema does not allow any data", + CONST_NOT_EQUAL: "Data does not match schema.const", // Numeric errors NUMBER_MULTIPLE_OF: "Value {value} is not a multiple of {multipleOf}", NUMBER_MINIMUM: "Value {value} is less than minimum {minimum}", @@ -1433,11 +1497,13 @@ var ErrorMessagesDefault = { OBJECT_REQUIRED: "Missing required property: {key}", OBJECT_ADDITIONAL_PROPERTIES: "Additional properties not allowed", OBJECT_DEPENDENCY_KEY: "Dependency failed - key must exist: {missing} (due to key: {key})", + OBJECT_PROPERTY_NAMES: "Property name \"{key}\" does not match schema with error: {error}", // Array errors ARRAY_LENGTH_SHORT: "Array is too short ({length}), minimum {minimum}", ARRAY_LENGTH_LONG: "Array is too long ({length}), maximum {maximum}", ARRAY_UNIQUE: "Array items are not unique (indices {match1} and {match2})", ARRAY_ADDITIONAL_ITEMS: "Additional items not allowed", + ARRAY_CONTAINS: "Array are not contain item matching schema.contains", // Format errors FORMAT_CUSTOM: "Format validation failed ({message})", KEYWORD_CUSTOM: "Keyword failed: {key} ({message})", @@ -1462,6 +1528,7 @@ function ValidationError(code, params, dataPath, schemaPath, subErrors) { var err = new Error(this.message); this.stack = err.stack || err.stacktrace; if (!this.stack) { + /*jshint -W002: true*/ try { throw err; } -- 2.30.9 From b9313a0c0aab053f45150e7fc478e69b76c894ef Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 28 Sep 2018 09:54:33 +0000 Subject: [PATCH 36/49] erp5_json_form: update version from https://lab.nexedi.com/bk/rjs_json_form --- .../erp5_json_form/jsonform.gadget.js.js | 85 +++- .../gadget_json_generated_form_child.js.js | 446 ++++++++++-------- 2 files changed, 320 insertions(+), 211 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index aae09ba6364..647679589eb 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -346,6 +346,15 @@ x = {}; } else if (!doesntcopy) { x = JSON.parse(JSON.stringify(x)); + if (x.anyOf) { + delete x.anyOf; + } + if (x.oneOf) { + delete x.oneOf; + } + if (x.allOf) { + delete x.allOf; + } } if (y === true) { y = {}; @@ -443,6 +452,7 @@ break; case "allOf": case "anyOf": + case "oneOf": case "$ref": case "id": case "$id": @@ -456,6 +466,7 @@ switch (key) { case "allOf": case "anyOf": + case "oneOf": case "$ref": break; default: @@ -473,7 +484,7 @@ var i, arr = []; for (i = 0; i < schema_array.length; i += 1) { - arr.push(expandSchema(g, schema_array[i], schema_path + '/allOf/' + i.toString())); + arr.push(expandSchema(g, schema_array[i], schema_path + '/' + i.toString())); } return RSVP.all(arr); }) @@ -507,14 +518,13 @@ }); } - function anyOf(g, schema, schema_path) { - var schema_array = schema.anyOf; + function anyOf(g, schema_array, schema_path, base_schema) { return RSVP.Queue() .push(function () { var i, arr = []; for (i = 0; i < schema_array.length; i += 1) { - arr.push(expandSchema(g, mergeSchemas(schema_array[i], schema), schema_path + '/anyOf/' + i.toString())); + arr.push(expandSchema(g, schema_array[i], schema_path + '/' + i.toString())); } return RSVP.all(arr); }) @@ -528,6 +538,13 @@ // or(any, restricted, restricted, .. ) simplify to any return [arr[i][z]]; } + if (base_schema.title) { + arr[i][z].title = base_schema.title; + } + if (base_schema.description) { + arr[i][z].description = base_schema.description; + } + arr[i][z].schema = mergeSchemas(base_schema, arr[i][z].schema); schema_arr.push(arr[i][z]); } } @@ -544,10 +561,13 @@ schema = true; } if (schema.anyOf !== undefined) { - return anyOf(g, schema, schema_path); + return anyOf(g, schema.anyOf, schema_path + '/anyOf', schema); + } + if (schema.oneOf !== undefined) { + return anyOf(g, schema.oneOf, schema_path + '/oneOf', schema); } if (schema.allOf !== undefined) { - return allOf(g, schema.allOf, schema_path, schema); + return allOf(g, schema.allOf, schema_path + '/allOf', schema); } if (schema.$ref) { return loadJSONSchema(g, schema.$ref, schema_path); @@ -573,13 +593,29 @@ return RSVP.Queue() .push(function () { return [{ - title: ref || schema.title, + title: schema.title, + ref: ref, schema: schema, schema_path: schema_path }]; }); }; + function schema_arr_marker(schema_arr) { + var i; + // XXX need cleanup false schema before + for (i = 0; i < schema_arr.length; i += 1) { + if (!schema_arr[i].schema.hasOwnProperty('const')) { + schema_arr[0].is_arr_of_const = false; + break; + } + if (i === schema_arr.length - 1) { + schema_arr[0].is_arr_of_const = true; + } + } + return schema_arr; + } + function expandSchemaForField(g, schema, schema_path, for_required) { var required_stack, prev_field_path; @@ -590,7 +626,8 @@ required_stack = []; } g.props.schema_required_urls[schema_path] = required_stack; - return expandSchema(g, schema, schema_path); + return expandSchema(g, schema, schema_path) + .push(schema_arr_marker); } rJS(window) @@ -624,6 +661,7 @@ return json_document; }) .push(function (json_d) { + gadget.state.value = JSON.stringify(json_d); return tv4.validateMultiple(json_d, gadget.props.schema[""]); }) .push(function (validation) { @@ -727,14 +765,17 @@ }) .declareMethod('render', function (options) { - return this.changeState({ + var z = { key: options.key, - value: JSON.stringify(options.value), schema: JSON.stringify(options.schema), saveOrigValue: options.saveOrigValue, schema_url: options.schema_url, editable: options.editable === undefined ? true : options.editable - }); + }; + if (options.value !== undefined) { + z.value = JSON.stringify(options.value); + } + return this.changeState(z); }) .onStateChange(function () { var g = this, @@ -804,22 +845,21 @@ schema_url = g.state.schema_url || (json_document && json_document.$schema); if (schema_url) { - queue = loadJSONSchema(g, schema_url); + queue = loadJSONSchema(g, schema_url) + .push(schema_arr_marker); } } if (queue) { - return queue - .push(function (schema_arr) { - // XXX for root of form use first schema selection - return schema_arr[0].schema; - }); + return queue; } - return {}; + return [{ + schema: true, + schema_path: "" + }]; }) - .push(function (schema) { + .push(function (schema_arr) { return g.props.form_gadget.renderForm({ - schema: schema, - schema_path: "", + schema_arr: schema_arr, document: json_document, saveOrigValue: g.state.saveOrigValue, required: true, @@ -836,6 +876,9 @@ }) .push(function () { return g; + }) + .push(undefined, function (err) { + console.log(err); }); }) .allowPublicAcquisition("expandSchema", function (arr) { diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 5374a265b82..2ffaa831141 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -178,6 +178,65 @@ return input; } + function render_enum_with_title(g, schema_arr, json_document, selected_schema) { + var input = document.createElement("select"), + option, + i, + ser_value, + selected = false; + input.size = 1; + if (json_document === undefined && selected_schema !== undefined) { + json_document = selected_schema.schema.const; + } + if (schema_arr[0].schema.default) { + if (json_document === undefined) { + json_document = schema_arr[0].schema.default; + g.props.changed = true; + } + } else { + option = document.createElement("option"); + option.value = ""; + if (json_document === undefined) { + option.selected = true; + } + input.appendChild(option); + } + for (i = 0; i < schema_arr.length; i += 1) { + option = document.createElement("option"); + // XXX use number id for speedup + ser_value = JSON.stringify(schema_arr[i].schema.const); + option.value = ser_value; + if (schema_arr[i].schema.title) { + option.textContent = schema_arr[i].schema.title; + } else if (typeof schema_arr[i].schema.const === "string") { + option.textContent = schema_arr[i].schema.const; + } else { + option.textContent = ser_value; + } + if (deepEqual(schema_arr[i].schema.const, json_document)) { + option.selected = true; + selected = true; + } + input.appendChild(option); + } + if (json_document !== undefined && !selected) { + // save original json_document even if it + // not support with schema + // XXX element should be removed on first user interact + option = document.createElement("option"); + ser_value = JSON.stringify(json_document); + option.value = ser_value; + if (typeof json_document === "string") { + option.textContent = json_document; + } else { + option.textContent = ser_value; + } + option.selected = true; + input.appendChild(option); + } + return input; + } + function render_boolean(g, schema, json_document) { var input, schema_for_selection = { @@ -209,7 +268,11 @@ g.props.changed = true; } input.setAttribute('data-origin-value', ser_const); - input.value = ser_const; + if (schema.title) { + input.value = schema.title; + } else { + input.value = ser_const; + } } else { input.value = ser_doc + ' ≠ ' + ser_const; input.setAttribute('data-origin-value', ser_doc); @@ -273,9 +336,9 @@ type: options.type, required: options.required, delete_button: options.delete_button, - schema: options.schema_part, - schema_path: options.schema_path, - document: options.default_dict, + selected_schema: options.selected_schema, + schema_arr: options.schema_arr, + document: options.json_document, display_label: options.parent_type !== "array", saveOrigValue: g.props.saveOrigValue, scope: scope @@ -338,7 +401,9 @@ if (schema_arr.length === 1) { if (schema_arr[0].schema === true || !(schema_arr[0].schema.hasOwnProperty('type') || - schema_arr[0].schema.hasOwnProperty('enum'))) { + schema_arr[0].schema.hasOwnProperty('enum') || + schema_arr[0].schema.hasOwnProperty('const') + )) { return false; } if (schema_arr[0].schema.type instanceof Array) { @@ -346,17 +411,24 @@ } return true; } + if (schema_arr[0].is_arr_of_const) { + return true; + } return false; } - function checkSchemaSimpleType(schema) { - return [ - 'string', - 'integer', - 'number', - 'boolean', - 'null' - ].indexOf(schema.type) >= 0; + function checkSchemaSimpleType(schema_arr) { + // return true if rendering are not recursive + var schema = schema_arr[0].schema; + return schema_arr[0].is_arr_of_const || + schema.hasOwnProperty('const') || + [ + 'string', + 'integer', + 'number', + 'boolean', + 'null' + ].indexOf(schema.type) >= 0; } function convertExpandedProperties2array(properties) { @@ -371,6 +443,8 @@ // add propertyName to title if (schema_array[i].title && schema_array.length > 1) { schema_array[i].title = property_name + ' /' + schema_array[i].title; + } else if (schema_array[i].ref && schema_array.length > 1) { + schema_array[i].title = property_name + ' /' + schema_array[i].ref; } else { schema_array[i].title = property_name; } @@ -386,10 +460,12 @@ function schemaArrFilteredByDocument(schema_arr, json_document) { var i, flag, + circular = schema_arr[0].circular, ret_arr = [], schema; - if (schema_arr.length === 1) { - return schema_arr[0]; + if (schema_arr.length === 1 || + schema_arr[0].is_arr_of_const) { + return schema_arr; } if (json_document !== undefined) { for (i = 0; i < schema_arr.length; i += 1) { @@ -407,11 +483,12 @@ } if (ret_arr.length === 0) { // XXX find schema more compatible with document - return schema_arr[0]; + return schema_arr; } + ret_arr[0].circular = circular; + return ret_arr; } - // XXX if (ret_arr.length > 1) notify user - return ret_arr[0]; + return schema_arr; } function render_schema_selector(gadget, title, schema_arr, event, rerender) { @@ -455,7 +532,8 @@ description = schema_item.title; if (schema_item.schema === true || !(schema_item.schema.hasOwnProperty('type') || - schema_item.schema.hasOwnProperty('enum'))) { + schema_item.schema.hasOwnProperty('enum') || + schema_item.schema.hasOwnProperty('const'))) { generateItemsForAny(schema_item.property_name, schema_item.schema_path); } else if (getDocumentType(schema_item.schema.type) === "array") { description = description || schema_item.schema.description; @@ -658,7 +736,6 @@ .push(function (arr) { var queue = RSVP.Queue(), i, - schema_path_item = schema_path + '/items', schema_arr_arr = arr[0], additionalItems = arr[1], schema_arr = schema_arr_arr, @@ -669,10 +746,8 @@ if (is_items_arr) { if (i < schema_arr_arr.length) { schema_arr = schema_arr_arr[i]; - schema_path_item = schema_path + '/items/' + i; } else { schema_arr = additionalItems; - schema_path_item = schema_path + '/additionalItems'; } } queue @@ -680,9 +755,8 @@ addSubForm.bind(gadget, { gadget: gadget, parent_type: 'array', - schema_path: schema_path_item, - schema_part: schema_arr, - default_dict: json_document[i], + schema_arr: schema_arr, + json_document: json_document[i], required: i < minItems }) ) @@ -707,8 +781,7 @@ addSubForm.bind(gadget, { gadget: gadget, parent_type: 'array', - schema_path: schema_arr[0].schema_path, - schema_part: schema_arr[0].schema, + schema_arr: schema_arr, required: true }) ) @@ -728,8 +801,8 @@ gadget: gadget, parent_type: 'array', type: value.type, - schema_path: value.schema_path, - schema_part: value.schema + selected_schema: value, + schema_arr: schema_arr }) .push(element_append); })); @@ -741,8 +814,7 @@ addSubForm.bind(gadget, { gadget: gadget, parent_type: 'array', - schema_path: schema_arr[0].schema_path, - schema_part: schema_arr[0].schema, + schema_arr: schema_arr, required: true }) ) @@ -757,8 +829,8 @@ gadget: gadget, parent_type: 'array', type: value.type, - schema_path: value.schema_path, - schema_part: value.schema + selected_schema: value, + schema_arr: schema_arr }) .push(element_append); })); @@ -775,7 +847,7 @@ }); } - function render_field(gadget, key, path, json_field, default_value, root, schema_path, options) { + function render_field(gadget, property_name, path, schema_arr, json_document, root, options) { var type, div, delete_button, @@ -785,64 +857,76 @@ span_info, error_message, input, + schema, + schema_path, + schema_ob, first_path, type_changed, queue = RSVP.Queue(); - if (json_field instanceof Array) { - json_field = schemaArrFilteredByDocument(json_field, default_value); - schema_path = json_field.schema_path; - json_field = json_field.schema; + if (options.selected_schema) { + schema_ob = options.selected_schema; + } else { + // XXX if (ret_arr.length > 1) notify user + schema_ob = schemaArrFilteredByDocument(schema_arr, json_document)[0]; + } + schema = schema_ob.schema; + schema_path = schema_ob.schema_path; + + if (schema_path === '/') { + schema_path = ''; } options = options || {}; type = options.type; - if (path && key) { - first_path = path + encodeJsonPointer(key); + if (path && property_name) { + first_path = path + encodeJsonPointer(property_name); } else { first_path = ""; } - if (json_field === undefined) { - json_field = getDocumentSchema(default_value); + if (schema === undefined) { + schema = getDocumentSchema(json_document); } - if (getDocumentType(json_field.type) === "string") { - type = json_field.type; + if (getDocumentType(schema.type) === "string") { + type = schema.type; } else if (type === undefined && - default_value === undefined && - getDocumentType(json_field.type) === "array") { - type = json_field.type[0]; + json_document === undefined && + getDocumentType(schema.type) === "array") { + type = schema.type[0]; } if (["object", "array"].indexOf(type) >= 0 && - !(path !== "" && default_value === undefined) && - getDocumentType(default_value) !== type) { + !(path !== "" && json_document === undefined) && + getDocumentType(json_document) !== type) { if (gadget.props.saveOrigValue) { // XXX is not useful for user // only for tests - json_field = { - const: default_value + schema = { + const: json_document }; } else { gadget.props.changed = true; } } - if (type === undefined && default_value !== undefined) { - type = getDocumentType(default_value); + if (type === undefined && json_document !== undefined) { + type = getDocumentType(json_document); } if (typeof type === "string") { // it's only for simple types so we not use // complex type detection - type_changed = default_value !== undefined && - typeof default_value !== type; + type_changed = json_document !== undefined && + typeof json_document !== type; } div = document.createElement("div"); div.setAttribute("class", "jsonformfield ui-field-contain"); - div.title = json_field.description; - // if (key && !first_path) { + if (schema.description) { + div.title = schema.description; + } + // if (property_name && !first_path) { if (options.delete_button === true) { delete_button = createElement("span", {"class": "ui-btn-icon-top ui-icon-trash-o"} @@ -861,77 +945,78 @@ div.appendChild(delete_button); } } - if (false) { - // XXX; - label = document.createElement("input"); - label.value = key; - gadget.props.property_name_edit = label; - } else { - label_text = [key, json_field.title] - .filter(function (v) { return v; }) - .join(" ") - // use non-breaking hyphen - .replace(/-/g, "‑"); - if (label_text) { - if (options.top) { - label = document.createElement("span"); - label.textContent = label_text; - root.appendChild(label); - } else { - label = document.createElement("label"); - label.textContent = label_text; - div.appendChild(label); - } + label_text = [property_name, schema_ob.title] + .filter(function (v) { return v; }) + .join(" ") + // use non-breaking hyphen + .replace(/-/g, "‑"); + if (property_name || options.top) { + if (options.top) { + label = document.createElement("span"); + label.textContent = label_text; + root.appendChild(label); + } else { + label = document.createElement("label"); + label.textContent = label_text; + div.appendChild(label); } + } + div_input = document.createElement("div"); div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/'); div_input.setAttribute("class", "input"); - if (json_field.const !== undefined) { - input = render_const(gadget, json_field, default_value); - } else if (json_field.enum !== undefined) { - input = render_enum(gadget, json_field, default_value); + // render input begin + + if (!input && schema_arr[0].is_arr_of_const) { + input = render_enum_with_title(gadget, schema_arr, json_document, options.selected_schema); + } + if (!input && schema.const !== undefined) { + input = render_const(gadget, schema, json_document); + } + if (!input && schema.enum !== undefined) { + input = render_enum(gadget, schema, json_document); // XXX take in account existing type with enum type_changed = false; } if (!input && type === "null") { - input = render_const(gadget, {const: null}, default_value); + input = render_const(gadget, {const: null}, json_document); } if (!input && type === "boolean") { - input = render_boolean(gadget, json_field, default_value); + input = render_boolean(gadget, schema, json_document); } if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) { - if (json_field.contentMediaType === "text/plain") { - input = render_textarea(default_value, "string"); + if (schema.contentMediaType === "text/plain") { + input = render_textarea(json_document, "string"); } else { input = document.createElement("input"); - if (default_value !== undefined) { - if (typeof default_value === "object") { - input.value = JSON.stringify(default_value); + if (json_document !== undefined) { + if (typeof json_document === "object") { + input.value = JSON.stringify(json_document); } else { - input.value = default_value; + input.value = json_document; } } if (type === "integer" || type === "number") { - if (default_value === undefined && typeof json_field.default === "number") { - input.value = json_field.default; + if (json_document === undefined && typeof schema.default === "number") { + input.value = schema.default; gadget.props.changed = true; } input.setAttribute("data-json-type", type); - if (default_value === undefined || default_value === null || - typeof default_value === "number") { + if (json_document === undefined || json_document === null || + typeof json_document === "number") { input.type = "number"; } if (type === "integer") { input.setAttribute("step", "1"); - if (typeof default_value === "number" && - parseInt(default_value, 10) !== default_value) { + if (typeof json_document === "number" && + parseInt(json_document, 10) !== json_document) { // original json_document contain float schema // limit integer we can save original document type_changed = true; @@ -940,16 +1025,36 @@ if (type === "number") { input.setAttribute("step", "any"); } + if (schema.multipleOf && schema.multipleOf >= 0) { + input.step = schema.multipleOf; + } + if (schema.minimum && + // step work from min value so we can't + // use min if min not multipleOf step + !(schema.multipleOf && + (schema.minimum % schema.multipleOf) !== 0)) { + input.min = schema.minimum; + } + if (schema.maximum) { + input.max = schema.maximum; + } } else { - if (default_value === undefined && typeof json_field.default === "string") { - input.value = json_field.default; + if (json_document === undefined && typeof schema.default === "string") { + input.value = schema.default; gadget.props.changed = true; } input.type = "text"; - if (json_field.pattern) { - input.pattern = json_field.pattern; + if (schema.pattern) { + input.pattern = schema.pattern; + } else if (schema.minLength) { + // minLength absent in html5 so + // use pattern for this task + input.pattern = ".{" + schema.minLength + ",}"; + } + if (schema.maxLength) { + input.maxLength = schema.maxLength; } - if (json_field.format === 'uri') { + if (schema.format === 'uri') { input.type = "url"; input.spellcheck = false; } @@ -960,8 +1065,8 @@ if (!input && type === "array") { queue = render_array( gadget, - json_field, - default_value, + schema, + json_document, div_input, first_path + '/', schema_path @@ -973,8 +1078,8 @@ .push(function () { return render_object( gadget, - json_field, - default_value, + schema, + json_document, div_input, first_path + '/', schema_path @@ -989,7 +1094,7 @@ input.name = first_path; input.required = options.required; if (type_changed) { - input.setAttribute('data-origin-value', JSON.stringify(default_value)); + input.setAttribute('data-origin-value', JSON.stringify(json_document)); } // XXX for gui //input.setAttribute("class", "slapos-parameter"); @@ -999,9 +1104,11 @@ div.setAttribute("data-json-type", type); } - if (json_field.info !== undefined) { + // render input end + + if (schema.info !== undefined) { span_info = document.createElement("span"); - span_info.textContent = json_field.info; + span_info.textContent = schema.info; div_input.appendChild(span_info); } error_message = document.createElement("span"); @@ -1024,7 +1131,7 @@ div = document.createElement("div"); div.setAttribute("class", "jsonformfield"); - // div.title = json_field.description; + // div.title = schema.description; div_input = document.createElement("div"); div_input.setAttribute("class", "input"); @@ -1047,9 +1154,8 @@ gadget: g, property_name: property_name, path: path, - schema_path: schema_path, - schema_part: schema_arr, - default_dict: json_document[property_name] + schema_arr: schema_arr, + json_document: json_document[property_name] }) ) .push(element_append); @@ -1062,8 +1168,7 @@ element: input, path: path, type: value.type, - schema_path: value.schema_path, - schema_part: value.schema + schema_arr: [value] }) .push(element_append); }); @@ -1197,9 +1302,9 @@ return true; } - render_object = function (g, json_field, default_dict, root, path, schema_path) { - var required = json_field.required || [], - schema_editor = checkSchemaIsMetaSchema(json_field), + render_object = function (g, schema, json_document, root, path, schema_path) { + var required = schema.required || [], + schema_editor = checkSchemaIsMetaSchema(schema), used_properties = {}, properties, selector = {}; @@ -1217,57 +1322,56 @@ root.appendChild(child); } - if (default_dict === undefined) { - if (json_field.hasOwnProperty('default')) { - default_dict = json_field.default; + if (json_document === undefined) { + if (schema.hasOwnProperty('default')) { + json_document = schema.default; g.props.changed = true; } else { - default_dict = {}; + json_document = {}; } } - return expandProperties(g, json_field.properties, schema_path + '/properties/', required) + return expandProperties(g, schema.properties, schema_path + '/properties/', required) .push(function (ret) { var schema_arr, q = RSVP.Queue(), - s_o, + filtered_schema_arr, key; properties = ret; for (key in properties) { if (properties.hasOwnProperty(key)) { schema_arr = properties[key]; - s_o = schemaArrFilteredByDocument(schema_arr, default_dict[key]); + filtered_schema_arr = schemaArrFilteredByDocument(schema_arr, json_document[key]); // XXX need schema merge with patternProperties passed key if (checkSchemaArrOneChoise(schema_arr)) { if (required.indexOf(key) >= 0) { used_properties[key] = false; q.push(render_field.bind(g, g, key, path, - s_o.schema, default_dict[key], root, s_o.schema_path, {required: true}) + filtered_schema_arr, json_document[key], root, {required: true}) ); } if (!used_properties.hasOwnProperty(key) && !schema_editor && - (checkSchemaSimpleType(s_o.schema) || !s_o.circular) + (checkSchemaSimpleType(filtered_schema_arr) || !filtered_schema_arr[0].circular) ) { used_properties[key] = false; q.push(render_field.bind(g, g, key, path, - s_o.schema, default_dict[key], root, s_o.schema_path, { + filtered_schema_arr, json_document[key], root, { required: false, delete_button: false })); } } if (!used_properties.hasOwnProperty(key) && - default_dict.hasOwnProperty(key)) { + json_document.hasOwnProperty(key)) { used_properties[key] = ""; q.push( addSubForm.bind(g, { gadget: g, property_name: key, path: path, - schema_path: s_o.schema_path, - schema_part: s_o.schema, - default_dict: default_dict[key] + schema_arr: filtered_schema_arr, + json_document: json_document[key] }) ) .push(root_append); @@ -1285,8 +1389,7 @@ property_name: value.property_name, path: path, type: value.type, - schema_path: value.schema_path, - schema_part: value.schema + schema_arr: [value] }) .push(function (element) { var s_e = selector.element; @@ -1333,9 +1436,9 @@ // XXX for pattern properties needs schemas merge for // all passed patterns - if (json_field.patternProperties !== undefined) { - for (key in json_field.patternProperties) { - if (json_field.patternProperties.hasOwnProperty(key)) { + if (schema.patternProperties !== undefined) { + for (key in schema.patternProperties) { + if (schema.patternProperties.hasOwnProperty(key)) { if (key === ".*" || key === "^.*$" || key === ".*$" || @@ -1348,23 +1451,23 @@ .push(render_object_additionalProperty.bind(g, g, key + " property", - default_dict, + json_document, path, - json_field.patternProperties[key], + schema.patternProperties[key], schema_path + '/patternProperties/' + key, used_properties, element_append - )) + )) .push(root_append); } } } if (additionalProperties === undefined) { - if (json_field.additionalProperties === undefined) { + if (schema.additionalProperties === undefined) { additionalProperties = true; } else { - additionalProperties = json_field.additionalProperties; + additionalProperties = schema.additionalProperties; } } if (additionalProperties !== false) { @@ -1372,7 +1475,7 @@ .push(render_object_additionalProperty.bind(g, g, "additional property", - default_dict, + json_document, path, additionalProperties, schema_path + '/additionalProperties', @@ -1387,8 +1490,8 @@ .push(function () { var key, queue = RSVP.Queue(); - for (key in default_dict) { - if (default_dict.hasOwnProperty(key)) { + for (key in json_document) { + if (json_document.hasOwnProperty(key)) { if (!used_properties.hasOwnProperty(key)) { queue .push( @@ -1396,9 +1499,11 @@ gadget: g, property_name: key, path: path, - schema_path: "", - schema_part: undefined, - default_dict: default_dict[key] + schema_arr: [{ + schema: undefined, + schema_path: "" + }], + json_document: json_document[key] }) ) .push(root_append); @@ -1583,42 +1688,6 @@ g.options = {}; }) .declareAcquiredMethod("rootNotifyChange", "rootNotifyChange") - .declareAcquiredMethod("renameChildrenParent", "renameChildren") - .allowPublicAcquisition("renameChildren", function (opt_arr, scope) { - var property_name, - objects = this.props.objects, - new_name = opt_arr[0], - element = getSubGadgetElement(this, scope), - parent = element.getAttribute('data-json-parent'); - if (objects.hasOwnProperty(parent)) { - parent = objects[parent]; - if (parent.hasOwnProperty(new_name)) { - throw new Error("property already exist"); - } - // XXX validate property if property pattern - for (property_name in parent) { - if (parent.hasOwnProperty(property_name) && parent[property_name] === scope) { - delete parent[property_name]; - parent[new_name] = scope; - return new_name; - } - } - throw new Error("gadget not found for renaming"); - } - }) - .declareMethod("rename", function (new_name, event) { - var g = this, - name = g.element.getAttribute('data-json-property-name'); - return this.renameChildrenParent(new_name) - .push(function () { - return g.element.setAttribute('data-json-property-name', new_name); - }) - .push(undefined, function () { - // XXX notify user - event.srcElement.value = name; - event.srcElement.focus(); - }); - }) .declareAcquiredMethod("selfRemove", "deleteChildren") .allowPublicAcquisition("deleteChildren", function (arr, scope) { var g = this, @@ -1750,7 +1819,7 @@ .declareMethod('renderForm', function (options) { var g = this, property_name = g.element.getAttribute('data-json-property-name'), - schema = options.schema, + schema = options.schema_arr !== undefined && options.schema_arr[0].schema, root; g.props.changed = false; g.props.saveOrigValue = options.saveOrigValue; @@ -1787,10 +1856,11 @@ g.props.updatePropertySelectors = true; g.props.current_document = options.document; } - return render_field(g, property_name, "", schema, - options.document, root, options.schema_path, + return render_field(g, property_name, "", options.schema_arr, + options.document, root, { type: options.type, + selected_schema: options.selected_schema, required: options.required, delete_button: options.delete_button, top: options.top @@ -1840,10 +1910,6 @@ }) .onEvent('input', function (evt) { - if (evt.target === this.props.property_name_edit) { - return this.rename(this.props.property_name_edit.value, evt); - } - var gadget = this, field_list = this.props.inputs, i, -- 2.30.9 From 4571c9426734b4219bf20f0200f58f6bf9bdf404 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 3 Oct 2018 21:54:19 +0000 Subject: [PATCH 37/49] erp5_officejs: schema_editor: schema reference update if file uploaded --- .../gadget_officejs_jio_json_schema_view.js.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js index 6c96d6b520b..bfc656c207f 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_schema_view.js.js @@ -43,10 +43,11 @@ .push(function (content) { var list = [], blob; - if (content.data_file_upload) { - blob = jIO.util.dataURItoBlob(content.data_file_upload.url); - content.title = content.data_file_upload.file_name; - delete content.data_file_upload; + if (content.file) { + blob = jIO.util.dataURItoBlob(content.file.url); + content.title = content.title || content.file.file_name; + content.reference = content.reference || content.file.file_name; + delete content.file; list = [ gadget.updateDocument(content), gadget.jio_putAttachment(gadget.state.jio_key, 'data', blob) @@ -124,7 +125,7 @@ "css_class": "", "required": 0, "editable": 1, - "key": "data_file_upload", + "key": "file", "hidden": 0, "accept": "application/json", "type": "FileField" @@ -178,4 +179,4 @@ }); }); }); -}(window, jIO, rJS, RSVP)); +}(window, jIO, rJS, RSVP)); \ No newline at end of file -- 2.30.9 From d9d69902bc70ed8981b3983aca359e4e9030f5a7 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Thu, 4 Oct 2018 01:04:16 +0300 Subject: [PATCH 38/49] erp5_officejs: schema_editor: use Query builder instead string concatination. thanks @jerome --- ...dget_officejs_jio_json_document_view.js.js | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js index b0c11fc6f0c..57dc1665b53 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js @@ -1,7 +1,7 @@ -/*global window, rJS, RSVP, jIO, URL, +/*global window, rJS, RSVP, jIO, URL, Query, promiseEventListener, document*/ /*jslint nomen: true, indent: 2, maxerr: 3 */ -(function (window, jIO, rJS, RSVP) { +(function (window, jIO, rJS, RSVP, Query) { "use strict"; rJS(window) @@ -88,11 +88,25 @@ url = arr[0], reference, args; - // return g.jio_getAttachment(id, "data", {format: "json"}); if (url.startsWith("urn:jio:reference?")) { reference = decodeURIComponent(url.replace("urn:jio:reference?", "")); args = { - query: '(portal_type: "JSON Schema") AND ((reference: "' + reference + '"))', + query: Query.objectToSearchText({ + type: "complex", + operator: "AND", + query_list: [ + { + key: "portal_type", + type: "simple", + value: "JSON Schema" + }, + { + key: "reference", + type: "simple", + value: reference + } + ] + }), limit: [0, 1], select_list: [], sort_on: [["modification_date", "descending"]] @@ -199,4 +213,4 @@ }); }); }); -}(window, jIO, rJS, RSVP)); +}(window, jIO, rJS, RSVP, Query)); -- 2.30.9 From bba6c4fd840affe48e26c0bef55ccd48ab08bf07 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Thu, 4 Oct 2018 01:06:50 +0300 Subject: [PATCH 39/49] erp5_officejs: schema_editor: create undefined json_document insteat clean string --- ...dget_erp5_page_ojs_add_json_document.js.js | 21 ++++++++----------- ...dget_officejs_jio_json_document_view.js.js | 5 ++++- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js index 1f0b37d4fe2..3a1bd5a6581 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js @@ -1,6 +1,6 @@ /*global window, rJS, RSVP */ /*jslint nomen: true, indent: 2, maxerr: 3 */ -(function (window, rJS, RSVP, Blob) { +(function (window, rJS, RSVP) { "use strict"; var content_type = { @@ -47,16 +47,13 @@ return gadget.jio_post(ret); }) .push(function (id) { - return gadget.jio_putAttachment(id, 'data', new Blob(['""'])) - .push(function () { - return gadget.redirect({ - command: 'display', - options: { - jio_key: id, - editable: true - } - }); - }); + return gadget.redirect({ + command: 'display', + options: { + jio_key: id, + editable: true + } + }); }); }); -}(window, rJS, RSVP, Blob)); +}(window, rJS, RSVP)); diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js index 57dc1665b53..a06cf04847c 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js @@ -125,7 +125,10 @@ .push(function () { return RSVP.all([ gadget.getDeclaredGadget('form_view'), - gadget.jio_getAttachment(gadget.state.jio_key, 'data', {format: "json"}), + gadget.jio_getAttachment(gadget.state.jio_key, 'data', {format: "json"}) + .push(undefined, function () { + return; + }), gadget.jio_get(gadget.state.doc.schema) ]); }) -- 2.30.9 From 31097adad16d4f2416206b3b3606dd06d4b8cead Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Thu, 4 Oct 2018 01:07:59 +0300 Subject: [PATCH 40/49] erp5_officejs: schema_editor: jslint fix --- ...dget_erp5_page_ojs_add_json_document.js.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js index 3a1bd5a6581..a11ef9cf04a 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js @@ -4,16 +4,15 @@ "use strict"; var content_type = { - Spreadsheet: 'application/x-asc-spreadsheet', - Presentation: 'application/x-asc-presentation', - Text: 'application/x-asc-text' - }; - - var file_ext = { - Spreadsheet: 'xlsy', - Presentation: 'ppty', - Text: 'docy' - }; + Spreadsheet: 'application/x-asc-spreadsheet', + Presentation: 'application/x-asc-presentation', + Text: 'application/x-asc-text' + }, + file_ext = { + Spreadsheet: 'xlsy', + Presentation: 'ppty', + Text: 'docy' + }; rJS(window) ///////////////////////////////////////////////////////////////// -- 2.30.9 From 420c2a329e7ff6f97da1a2bbf0b84c368ad8ed21 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 5 Oct 2018 01:14:10 +0300 Subject: [PATCH 41/49] erp5_json_form and erp5_officejs: rename downloadJSON() to resolveExternalReference() thanks @jerome --- .../portal_skins/erp5_json_form/jsonform.gadget.js.js | 4 ++-- .../gadget_officejs_jio_json_document_view.js.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index 647679589eb..c419693c9da 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -272,7 +272,7 @@ if (download_url.startsWith("urn:jio:")) { queue = RSVP.Queue() .push(function () { - return g.downloadJSON(download_url); + return g.resolveExternalReference(download_url); }); } else { queue = RSVP.Queue() @@ -636,7 +636,7 @@ g.props = {}; g.options = {}; }) - .declareAcquiredMethod("downloadJSON", "downloadJSON") + .declareAcquiredMethod("resolveExternalReference", "resolveExternalReference") .declareAcquiredMethod("notifyChange", "notifyChange") .allowPublicAcquisition("rootNotifyChange", function () { this.props.changed = true; diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js index a06cf04847c..614490ddd54 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_officejs_jio_json_document_view.js.js @@ -83,7 +83,7 @@ return this.element.querySelector('button[type="submit"]').click(); }) - .allowPublicAcquisition("downloadJSON", function (arr) { + .allowPublicAcquisition("resolveExternalReference", function (arr) { var g = this, url = arr[0], reference, -- 2.30.9 From dd8d76f4b1f4288cec5466104cc19739aff7c49f Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 12 Oct 2018 11:16:23 +0000 Subject: [PATCH 42/49] erp5_json_form: update version from https://lab.nexedi.com/bk/rjs_json_form --- .../erp5_json_form/jsonform.gadget.js.js | 23 +++- .../gadget_json_generated_form_child.js.js | 125 +++++++++++------- 2 files changed, 94 insertions(+), 54 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index c419693c9da..ddcac808bbb 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -342,10 +342,27 @@ } var key, p; + if (x.hasOwnProperty("$ref") || + y.hasOwnProperty("$ref")) { + if (doesntcopy) { + // we need reference resolve before merging + // so allOf schema returned and array item or object field + // run merging on next iteration. + return { + allOf: [ + x, + y + ] + }; + } else { + throw new Error("all reference must be resolved before merge run on first recursion level"); + } + } if (x === true) { x = {}; } else if (!doesntcopy) { x = JSON.parse(JSON.stringify(x)); + // cleanup already walked schema variations if (x.anyOf) { delete x.anyOf; } @@ -385,11 +402,11 @@ case "additionalItems": case "contains": case "propertyNames": - mergeSchemas(x[key], y[key], true); + x[key] = mergeSchemas(x[key], y[key], true); break; case "items": // XXX items can be array - mergeSchemas(x[key], y[key], true); + x[key] = mergeSchemas(x[key], y[key], true); break; case "contentEncoding": case "contentMediaType": @@ -427,7 +444,7 @@ for (p in y[key]) { if (y[key].hasOwnProperty(p)) { if (x[key].hasOwnProperty(p)) { - mergeSchemas(x[key][p], y[key][p], true); + x[key][p] = mergeSchemas(x[key][p], y[key][p], true); } else { x[key][p] = y[key][p]; } diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 2ffaa831141..ef68ce3484c 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -921,56 +921,8 @@ typeof json_document !== type; } - div = document.createElement("div"); - div.setAttribute("class", "jsonformfield ui-field-contain"); - if (schema.description) { - div.title = schema.description; - } - // if (property_name && !first_path) { - if (options.delete_button === true) { - delete_button = createElement("span", - {"class": "ui-btn-icon-top ui-icon-trash-o"} - ); - gadget.props.delete_button = delete_button; - div.appendChild(delete_button); - } else if (options.top !== true) { - if (options.required) { - delete_button = createElement("span", - {"class": "ui-btn-icon-top ui-icon-circle"} - ); - div.appendChild(delete_button); - } else { - delete_button = createElement("span"); - delete_button.innerHTML = " "; - div.appendChild(delete_button); - } - } - - label_text = [property_name, schema_ob.title] - .filter(function (v) { return v; }) - .join(" ") - // use non-breaking hyphen - .replace(/-/g, "‑"); - if (property_name || options.top) { - if (options.top) { - label = document.createElement("span"); - label.textContent = label_text; - root.appendChild(label); - } else { - label = document.createElement("label"); - label.textContent = label_text; - div.appendChild(label); - } - - } - - div_input = document.createElement("div"); - div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/'); - div_input.setAttribute("class", "input"); - // render input begin - - if (!input && schema_arr[0].is_arr_of_const) { + if (!input && schema_arr[0].is_arr_of_const && schema_arr.length > 1) { input = render_enum_with_title(gadget, schema_arr, json_document, options.selected_schema); } if (!input && schema.const !== undefined) { @@ -1060,7 +1012,59 @@ } } } + if (schema.default !== undefined) { + input.setAttribute('data-default-value', JSON.stringify(schema.default)); + input.placeholder = schema.default; + } } + // render input end + + // html layout render begin + div = document.createElement("div"); + div.setAttribute("class", "jsonformfield ui-field-contain"); + if (schema.description) { + div.title = schema.description; + } + // if (property_name && !first_path) { + if (options.delete_button === true) { + delete_button = createElement("span", + {"class": "ui-btn-icon-top ui-icon-trash-o"} + ); + gadget.props.delete_button = delete_button; + div.appendChild(delete_button); + } else if (options.top !== true) { + if (options.required) { + delete_button = createElement("span", + {"class": "ui-btn-icon-top ui-icon-circle"} + ); + div.appendChild(delete_button); + } else { + delete_button = createElement("span"); + delete_button.innerHTML = " "; + div.appendChild(delete_button); + } + } + + label_text = [property_name, schema_ob.title] + .filter(function (v) { return v; }) + .join(" ") + // use non-breaking hyphen + .replace(/-/g, "‑"); + if (property_name || options.top) { + if (options.top) { + label = document.createElement("span"); + label.textContent = label_text; + root.appendChild(label); + } else { + label = document.createElement("label"); + label.textContent = label_text; + div.appendChild(label); + } + } + + div_input = document.createElement("div"); + div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/'); + div_input.setAttribute("class", "input"); if (!input && type === "array") { queue = render_array( @@ -1100,12 +1104,11 @@ //input.setAttribute("class", "slapos-parameter"); div_input.appendChild(input); } else { + div.setAttribute("data-parent-scope", gadget.element.getAttribute("data-gadget-scope")); div.setAttribute("data-json-path", first_path + '/'); div.setAttribute("data-json-type", type); } - // render input end - if (schema.info !== undefined) { span_info = document.createElement("span"); span_info.textContent = schema.info; @@ -1116,6 +1119,7 @@ error_message.hidden = true; div_input.appendChild(error_message); div.appendChild(div_input); + // html layout render end return queue .push(function () { @@ -1322,6 +1326,11 @@ root.appendChild(child); } + if (JSON.stringify(schema.default) === '{}') { + // save default value as attribute only for empty values + root.parentElement.setAttribute("data-default-value", '{}'); + } + if (json_document === undefined) { if (schema.hasOwnProperty('default')) { json_document = schema.default; @@ -1585,6 +1594,18 @@ }); } + + // set empty object if default value require this + array = g.element + .querySelectorAll("div[data-parent-scope='" + + g.element.getAttribute("data-gadget-scope") + "']"); + for (i = 0; i < array.length; i += 1) { + path = array[i].getAttribute("data-json-path").slice(0, -1); + if (array[i].getAttribute("data-default-value") === "{}") { + convertOnMultiLevel(multi_level_dict, path, {}); + } + } + for (path in options.arrays) { if (options.arrays.hasOwnProperty(path)) { array = options.arrays[path] @@ -1649,6 +1670,8 @@ } else { json_dict[input.name] = input.value; } + } else if (input.hasAttribute('data-default-value')) { + json_dict[input.name] = JSON.parse(input.getAttribute('data-default-value')); } } }); -- 2.30.9 From 9b390ba0df2bd6d59ab8bfc264c0a986eb09417e Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 17 Oct 2018 20:05:57 +0000 Subject: [PATCH 43/49] erp5_json_form: update from https://lab.nexedi.com/bk/rjs_json_form/tree/9dafc5c385b6b1de8060fd1b897a50386fabc2cd --- .../gadget_json_generated_form_child.js.js | 215 ++++++++---------- 1 file changed, 94 insertions(+), 121 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index ef68ce3484c..5ca7fc07e6f 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -121,7 +121,7 @@ return schema; } - function render_enum(g, schema, json_document) { + function render_enum(schema, json_document) { var input = document.createElement("select"), option, i, @@ -129,19 +129,12 @@ selected = false, enum_arr = schema['enum']; input.size = 1; - if (schema.default) { - if (json_document === undefined) { - json_document = schema.default; - g.props.changed = true; - } - } else { - option = document.createElement("option"); - option.value = ""; - if (json_document === undefined) { - option.selected = true; - } - input.appendChild(option); + option = document.createElement("option"); + option.value = ""; + if (json_document === undefined) { + option.selected = true; } + input.appendChild(option); for (i = 0; i < enum_arr.length; i += 1) { if (enum_arr.hasOwnProperty(i)) { option = document.createElement("option"); @@ -178,7 +171,7 @@ return input; } - function render_enum_with_title(g, schema_arr, json_document, selected_schema) { + function render_enum_with_title(schema_arr, json_document, selected_schema) { var input = document.createElement("select"), option, i, @@ -188,19 +181,12 @@ if (json_document === undefined && selected_schema !== undefined) { json_document = selected_schema.schema.const; } - if (schema_arr[0].schema.default) { - if (json_document === undefined) { - json_document = schema_arr[0].schema.default; - g.props.changed = true; - } - } else { - option = document.createElement("option"); - option.value = ""; - if (json_document === undefined) { - option.selected = true; - } - input.appendChild(option); + option = document.createElement("option"); + option.value = ""; + if (json_document === undefined) { + option.selected = true; } + input.appendChild(option); for (i = 0; i < schema_arr.length; i += 1) { option = document.createElement("option"); // XXX use number id for speedup @@ -237,7 +223,7 @@ return input; } - function render_boolean(g, schema, json_document) { + function render_boolean(json_document) { var input, schema_for_selection = { type: "boolean", @@ -250,10 +236,7 @@ if (json_document === "false") { json_document = false; } - if (getDocumentType(schema.default) === "boolean") { - schema_for_selection.default = schema.default; - } - input = render_enum(g, schema_for_selection, json_document); + input = render_enum(schema_for_selection, json_document); input.setAttribute('data-json-type', "boolean"); return input; } @@ -598,9 +581,6 @@ .push(function (value) { return event(schema_alternatives[value[scope]].value); }) - .push(function () { - return gadget.rootNotifyChange(); - }) .push(function () { if (rerender) { return rerender(g, schema_alternatives); @@ -609,6 +589,9 @@ }) .push(function (render_options) { return g.render(render_options); + }) + .push(function () { + return gadget.rootNotifyChange(); }); }, rerender: function () { @@ -698,29 +681,22 @@ var input, is_items_arr = schema.items instanceof Array, minItems = schema.minItems || 0; - if (schema.default === undefined && - json_document === undefined) { - div_input.setAttribute("data-undefined", "true"); + if (json_document instanceof Array && + json_document.length === 0) { + div_input.setAttribute("data-json-empty-array", "true"); } function element_append(child) { if (child) { input.parentNode.insertBefore(child, input); - div_input.removeAttribute("data-undefined"); + div_input.removeAttribute("data-json-empty-array"); } } function div_append(child) { if (child) { div_input.appendChild(child); - div_input.removeAttribute("data-undefined"); - } - } - - if (json_document === undefined) { - if (schema.hasOwnProperty('default')) { - json_document = schema.default; - gadget.props.changed = true; + div_input.removeAttribute("data-json-empty-array"); } } @@ -923,13 +899,13 @@ // render input begin if (!input && schema_arr[0].is_arr_of_const && schema_arr.length > 1) { - input = render_enum_with_title(gadget, schema_arr, json_document, options.selected_schema); + input = render_enum_with_title(schema_arr, json_document, options.selected_schema); } if (!input && schema.const !== undefined) { input = render_const(gadget, schema, json_document); } if (!input && schema.enum !== undefined) { - input = render_enum(gadget, schema, json_document); + input = render_enum(schema, json_document); // XXX take in account existing type with enum type_changed = false; } @@ -939,7 +915,7 @@ } if (!input && type === "boolean") { - input = render_boolean(gadget, schema, json_document); + input = render_boolean(json_document); } if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) { @@ -956,10 +932,6 @@ } if (type === "integer" || type === "number") { - if (json_document === undefined && typeof schema.default === "number") { - input.value = schema.default; - gadget.props.changed = true; - } input.setAttribute("data-json-type", type); if (json_document === undefined || json_document === null || typeof json_document === "number") { @@ -991,10 +963,6 @@ input.max = schema.maximum; } } else { - if (json_document === undefined && typeof schema.default === "string") { - input.value = schema.default; - gadget.props.changed = true; - } input.type = "text"; if (schema.pattern) { input.pattern = schema.pattern; @@ -1012,10 +980,6 @@ } } } - if (schema.default !== undefined) { - input.setAttribute('data-default-value', JSON.stringify(schema.default)); - input.placeholder = schema.default; - } } // render input end @@ -1107,6 +1071,9 @@ div.setAttribute("data-parent-scope", gadget.element.getAttribute("data-gadget-scope")); div.setAttribute("data-json-path", first_path + '/'); div.setAttribute("data-json-type", type); + if (options.required) { + div.setAttribute("data-json-required", "true"); + } } if (schema.info !== undefined) { @@ -1326,18 +1293,8 @@ root.appendChild(child); } - if (JSON.stringify(schema.default) === '{}') { - // save default value as attribute only for empty values - root.parentElement.setAttribute("data-default-value", '{}'); - } - if (json_document === undefined) { - if (schema.hasOwnProperty('default')) { - json_document = schema.default; - g.props.changed = true; - } else { - json_document = {}; - } + json_document = {}; } return expandProperties(g, schema.properties, schema_path + '/properties/', required) @@ -1525,7 +1482,7 @@ function getFormValuesAsJSONDict(g) { var multi_level_dict = {"": {}}, - count_of_values = 0, + is_empty = true, scope, options = g.props, array, @@ -1533,6 +1490,7 @@ key, i, len, + json_dict = {}, queue = RSVP.Queue(); function convertOnMultiLevel(d, key, value) { @@ -1544,19 +1502,29 @@ if (ii === key_list.length - 1) { if (value !== undefined) { d[kk] = value; - count_of_values += 1; + is_empty = false; } else { return d[kk]; } } else { if (!d.hasOwnProperty(kk)) { - d[kk] = {}; + if (value !== undefined) { + d[kk] = {}; + } else { + return; + } } d = d[kk]; } } } + function check_parent_path_not_empty(path) { + var key_list = path.split("/"), + parent_path = key_list.slice(0, key_list.length - 1).join("/"); + return convertOnMultiLevel(multi_level_dict, parent_path) !== undefined; + } + function recursiveGetContent(scope, path) { queue .push(function () { @@ -1594,25 +1562,51 @@ }); } - - // set empty object if default value require this - array = g.element - .querySelectorAll("div[data-parent-scope='" + - g.element.getAttribute("data-gadget-scope") + "']"); - for (i = 0; i < array.length; i += 1) { - path = array[i].getAttribute("data-json-path").slice(0, -1); - if (array[i].getAttribute("data-default-value") === "{}") { - convertOnMultiLevel(multi_level_dict, path, {}); + g.props.inputs.forEach(function (input) { + if (input.hasAttribute('data-origin-value')) { + json_dict[input.name] = JSON.parse(input.getAttribute('data-origin-value')); + } else { + if (input.value !== "") { + var type = input.getAttribute('data-json-type'); + if (input.tagName === "SELECT" && input.value) { + // selection used for enums + json_dict[input.name] = JSON.parse(input.value); + } else if (type === 'number') { + json_dict[input.name] = parseFloat(input.value); + } else if (type === "integer") { + json_dict[input.name] = parseInt(input.value, 10); + } else if (type === "boolean") { + if (input.value === "true") { + json_dict[input.name] = true; + } else if (input.value === "false") { + json_dict[input.name] = false; + } + } else if (input.tagName === "TEXTAREA") { + if (input["data-format"] === "string") { + json_dict[input.name] = input.value; + } else { + json_dict[input.name] = input.value.split('\n'); + } + } else { + json_dict[input.name] = input.value; + } + } + } + }); + for (path in json_dict) { + if (json_dict.hasOwnProperty(path)) { + convertOnMultiLevel(multi_level_dict, path, json_dict[path]); } } + for (path in options.arrays) { if (options.arrays.hasOwnProperty(path)) { array = options.arrays[path] .querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']"); len = array.length; if (len === 0 && - !options.arrays[path].hasAttribute('data-undefined')) { + options.arrays[path].hasAttribute('data-json-empty-array')) { convertOnMultiLevel(multi_level_dict, path.slice(0, -1), []); } for (i = 0; i < len; i = i + 1) { @@ -1640,47 +1634,26 @@ return queue .push(function () { - var json_dict = {}, - k; - g.props.inputs.forEach(function (input) { - if (input.hasAttribute('data-origin-value')) { - json_dict[input.name] = JSON.parse(input.getAttribute('data-origin-value')); - } else { - if (input.value !== "") { - var type = input.getAttribute('data-json-type'); - if (input.tagName === "SELECT" && input.value) { - // selection used for enums - json_dict[input.name] = JSON.parse(input.value); - } else if (type === 'number') { - json_dict[input.name] = parseFloat(input.value); - } else if (type === "integer") { - json_dict[input.name] = parseInt(input.value, 10); - } else if (type === "boolean") { - if (input.value === "true") { - json_dict[input.name] = true; - } else if (input.value === "false") { - json_dict[input.name] = false; - } - } else if (input.tagName === "TEXTAREA") { - if (input["data-format"] === "string") { - json_dict[input.name] = input.value; - } else { - json_dict[input.name] = input.value.split('\n'); - } + // set empty object/array for required properties/items + // if parent object/array existed + array = g.element + .querySelectorAll("div[data-parent-scope='" + + g.element.getAttribute("data-gadget-scope") + "']"); + for (i = 0; i < array.length; i += 1) { + path = array[i].getAttribute("data-json-path").slice(0, -1); + if (check_parent_path_not_empty(path) && + convertOnMultiLevel(multi_level_dict, path) === undefined) { + if (array[i].hasAttribute("data-json-required")) { + if (array[i].getAttribute("data-json-type") === "object") { + convertOnMultiLevel(multi_level_dict, path, {}); } else { - json_dict[input.name] = input.value; + convertOnMultiLevel(multi_level_dict, path, []); } - } else if (input.hasAttribute('data-default-value')) { - json_dict[input.name] = JSON.parse(input.getAttribute('data-default-value')); } } - }); - for (k in json_dict) { - if (json_dict.hasOwnProperty(k)) { - convertOnMultiLevel(multi_level_dict, k, json_dict[k]); - } } - if (count_of_values === 0) { + + if (is_empty) { switch (g.props.type) { case "string": return ""; -- 2.30.9 From ef48eaf67ac8d3d2387049ef811658dfb7409ebe Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 19 Oct 2018 18:25:31 +0300 Subject: [PATCH 44/49] erp5_web_renderjs_ui: doesn't save panel state in launcher.props because no needs. and rename updateHeader and updatePanel to lUpdateHeader lUpdatePanel for avoiding naming conflict thanks @jerome --- .../rjs_gadget_erp5_launcher_js.js | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js index 8214deb7999..648da6ed7cf 100644 --- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js +++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_gadget_erp5_launcher_js.js @@ -31,10 +31,6 @@ }; } - function initPanelOptions(gadget) { - gadget.props.panel_argument_list = {}; - } - function route(my_root_gadget, my_scope, my_method, argument_list) { return my_root_gadget.getDeclaredGadget(my_scope) .push(function (my_gadget) { @@ -45,7 +41,7 @@ }); } - function updateHeader(gadget) { + function lUpdateHeader(gadget) { var header_gadget; return gadget.getDeclaredGadget("header") .push(function (result) { @@ -57,10 +53,10 @@ }); } - function updatePanel(gadget) { + function lUpdatePanel(gadget, panel_state) { return gadget.getDeclaredGadget("panel") .push(function (panel_gadget) { - return panel_gadget.render(gadget.props.panel_argument_list); + return panel_gadget.render(panel_state || {}); }); } @@ -472,11 +468,8 @@ }); }) - .allowPublicAcquisition("updatePanel", function (param_list) { - var gadget = this; - initPanelOptions(gadget); - gadget.props.panel_argument_list = param_list[0]; - return updatePanel(gadget); + .allowPublicAcquisition("updatePanel", function updatePanel(param_list) { + return lUpdatePanel(this, param_list[0]); }) .allowPublicAcquisition('hidePanel', function hidePanel(param_list) { @@ -594,8 +587,8 @@ element.appendChild(content_container); return RSVP.all([ - updateHeader(gadget), - updatePanel(gadget) + lUpdateHeader(gadget), + lUpdatePanel(gadget) ]); // XXX Drop notification // return header_gadget.notifyLoaded(); @@ -610,8 +603,8 @@ }) .push(function () { return RSVP.all([ - updateHeader(gadget), - updatePanel(gadget) + lUpdateHeader(gadget), + lUpdatePanel(gadget) ]); }); }) @@ -624,7 +617,6 @@ // By default, init the header options to be empty // (ERP5 title by default + sidebar) initHeaderOptions(gadget); - initPanelOptions(gadget); return increaseLoadingCounter(gadget) .push(function () { var promise_list = [ @@ -671,4 +663,4 @@ }); }(window, document, RSVP, rJS, - XMLHttpRequest, location, console, navigator, ProgressEvent)); \ No newline at end of file + XMLHttpRequest, location, console, navigator, ProgressEvent)); -- 2.30.9 From c9f2cb6896c04e2efea39b7ea8134246b8344f26 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 16 Nov 2018 23:10:14 +0000 Subject: [PATCH 45/49] erp5_json_form: update from https://lab.nexedi.com/bk/rjs_json_form/commit/e9d5621047936bf7f999ad41a5e1d91c3d7a6ee5 --- .../erp5_json_form/jsonform.gadget.js.js | 23 -------- .../gadget_json_generated_form_child.js.js | 52 +++++++++++++++++-- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js index ddcac808bbb..01a14d41ac0 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -901,29 +901,6 @@ .allowPublicAcquisition("expandSchema", function (arr) { return expandSchemaForField(this, arr[0], arr[1], arr[2]); }) - .onEvent('click', function (evt) { - if (evt.target === this.props.delete_button) { - return this.selfRemove(evt); - } - - var link = evt.target.getAttribute("data-error-link"), - button_list = this.props.add_buttons, - i; - if (link) { - location.href = link; - return; - } - - for (i = 0; i < button_list.length; i = i + 1) { - if (evt.target === button_list[i].element) { - return button_list[i].event(evt); - } - } - }) - .declareJob('listenEvents', function () { - // XXX Disable - return; - }) .onLoop(function () { var gadget = this; if (this.props.changed) { diff --git a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js index 5ca7fc07e6f..15e21cd9f2c 100644 --- a/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -441,18 +441,22 @@ } function schemaArrFilteredByDocument(schema_arr, json_document) { - var i, + var x, + i, + errors, + error, flag, circular = schema_arr[0].circular, ret_arr = [], + validation, schema; if (schema_arr.length === 1 || schema_arr[0].is_arr_of_const) { return schema_arr; } if (json_document !== undefined) { - for (i = 0; i < schema_arr.length; i += 1) { - schema = schema_arr[i].schema; + for (x = 0; x < schema_arr.length; x += 1) { + schema = schema_arr[x].schema; if (schema === true) { flag = true; } else if (schema === false) { @@ -461,11 +465,49 @@ flag = tv4.validate(json_document, schema); } if (flag) { - ret_arr.push(schema_arr[i]); + ret_arr.push(schema_arr[x]); + } + } + if (ret_arr.length === 0) { + // currently try to find + // more compatible schema for current document + // XXX it may be need be more smart in future + // (every error has weigh, weigh depend from level...), + // may be not. + for (x = 0; x < schema_arr.length; x += 1) { + schema = schema_arr[x].schema; + if (schema !== false) { + validation = tv4.validateMultiple(json_document, schema); + errors = validation.errors; + flag = true; + for (i = 0; i < errors.length; i += 1) { + error = errors[i]; + if (error.code === 0 || // INVALID_TYPE + error.code === 13 || // NOT_PASSED + error.code === 14 // BOOLEAN_SCHEMA_FALSE + ) { + if (error.dataPath.split('/').length === 1) { + flag = false; + break; + } + } + if (error.code === 15 // CONST_NOT_EQUAL + ) { + // take in account errors only on fist level + if (error.dataPath.split('/').length <= 2) { + flag = false; + break; + } + } + } + if (flag) { + ret_arr = [schema_arr[x]]; + break; + } + } } } if (ret_arr.length === 0) { - // XXX find schema more compatible with document return schema_arr; } ret_arr[0].circular = circular; -- 2.30.9 From d6a8616689ff1d6418cb00a5af6889014bd86fd1 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Wed, 21 Nov 2018 01:39:56 +0300 Subject: [PATCH 46/49] erp5_officejs: schema_editor: remove unused code --- ...dget_erp5_page_ojs_add_json_document.js.js | 21 ++---------------- ...gadget_erp5_page_ojs_add_json_schema.js.js | 22 ++----------------- 2 files changed, 4 insertions(+), 39 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js index a11ef9cf04a..7845afedb56 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_document.js.js @@ -3,17 +3,6 @@ (function (window, rJS, RSVP) { "use strict"; - var content_type = { - Spreadsheet: 'application/x-asc-spreadsheet', - Presentation: 'application/x-asc-presentation', - Text: 'application/x-asc-text' - }, - file_ext = { - Spreadsheet: 'xlsy', - Presentation: 'ppty', - Text: 'docy' - }; - rJS(window) ///////////////////////////////////////////////////////////////// // Acquired methods @@ -31,18 +20,12 @@ var gadget = this; return RSVP.Queue() .push(function () { - var portal_type = options.portal_type, - ext = file_ext[portal_type], - ret = { + var ret = { title: "Untitled Document", portal_type: "JSON Document", schema: options.schema, - parent_relative_url: "document_module", - content_type: content_type[portal_type] || undefined + parent_relative_url: "document_module" }; - if (ext) { - ret.filename = "default." + ext; - } return gadget.jio_post(ret); }) .push(function (id) { diff --git a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js index e55f5eef413..a6c882846ee 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js +++ b/bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_erp5_page_ojs_add_json_schema.js.js @@ -3,18 +3,6 @@ (function (window, rJS, RSVP, Blob) { "use strict"; - var content_type = { - Spreadsheet: 'application/x-asc-spreadsheet', - Presentation: 'application/x-asc-presentation', - Text: 'application/x-asc-text' - }; - - var file_ext = { - Spreadsheet: 'xlsy', - Presentation: 'ppty', - Text: 'docy' - }; - rJS(window) ///////////////////////////////////////////////////////////////// // Acquired methods @@ -30,21 +18,15 @@ ///////////////////////////////////////////////////////////////// // declared methods ///////////////////////////////////////////////////////////////// - .declareMethod("render", function (options) { + .declareMethod("render", function () { var gadget = this, - portal_type = options.portal_type, - ext = file_ext[portal_type], ret = { title: "Untitled Schema", portal_type: "JSON Schema", - parent_relative_url: "schema_module", - content_type: content_type[portal_type] || undefined + parent_relative_url: "schema_module" }; return RSVP.Queue() .push(function () { - if (ext) { - ret.filename = "default." + ext; - } return gadget.jio_post(ret); }) .push(function (id) { -- 2.30.9 From 98b8aea4f95539a14cf212761f92eeb71455a4fb Mon Sep 17 00:00:00 2001 From: Romain Courteaud Date: Mon, 7 Nov 2016 13:42:56 +0000 Subject: [PATCH 47/49] Reduce number of test to run --- tests/__init__.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 571fd45fd71..c2f559dd20a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -35,9 +35,20 @@ class _ERP5(ERP5TypeTestSuite): component_re = re.compile(".*/([^/]+)/TestTemplateItem/portal_components" "/test\.[^.]+\.([^.]+).py$") for test_path in ( - glob('%s/product/*/tests/test*.py' % path) + - glob('%s/bt5/*/TestTemplateItem/test*.py' % path) + - glob('%s/bt5/*/TestTemplateItem/portal_components/test.*.test*.py' % path)): + # glob('%s/product/Formulator/tests/test*.py' % path) + + # glob('%s/product/ERP5Form/tests/test*.py' % path) + + # ['%s/product/ERP5/tests/testXHTML.py' % path] + + # ['%s/product/ERP5Type/tests/testFunctionalCore.py' % path] + + # ['%s/product/ERP5Type/tests/testFunctionalAnonymousSelection.py' % path] + + # glob('%s/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_ui_test/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_token_login/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_pdm_renderjs_ui_test/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_crm_renderjs_ui_test/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_accounting_renderjs_ui_test/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_gadget_interface_validator_ui_test/TestTemplateItem/portal_components/test.*.test*.py' % path) + + # glob('%s/bt5/erp5_web_renderjs_ui_test/TestTemplateItem/portal_components/test.*.test*.py' % path)): + glob('%s/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.py' % path)): component_re_match = component_re.match(test_path) if component_re_match is not None: test_case = "%s:%s" % (component_re_match.group(1), -- 2.30.9 From 9890e62f160e965c0ffdb83371437da0bcde4f26 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Fri, 23 Nov 2018 23:03:54 +0000 Subject: [PATCH 48/49] erp5_officejs_ui_test: add officejs_ui_schema_editor_zuite --- .../officejs_ui_schema_editor_zuite.xml | 26 +++++ .../testOfficeJSchemaEditor.xml | 58 ++++++++++ .../testOfficeJSchemaEditor.zpt | 104 ++++++++++++++++++ ...erp5.testFunctionalOfficeJSSchemaEditor.py | 47 ++++++++ ...rp5.testFunctionalOfficeJSSchemaEditor.xml | 102 +++++++++++++++++ .../bt/template_test_id_list | 1 + 6 files changed, 338 insertions(+) create mode 100644 bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite.xml create mode 100644 bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.xml create mode 100644 bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.zpt create mode 100644 bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.py create mode 100644 bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.xml diff --git a/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite.xml b/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite.xml new file mode 100644 index 00000000000..42dc26d3a4b --- /dev/null +++ b/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite.xml @@ -0,0 +1,26 @@ + + + + + + + + + + _objects + + + + + + id + officejs_ui_schema_editor_zuite + + + title + + + + + + diff --git a/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.xml b/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.xml new file mode 100644 index 00000000000..19f794ed4d2 --- /dev/null +++ b/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.xml @@ -0,0 +1,58 @@ + + + + + + + + + + _bind_names + + + + + + + + + + _asgns + + + + name_subpath + traverse_subpath + + + + + + + + + + + content_type + text/html + + + expand + 0 + + + id + testOfficeJSchemaEditor + + + output_encoding + utf-8 + + + title + + + + + + diff --git a/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.zpt b/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.zpt new file mode 100644 index 00000000000..1fb5ab045b4 --- /dev/null +++ b/bt5/erp5_officejs_ui_test/PathTemplateItem/portal_tests/officejs_ui_schema_editor_zuite/testOfficeJSchemaEditor.zpt @@ -0,0 +1,104 @@ + + + + Test Media Player UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Test OfficeJS UI
      waitForElementPresent//a[@data-i18n='Storages']
      click//a[@data-i18n='Storages']
      waitForElementPresentlink=Local is Enough
      clicklink=Local is Enough
      waitForElementPresent//a[@data-i18n='Add']
      verifyTextPresentSchemas
      verifyTextPresentAdd
      click//a[@data-i18n='Add']
      waitForElementPresent//button[@data-i18n='Save']
      verifyTextPresentUpload
      verifyTextPresentSave
      click//a[@data-i18n='Schemas']
      verifyElementPresent//a[text()='Untitled Schema']
      verifyTextPresentSchemas
      verifyTextPresentFilter
      verifyTextPresentAdd
      + + \ No newline at end of file diff --git a/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.py b/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.py new file mode 100644 index 00000000000..0f730cdede4 --- /dev/null +++ b/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.py @@ -0,0 +1,47 @@ +############################################################################## +# +# Copyright (c) 2011 Nexedi SARL and Contributors. All Rights Reserved. +# Kazuhiko +# Rafael Monnerat +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## +import unittest + +from Products.ERP5Type.tests.ERP5TypeFunctionalTestCase import ERP5TypeFunctionalTestCase + +class TestOfficejSUISchemaEditor(ERP5TypeFunctionalTestCase): + foreground = 0 + run_only = "officejs_ui_schema_editor_zuite" + + def getBusinessTemplateList(self): + return ( + 'erp5_officejs', + 'erp5_officejs_ui_test', + 'erp5_ui_test_core', + ) + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestOfficejSUISchemaEditor)) + return suite diff --git a/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.xml b/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.xml new file mode 100644 index 00000000000..57e6aa0a088 --- /dev/null +++ b/bt5/erp5_officejs_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficeJSSchemaEditor.xml @@ -0,0 +1,102 @@ + + + + + + + + + + default_reference + testFunctionalOfficeJSSchemaEditor + + + description + + + + + + id + test.erp5.testFunctionalOfficeJSSchemaEditor + + + portal_type + Test Component + + + sid + + + + + + text_content_error_message + + + + + + text_content_warning_message + + + + + + version + erp5 + + + workflow_history + + AAAAAAAAAAI= + + + + + + + + + + + + + data + + + + component_validation_workflow + + AAAAAAAAAAM= + + + + + + + + + + + + + + + + + + + action + validate + + + validation_state + validated + + + + + + + diff --git a/bt5/erp5_officejs_ui_test/bt/template_test_id_list b/bt5/erp5_officejs_ui_test/bt/template_test_id_list index d99e0ec7233..81c8efeb448 100644 --- a/bt5/erp5_officejs_ui_test/bt/template_test_id_list +++ b/bt5/erp5_officejs_ui_test/bt/template_test_id_list @@ -1,4 +1,5 @@ test.erp5.testFunctionalOfficeJSSmartAssistant +test.erp5.testFunctionalOfficeJSSchemaEditor test.erp5.testFunctionalOfficeJSTextEditor test.erp5.testFunctionalOfficeJSCodeMirror test.erp5.testFunctionalOfficeJSMediaPlayer -- 2.30.9 From d95662932e46ed21bdfd1a2dfba625686c9d0419 Mon Sep 17 00:00:00 2001 From: Boris Kocherov Date: Sun, 25 Nov 2018 23:07:14 +0300 Subject: [PATCH 49/49] erp5_officejs: schema_editor: fix web_site_module --- .../PathTemplateItem/web_site_module/officejs_schema.xml | 2 +- .../web_site_module/officejs_schema/app.xml | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml index 629f1f55eb3..f95bd9c23df 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema.xml @@ -525,7 +525,7 @@
      skin_selection_name - Officejs + RJS static_language_selection diff --git a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml index efcf40f5a1c..2026866a525 100644 --- a/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml +++ b/bt5/erp5_officejs/PathTemplateItem/web_site_module/officejs_schema/app.xml @@ -316,7 +316,7 @@ configuration_content_security_policy - default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' http: https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data: + default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data: configuration_default_jio_document_page_gadget_url @@ -560,9 +560,7 @@ action - - - + publish actor @@ -597,7 +595,7 @@ validation_state - embedded + published -- 2.30.9