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 0000000000000000000000000000000000000000..cdba2281157c898f089a61e3a93bbcef66e11e78 --- /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 0000000000000000000000000000000000000000..cbafac43b5a1793f55e24fbf511e1bbc351fb212 --- /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 0000000000000000000000000000000000000000..bcbb84743e3838fab7cbec5f0a5bcbafcfc99136 --- /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 0000000000000000000000000000000000000000..e70369b20d7ebdb546f980b260106517c4e73949 --- /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 0000000000000000000000000000000000000000..5656240b94724091487c1c3c9cdce68c10352598 --- /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 0000000000000000000000000000000000000000..00ece57f36b2158b4e11378672fefe5c2c895554 --- /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 0000000000000000000000000000000000000000..5bee90ec141cc3c3fb369aee979027c6453c49e9 --- /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 0000000000000000000000000000000000000000..4bad30d30d2bf1e519a503124d34b461166b9df1 --- /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 0000000000000000000000000000000000000000..fd6fcdb868c0733201f1552618ce2bfd860dc01f --- /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 0000000000000000000000000000000000000000..63b3403ef8fd492c6869d531b9215cdd4758c203 --- /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 0000000000000000000000000000000000000000..f42a5cd9fb99df06437bd95b3d2ccc9e5e2a43d3 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.html.html @@ -0,0 +1,15 @@ + + + + + + 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 0000000000000000000000000000000000000000..d63d0617dccf2a8e7735de5d8601680b68751870 --- /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 0000000000000000000000000000000000000000..4199d351a9f61e7c7685b326a7d9c16ac1dce94b --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform.gadget.js.js @@ -0,0 +1,1083 @@ +/*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/ +/*global window, document, URL, rJS, RSVP, jIO, Blob, console*/ + +(function (window, document, Blob, rJS, RSVP, jIO) { + "use strict"; + var expandSchema; + + function arrayIntersect(x, y) { + return x.filter(function (value) { + return y.indexOf(value) >= 0; + }); + } + + function getUrlWithoutHash(url) { + if (typeof url !== "string") { + url = url.href; + } + var index = url.indexOf('#'); + + if (index >= 0) { + return url.substring(0, index); + } + return url; + } + + 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" && + !(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); + } + base_url = fake_prefix + decodeURIComponent(base_url.replace(urn_prefix, "")); + } + url = new URL(url, base_url); + if (urn_prefix) { + pathname = url.pathname.slice(1); + 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; + } + + 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(urls, path, url) { + var stack, + idx, + 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; + } + 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] = []; + } + } + + 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 URLwithJio(url, base_url_failback); + } else { + absolute_url = new URLwithJio(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 map_url(g, download_url) { + var hash = download_url.hash, + mapped_url = getUrlWithoutHash(download_url), + 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 = schemas[mapped_url]; + if (next_mapped_url === undefined) { + break; + } + mapped_url = new URL(next_mapped_url, g.__path); + if (hash[0] === '#') { + hash = hash.slice(1); + } + if (hash === '/') { + hash = ''; + } + hash = mapped_url.hash || "#" + hash; + mapped_url = getUrlWithoutHash(mapped_url); + } + return new URL(mapped_url + hash); + } + + function loadJSONSchema(g, $ref, schema_path, path) { + var protocol, + abs_url, + url, + download_url, + hash, + external_reference = false, + queue; + // XXX need use `id` property + if (!schema_path) { + schema_path = "/"; + } + abs_url = convertUrlToAbsolute(g, schema_path, decodeURI($ref), window.location); + url = map_url(g, abs_url); + abs_url = abs_url.href; + protocol = url.protocol; + if (protocol === "http:") { + if (window.location.protocol !== protocol) { + // try change url protocol to https + url = new URL(url.toString().replace(protocol + "//", window.location.protocol + "//")); + // throw new Error("You cannot mixed http and https calls"); + } + } + download_url = getUrlWithoutHash(url); + hash = url.hash; + url = url.href; + if (download_url.startsWith("urn:jio:")) { + external_reference = download_url; + queue = RSVP.Queue() + .push(function () { + return g.resolveExternalReference(download_url, schema_path, path); + }); + } else { + queue = RSVP.Queue() + .push(function () { + return downloadJSON(download_url); + }); + } + return queue + .push(function (json) { + if (checkHardCircular(g, schema_path, url)) { + throw new Error("Circular reference detected"); + } + 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, schema_path), + schema_a = document.createElement("a"), + pointed_a = document.createElement("a"); + schema_a.setAttribute("href", download_url); + schema_a.text = (new URLwithJio(download_url)).pathname; + pointed_a.setAttribute("href", url_from_pointed); + pointed_a.text = (new URLwithJio(url_from_pointed)).pathname; + g.props.schema_resolve_errors[url_from_pointed] = { + schemaPath: schema_path, + message: [ + document.createTextNode("schema error: "), + document.createTextNode(err.message), + schema_a, + document.createTextNode(" pointed from schema: "), + pointed_a + ] + }; + console.error(err); + return null; // schema part can't be null + }) + .push(function (schema_part) { + 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 + if (!g.props.hasOwnProperty(schema_path)) { + g.props.schema_map[schema_path] = abs_url; + } + } + schemaPushSchemaPart(g.props.schema, schema_path, JSON.parse(JSON.stringify(schema_part))); + // console.log(g.props.schema[""]); + return expandSchema(g, schema_part, schema_path, path, $ref); + }) + .push(function (schema_arr) { + checkAndMarkSoftCircular(g, schema_arr, schema_path, url); + schema_arr.external_reference = external_reference; + return schema_arr; + }); + } + + function mergeSchemas(x, y, doesntcopy) { + if (x === true && y === true) { + return true; + } + if (x === false || y === false) { + return false; + } + 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 + ] + }; + } + 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; + } + if (x.oneOf) { + delete x.oneOf; + } + if (x.allOf) { + delete x.allOf; + } + } + 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": + x[key] = mergeSchemas(x[key], y[key], true); + break; + case "items": + // XXX items can be array + x[key] = 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)) { + x[key][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 "oneOf": + case "$ref": + case "id": + case "$id": + // XXX + break; + default: + // XXX + x[key] = y[key]; + } + } else { + switch (key) { + case "allOf": + case "anyOf": + case "oneOf": + case "$ref": + break; + default: + x[key] = y[key]; + } + } + } + } + return x; + } + + function allOf(g, schema_array, schema_path, path, base_schema) { + 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 + '/' + i.toString(), path)); + } + return RSVP.all(arr); + }) + .push(function (arr) { + var i, + x, + y, + next_schema, + schema, + 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; + 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; + } + 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, path, base_schema) { + 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 + '/' + i.toString(), path)); + } + 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]]; + } + 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]); + } + } + return schema_arr; + }); + } + + expandSchema = function (g, schema, schema_path, path, ref) { + // XXX `if then else` construction can be simplify to + // anyOf(allOf(if_schema, then_schema), else_schema) + // and realized by existed rails + var schema_p; + if (schema === undefined || + Object.keys(schema).length === 0) { + schema = true; + } + if (schema_path === "/") { + schema_p = ""; + } else { + schema_p = schema_path; + } + // XXX check oneOf anyOf allOf length >= 1 and generate exception if not + if (schema.anyOf !== undefined) { + return anyOf(g, schema.anyOf, schema_p + '/anyOf', path, schema); + } + if (schema.oneOf !== undefined) { + return anyOf(g, schema.oneOf, schema_p + '/oneOf', path, schema) + .push(function (ret) { + ret.schema_path = schema_path; + return ret; + }); + } + if (schema.allOf !== undefined) { + return allOf(g, schema.allOf, schema_p + '/allOf', path, schema) + .push(function (ret) { + ret.schema_path = schema_path; + return ret; + }); + } + if (schema.$ref) { + return loadJSONSchema(g, schema.$ref, schema_path, 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; + if (!g.props.schemas.hasOwnProperty(url)) { + g.props.schemas[url] = mapped_url; + } + } + } + } + } + return RSVP.Queue() + .push(function () { + return [{ + 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, 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, path) + .push(schema_arr_marker); + } + + function convertOnMultiLevel(d, key) { + var ii, + kk, + key_list = key.split("/"); + if (key === "/") { + return d; + } + for (ii = 1; ii < key_list.length; ii += 1) { + kk = decodeJsonPointer(key_list[ii]); + if (ii === key_list.length - 1) { + return d[kk]; + } + if (!d.hasOwnProperty(kk)) { + return; + } + d = d[kk]; + } + } + + rJS(window) + .ready(function () { + var g = this; + g.props = { + errors: {} + }; + g.options = {}; + }) + .declareAcquiredMethod("resolveExternalReference", "resolveExternalReference") + .declareAcquiredMethod("notifyChange", "notifyChange") + .allowPublicAcquisition("rootNotifyChange", function (arr, scope) { + return this.notifyChange(arr[0], scope); + }) + .declareAcquiredMethod("notifyValid", "notifyValid") + .declareAcquiredMethod("notifyInvalid", "notifyInvalid") + .allowPublicAcquisition("notifyInvalid", function (arr) { + if (arr[0].length === 0) { + delete this.props.errors[arr[1]]; + } else { + this.props.errors[arr[1]] = arr[0]; + } + }) + .declareMethod('getSubGadget', function (scope) { + // recursive getDeclaredGadget + // work only if subgadget scope contain parent + // scope as prefix + // example: + // gadget: scope1234 + // subgadet: scope1234_subgadgetscope1 + // subsubgadet: scope1234_subgadgetscope1_subsubgadetscope + var i, + gadget = this, + scope_arr = scope.split('_'), + queue = RSVP.Queue() + .push(function () { + return gadget.props.form_gadget; + }); + function getDeclaredGadget(scope) { + return function (g) { + return g.getDeclaredGadget(scope); + }; + } + for (i = 2; i <= scope_arr.length; i += 1) { + queue.push(getDeclaredGadget(scope_arr.slice(0, i).join('_'))); + } + return queue; + }) + .declareMethod('getGadgetByPath', function (path) { + return this.props.form_gadget.getGadgetByPath(path || "/"); + }) + .allowPublicAcquisition("getSchema", function (arr) { + var schema_path = arr[0]; + return convertOnMultiLevel(this.props.schema[""], schema_path); + }) + .declareJob('jobPrintErrors', function () { + return this.printErrors(); + }) + .allowPublicAcquisition("printErrors", function () { + return this.jobPrintErrors(); + }) + .declareMethod("printErrors", function () { + var g = this.props.form_gadget, + gadget = this; + return RSVP.Queue() + .push(function () { + 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 gadget.props.errors) { + if (gadget.props.errors.hasOwnProperty(i)) { + errors = errors.concat(gadget.props.errors[i]); + } + } + + for (i in schema_resolve_errors) { + if (schema_resolve_errors.hasOwnProperty(i)) { + errors.push(schema_resolve_errors[i]); + } + } + + 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 error_message, + createTextNode = document.createTextNode.bind(document), + a = document.createElement("a"); + element = element || error.element; + a.setAttribute("href", "#" + errorUid); + a.text = errorId; + element.setAttribute("class", "error-input"); + error_message = element.querySelector(".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.appendChild(document.createElement("br")); + 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(); + if (error.element) { + tasks.push( + new RSVP.Queue() + .push(print_error(error, "error" + error_id, error_id)) + ); + } else { + 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; + }); + }); + }) + + .allowPublicAcquisition('parentGetJsonPath', function (arr, scope) { + return ""; + }) + + .declareMethod('render', function (options) { + if (!options) { + options = {}; + } + var z = { + saveOrigValue: options.saveOrigValue, + editable: options.editable === undefined ? true : options.editable + }; + if (options.hasOwnProperty("key")) { + z.key = options.key; + } + if (options.hasOwnProperty("schema")) { + if (typeof options.schema === "string") { + z.schema = options.schema; + } else { + z.schema = JSON.stringify(options.schema); + } + } + if (options.schema_url) { + z.schema_url = (new URL(options.schema_url, window.location)) + .toString(); + } + if (options.value !== undefined) { + z.value = JSON.stringify(options.value); + } + return this.changeState(z); + }) + .onStateChange(function () { + var g = this, + json_document = g.state.value, + schema; + if (json_document !== undefined) { + json_document = JSON.parse(json_document); + } + g.props.init_value = json_document; + 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 + // 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_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, + // 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 () { + 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] = URL + .createObjectURL(new Blob([g.state.schema], {type : 'application/json'})); + 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) + .push(schema_arr_marker); + } + } + if (queue) { + return queue; + } + return [{ + schema: true, + schema_path: "" + }]; + }) + .push(function (schema_arr) { + return g.props.form_gadget.renderForm({ + schema_arr: schema_arr, + document: json_document, + saveOrigValue: g.state.saveOrigValue, + required: true, + top: true + }); + }) + .push(function () { + return g.printErrors(); + }) + .push(function () { + if (g.props.form_gadget.props.changed.length > 0) { + g.notifyChange(); + } + delete g.props.init_value; + }) + .push(function () { + return true; + }) + .push(undefined, function (err) { + console.error(err); + }); + }) + .declareMethod('rerender', function (opt) { + var g = this, + gadget = g.props.form_gadget, + queue = RSVP.Queue(); + opt = opt || {}; + if (!opt.scope && !opt.path) { + opt.schema = opt.schema || g.state.schema; + } + if (opt.scope) { + queue + .push(function () { + return g.getSubGadget(opt.scope); + }) + .push(function (ret) { + gadget = ret; + }); + } + if (opt.path) { + queue + .push(function () { + if (!gadget) { + gadget = g.props.form_gadget; + } + return gadget.getGadgetByPath(opt.path); + }) + .push(function (ret) { + gadget = ret.gadget; + }); + } + return queue + .push(function () { + return gadget.getContent(); + }) + .push(function (value) { + opt.value = value; + g.props.init_value = value; + return gadget.rerender(opt) + .push(function () { + delete g.props.init_value; + return gadget.props.changed; + }); + }); + }) + + .allowPublicAcquisition("expandSchema", function (arr) { + return expandSchemaForField(this, arr[0], arr[1], arr[2], arr[3]); + }) + + .declareMethod('getContentMutex', function () { + return this.props.form_gadget.getContent(); + }, {mutex: 'changestate'}) + .declareMethod('getContent', function (sub_path) { + var g = this; + if (g.state.editable) { + return RSVP.Queue() + .push(function () { + if (g.props.init_value) { + return g.props.init_value; + } + return g.getContentMutex(); + }) + .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 = JSON.stringify(value); + if (sub_path) { + value = convertOnMultiLevel(value, sub_path); + } + 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, Blob, rJS, RSVP, jIO)); \ 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 0000000000000000000000000000000000000000..e74857f8664c0c0725dcf4aef13883b5bec60d70 --- /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 + jsonform.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 0000000000000000000000000000000000000000..e95a62ff6f96e2da59a2c32ec67923ea2f1e3c0a --- /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 0000000000000000000000000000000000000000..6afe69360257c76d9cec43b6176517e555f48f8d --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.html.html @@ -0,0 +1,17 @@ + + + + + + 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 0000000000000000000000000000000000000000..64890d6898d6c2fa153aabc23607e9d70a6d3c25 --- /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 0000000000000000000000000000000000000000..9b2273c693b6f4ee4b4b139231caf0b5a7e1d032 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/gadget_json_generated_form_child.js.js @@ -0,0 +1,2420 @@ +/*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/ +/*global window, document, URL, rJS, RSVP, jIO, tv4, location, console */ + +(function (window, document, location, rJS, RSVP, tv4) { + "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, '~'); + } + + function encodeJsonPointer(_str) { + // https://tools.ietf.org/html/rfc6901#section-5 + return _str.replace(/~/g, '~0').replace(/\//g, '~1'); + } + + function escapeId(s) { + return s.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&"); + } + + 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; + 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_enum(g, schema, json_document) { + var input = document.createElement("select"), + option, + i, + ser_value, + selected = false, + empty_option, + enum_arr = schema['enum']; + input.size = 1; + empty_option = document.createElement("option"); + empty_option.value = ""; + if (json_document === undefined) { + empty_option.selected = true; + } + input.appendChild(empty_option); + for (i = 0; i < enum_arr.length; i += 1) { + option = document.createElement("option"); + 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) { + if (g.props.ignore_incorrect) { + empty_option.selected = true; + g.props.changed.push(input); + } else { + // 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_enum_with_title(g, schema_arr, json_document, selected_schema) { + var input = document.createElement("select"), + empty_option, + option, + i, + ser_value, + selected = false; + input.size = 1; + if (json_document === undefined && selected_schema !== undefined) { + json_document = selected_schema.schema.const; + } + empty_option = document.createElement("option"); + empty_option.value = ""; + if (json_document === undefined) { + empty_option.selected = true; + } + input.appendChild(empty_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) { + if (g.props.ignore_incorrect) { + empty_option.selected = true; + g.props.changed.push(input); + } else { + // 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, 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; + } + input = render_enum(g, schema_for_selection, json_document); + input.setAttribute('data-json-type', "boolean"); + return input; + } + + 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 || g.props.ignore_incorrect || + deepEqual(json_document, schema.const)) { + if (json_document === undefined || !deepEqual(json_document, schema.const)) { + g.props.changed.push(input); + } + input.setAttribute('data-origin-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); + 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) { + if (typeof json_document === "object") { + input.value = JSON.stringify(json_document, null, 2); + } else { + input.value = json_document; + } + } + input["data-format"] = data_format; + return input; + } + + function generateUid(g) { + // generate scope use parent scope as prefix so + // we can filter all sub_gadgets target gadget + // XXX size? + var z = g.element.getAttribute('data-gadget-scope'); + return z + '_' + Math.random().toString(36).substr(2, 5); + } + + function addSubForm(options) { + var input_element = options.element, + g = options.gadget, + property_name, + parent_path, + scope; + return RSVP.Queue() + .push(function () { + scope = generateUid(g); + parent_path = options.parent_path; + if (options.parent_type !== "array") { + property_name = options.property_name; + if (!property_name) { + property_name = input_element.value; + } + if (!property_name) { + throw new Error("can't create property without name"); + } + if (g.props.objects[parent_path].hasOwnProperty(property_name) && g.props.objects[parent_path][property_name] !== "") { + throw new Error("you can't create property with existed name"); + } + 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")); + form_gadget.element.setAttribute("data-json-parent", parent_path); + if (options.parent_type !== "array") { + g.props.objects[parent_path][property_name] = scope; + 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, + selected_schema: options.selected_schema, + schema_arr: options.schema_arr, + document: options.json_document, + display_label: options.parent_type !== "array", + saveOrigValue: g.props.saveOrigValue, + ignore_incorrect: g.props.ignore_incorrect, + scope: scope + }) + .push(function () { + if (options.schema_arr.external_reference) { + return form_gadget.rootNotifyChange({ + scope: scope, + action: "render", + path: "/" + }); + } + }) + .push(function () { + if (form_gadget.props.changed.length > 0) { + // XXX not exactly path changed element + g.props.changed.push(parent_path); + } + return form_gadget.element; + }); + }); + } + + function expandItems(g, items, schema_path, path, minItems) { + if (!(items instanceof Array)) { + return g.expandSchema(items, schema_path, path, minItems !== 0); + } + var i, + tasks = []; + for (i = 0; i < items.length; i += 1) { + tasks.push(g.expandSchema(items[i], schema_path + '/' + i, path, i < minItems)); + } + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }); + } + + function expandProperties(g, properties, schema_path, path, required) { + var ret_obj = {}; + return RSVP.Queue() + .push(function () { + var property_name, + arr = []; + function addPropertyName(p_name) { + return g.getJsonPath(path) + .push(function (p) { + return g.expandSchema( + properties[p_name], + schema_path + encodeJsonPointer(p_name), + p + encodeJsonPointer(p_name), + required.indexOf(p_name) >= 0 + ); + }) + .push(function (schema_array) { + ret_obj[p_name] = schema_array; + }); + } + for (property_name in properties) { + if (properties.hasOwnProperty(property_name)) { + arr.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 || + !(schema_arr[0].schema.hasOwnProperty('type') || + schema_arr[0].schema.hasOwnProperty('enum') || + schema_arr[0].schema.hasOwnProperty('const') + )) { + return false; + } + if (schema_arr[0].schema.type instanceof Array) { + return schema_arr[0].schema.type.length <= 1; + } + return true; + } + if (schema_arr[0].is_arr_of_const) { + return true; + } + return false; + } + + 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) { + 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 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; + } + // 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 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 (x = 0; x < schema_arr.length; x += 1) { + schema = schema_arr[x].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[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) { + return schema_arr; + } + ret_arr[0].circular = circular; + ret_arr.external_reference = schema_arr.external_reference; + return ret_arr; + } + return schema_arr; + } + + 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 || + !(schema_item.schema.hasOwnProperty('type') || + 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; + 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 () { + var notify = { + action: "add" + }; + return g.getContent() + .push(function (value) { + return event(schema_alternatives[value[scope]].value); + }) + .push(function (v) { + if (v) { + return RSVP.Queue() + .push(function () { + notify.scope = v.scope; + notify.path = v.path; + if (rerender) { + return rerender(g, schema_alternatives); + } + return render_options; + }) + .push(function (render_options) { + return g.render(render_options); + }) + .push(function () { + return gadget.rootNotifyChange(notify); + }); + } + }); + }, + 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 () { + var notify = { + action: "add" + }; + return event(schema_alternatives[0].value) + .push(function (v) { + if (v) { + return RSVP.Queue() + .push(function () { + notify.scope = v.scope; + notify.path = v.path; + if (rerender) { + return rerender(undefined, schema_alternatives); + } + return true; + }) + .push(function (r) { + if (!r) { + input.setAttribute("style", "display: none;"); + } else { + input.removeAttribute("style"); + } + return gadget.rootNotifyChange(notify); + }); + } + }); + }, + 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, div_input, path, schema_path) { + var input, + array_path, + is_items_arr = schema.items instanceof Array, + minItems = schema.minItems || 0; + if (json_document instanceof Array && + json_document.length === 0) { + div_input.setAttribute("data-json-empty-array", "true"); + } + + function current_array_length() { + var array = div_input + .querySelectorAll("div[data-gadget-parent-scope='" + + gadget.element.getAttribute("data-gadget-scope") + + "']"); + return array.length; + } + + function add_item_form(id, required) { + return function (value) { + return gadget.expandSchema(schema.items, schema_path + '/items', array_path + id, required) + .push(function (s_arr) { + return addSubForm({ + gadget: gadget, + parent_type: 'array', + parent_path: path, + type: value && value.schema.type, + selected_schema: value, + schema_arr: s_arr, + required: required + }); + }); + }; + } + + function element_append(child) { + if (child) { + input.parentNode.insertBefore(child, input); + div_input.removeAttribute("data-json-empty-array"); + return { + scope: child.getAttribute("data-gadget-scope"), + path: "/" + }; + } + } + + function div_append(child) { + if (child) { + div_input.appendChild(child); + div_input.removeAttribute("data-json-empty-array"); + } + } + + // XXX add failback rendering if json_document not array + // input = render_textarea(schema, default_value, "array"); + return gadget.getJsonPath(path) + .push(function (p) { + array_path = p; + return RSVP.all([ + expandItems(gadget, schema.items, schema_path + '/items', p, minItems), + gadget.expandSchema(schema.additionalItems, schema_path + '/additionalItems', p, false) + ]); + }) + .push(function (arr) { + var queue = RSVP.Queue(), + i, + 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]; + } else { + schema_arr = additionalItems; + } + } + queue + .push( + addSubForm.bind(gadget, { + gadget: gadget, + parent_type: 'array', + parent_path: path, + schema_arr: schema_arr, + json_document: json_document[i], + required: i < minItems + }) + ) + .push(div_append); + } + len = json_document.length; + } + + 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', + parent_path: path, + schema_arr: schema_arr, + 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', + parent_path: path, + type: value.type, + selected_schema: value, + schema_arr: schema_arr + }) + .push(element_append); + })); + } else { + if (minItems > len && checkSchemaArrOneChoise(schema_arr)) { + for (i = len; i < minItems; i += 1) { + queue + .push(add_item_form(i, true)) + .push(div_append); + } + } + + queue.push(render_schema_selector.bind(gadget, + gadget, "add item to array", + schema_arr, function (value) { + return add_item_form(current_array_length(), false)(value) + .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); + gadget.props.arrays[path] = div_input; + }); + } + + function create_layout(gadget, options, create_field) { + var div, + div_input; + return RSVP.Queue() + .push(function () { + var delete_button, + label, + label_text; + div = document.createElement("div"); + div.setAttribute("class", "jsonformfield ui-field-contain"); + if (options.schema.description) { + div.title = options.schema.description; + } + // if (property_name && !options.json_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 = [options.property_name, options.schema_ob.title] + .filter(function (v) { return v; }) + .join(" ") + // use non-breaking hyphen + .replace(/-/g, "‑"); + if (options.property_name || options.top) { + if (options.top) { + label = document.createElement("span"); + label.textContent = label_text; + options.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") + + options.json_path + '/'); + div_input.setAttribute("class", "input"); + return div_input; + }) + .push(function (div_input) { + return create_field(div_input); + }) + .push(function (input) { + var span_info, + error_message; + if (input) { + // object and array excluded from + // gadget.props.inputs not contain values + gadget.props.inputs.push(input); + input.name = options.json_path; + input.required = options.required; + if (options.type_changed) { + input.setAttribute('data-origin-value', JSON.stringify(options.json_document)); + } + // XXX for gui + //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", options.json_path + '/'); + div.setAttribute("data-json-type", options.type); + if (options.required) { + div.setAttribute("data-json-required", "true"); + } + } + + if (options.schema.info !== undefined) { + span_info = document.createElement("span"); + span_info.textContent = options.schema.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 div; + }); + } + + function render_field(gadget, property_name, path, schema_arr, json_document, root, options) { + var type, + input, + schema, + schema_path, + schema_ob, + first_path, + type_changed; + + 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 && property_name) { + first_path = path + encodeJsonPointer(property_name); + } else { + first_path = ""; + } + + if (schema === undefined) { + schema = getDocumentSchema(json_document); + } + + if (getDocumentType(schema.type) === "string") { + type = schema.type; + } else if (type === undefined && + json_document === undefined && + getDocumentType(schema.type) === "array") { + type = schema.type[0]; + } + if (["object", "array"].indexOf(type) >= 0 && + !(path !== "" && json_document === undefined) && + getDocumentType(json_document) !== type) { + if (gadget.props.saveOrigValue) { + // XXX is not useful for user + // only for tests + schema = { + const: json_document + }; + } else { + gadget.props.changed.push(first_path); + } + } + 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 = json_document !== undefined && + typeof json_document !== type; + } + + // 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); + } + 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}, json_document); + } + + if (!input && type === "boolean") { + input = render_boolean(gadget, json_document); + } + + if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) { + if (schema.contentMediaType === "text/plain") { + input = render_textarea(json_document, "string"); + } else { + input = document.createElement("input"); + if (json_document !== undefined) { + if (typeof json_document === "object") { + input.value = JSON.stringify(json_document); + } else { + input.value = json_document; + } + } + + if (type === "integer" || type === "number") { + input.setAttribute("data-json-type", type); + if (json_document === undefined || json_document === null || + typeof json_document === "number") { + input.type = "number"; + } + if (type === "integer") { + input.setAttribute("step", "1"); + 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; + } + } + 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 { + input.type = "text"; + 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 (schema.format === 'uri') { + input.type = "url"; + input.spellcheck = false; + } + } + } + } + // render input end + + // html layout render begin + options.schema = schema; + options.schema_ob = schema_ob; + options.json_path = first_path; + options.json_document = json_document; + options.root = root; + options.property_name = property_name; + options.type_changed = type_changed; + return create_layout(gadget, options, function (div_input) { + var q; + if (input) { + return input; + } + if (type === "array") { + q = render_array( + gadget, + schema, + json_document, + div_input, + first_path + '/', + schema_path + ); + } + if (type === "object") { + q = render_object( + gadget, + schema, + json_document, + div_input, + first_path + '/', + schema_path + ); + } + return q; + }) + .push(function (div) { + 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 = schema.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.getJsonPath(path) + .push(function (p) { + return g.expandSchema(schema, schema_path, p); + }) + .push(function (schema_arr) { + var queue = RSVP.Queue(), + property_name; + if (checkSchemaArrOneChoise(schema_arr) && schema_arr[0].schema.title) { + title = schema_arr[0].schema.title; + // XXX change placeholder again + input.placeholder = "name of " + title; + } + 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, + parent_path: path, + schema_arr: schema_arr, + json_document: 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, + parent_path: path, + type: value.type, + schema_arr: [value] + }) + .push(element_append) + .push(undefined, function (err) { + // XXX notify user + console.error(err); + }); + }); + }); + return queue; + }) + .push(function (input) { + div_input.appendChild(input); + div.appendChild(div_input); + return div; + }); + } + + function checkSchemaIsMetaSchema(schema) { + if (!schema) { + return false; + } + 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": + case "contains": + if (!checkSchemaType(current_document.type, "array")) { + return false; + } + break; + case "required": + case "maxProperties": + case "minProperties": + case "additionalProperties": + case "properties": + case "patternProperties": + case "dependencies": + case "propertyNames": + if (!checkSchemaType(current_document.type, "object")) { + return false; + } + break; + case "maxLength": + case "minLength": + case "pattern": + case "contentEncoding": + case "contentMediaType": + 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": + case "contains": + case "dependencies": + case "contentEncoding": + case "contentMediaType": + return false; + } + } + return true; + } + + render_object = function (g, schema, json_document, root, path, schema_path) { + var required = schema.required || [], + schema_editor = checkSchemaIsMetaSchema(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); + return { + scope: child.getAttribute("data-gadget-scope"), + path: "/" + }; + } + } + + function root_append(child) { + root.appendChild(child); + } + + if (json_document === undefined) { + json_document = {}; + } + + return expandProperties(g, schema.properties, schema_path + '/properties/', path, required) + .push(function (ret) { + var schema_arr, + q = RSVP.Queue(), + filtered_schema_arr, + key; + properties = ret; + for (key in properties) { + if (properties.hasOwnProperty(key)) { + schema_arr = properties[key]; + filtered_schema_arr = schemaArrFilteredByDocument(schema_arr, json_document[key]); + // XXX need schema merge with patternProperties passed key + if (checkSchemaArrOneChoise(schema_arr) && !schema_arr.external_reference) { + if (required.indexOf(key) >= 0) { + used_properties[key] = false; + q.push(render_field.bind(g, g, key, path, + filtered_schema_arr, json_document[key], root, {required: true}) + ); + } + if (!used_properties.hasOwnProperty(key) && + !schema_editor && + (checkSchemaSimpleType(filtered_schema_arr) || !filtered_schema_arr[0].circular) + ) { + used_properties[key] = false; + q.push(render_field.bind(g, g, key, path, + filtered_schema_arr, json_document[key], root, { + required: false, + delete_button: false + })); + } + } + if (!used_properties.hasOwnProperty(key) && + (json_document.hasOwnProperty(key) || + schema_arr.external_reference)) { + used_properties[key] = ""; + q.push( + addSubForm.bind(g, { + gadget: g, + property_name: key, + parent_path: path, + delete_button: !schema_arr.external_reference, + schema_arr: filtered_schema_arr, + json_document: json_document[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, + parent_path: path, + type: value.type, + schema_arr: [value] + }) + .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, + 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) && + !(schema_editor && current_document && + !filterPropery(item.value.property_name, current_document))) { + 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(), + key, + additionalProperties; + + // XXX for pattern properties needs schemas merge for + // all passed patterns + if (schema.patternProperties !== undefined) { + for (key in schema.patternProperties) { + if (schema.patternProperties.hasOwnProperty(key)) { + if (key === ".*" || + key === "^.*$" || + key === ".*$" || + key === "^.*" + ) { + // additionalProperties nether used in this case + additionalProperties = false; + } + queue + .push(render_object_additionalProperty.bind(g, + g, + key + " property", + json_document, + path, + schema.patternProperties[key], + schema_path + '/patternProperties/' + key, + used_properties, + element_append + )) + .push(root_append); + } + } + } + + if (additionalProperties === undefined) { + if (schema.additionalProperties === undefined) { + additionalProperties = true; + } else { + additionalProperties = schema.additionalProperties; + } + } + if (additionalProperties !== false) { + queue + .push(render_object_additionalProperty.bind(g, + g, + "additional property", + json_document, + path, + additionalProperties, + schema_path + '/additionalProperties', + used_properties, + element_append + )) + .push(root_append); + } + + return queue; + }) + .push(function () { + var key, + queue = RSVP.Queue(); + for (key in json_document) { + if (json_document.hasOwnProperty(key)) { + if (!used_properties.hasOwnProperty(key)) { + if (g.props.ignore_incorrect) { + g.props.changed.push(path); + return; + } + queue + .push( + addSubForm.bind(g, { + gadget: g, + property_name: key, + parent_path: path, + schema_arr: [{ + schema: undefined, + schema_path: "" + }], + json_document: json_document[key] + }) + ) + .push(root_append); + } + } + } + return queue; + }); + }; + + function getFormValuesAsJSONDict(g) { + var multi_level_dict = {"": {}}, + is_empty = true, + scope, + options = g.props, + array, + path, + key, + i, + len, + json_dict = {}, + 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; + is_empty = false; + } else { + return d[kk]; + } + } else { + if (!d.hasOwnProperty(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 () { + 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); + }); + } + + 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-json-empty-array')) { + 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 () { + // 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 { + convertOnMultiLevel(multi_level_dict, path, []); + } + } + } + } + + if (is_empty) { + 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[""]; + }); + } + + function getSubGadgetElement(g, scope) { + return g.element.querySelector("div[data-gadget-scope='" + scope + "']"); + } + + rJS(window) + .ready(function () { + var g = this; + g.props = { + needValidate: false + }; + g.options = {}; + }) + .declareAcquiredMethod("rNotifyChange", "rootNotifyChange") + .declareMethod("rootNotifyChange", function (v) { + var g = this, + queue, + cur_scope = g.element.getAttribute("data-gadget-scope"); + this.props.needValidate = true; + if (v.scope && v.scope !== cur_scope) { + queue = g.getDeclaredGadget(v.scope); + } else { + queue = new RSVP.Queue() + .push(function () { + return g; + }); + } + if (!v.scope) { + v.scope = cur_scope; + } + return queue + .push(function (gadget) { + return gadget.getJsonPath(v.path); + }) + .push(function (p) { + g.rNotifyChange({ + scope: v.scope, + rel_path: v.path, + path: p, + ref: g.props.schema_arr.external_reference, + action: v.action + }); + }); + }) + .declareMethod("selfRemove", function () { + var g = this, + sub_gadets = g.element.querySelectorAll("div[data-gadget-scope]"), + i, + tasks = []; + for (i = 0; i < sub_gadets.length; i += 1) { + tasks.push( + g.notifyInvalid([], sub_gadets[i].getAttribute("data-gadget-scope")) + ); + } + tasks.push(g.notifyInvalid([], g.element.getAttribute("data-gadget-scope"))); + g.props.deleted = true; + return new RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }) + .push(function () { + return g.getJsonPath(); + }) + .push(function (path) { + return g.deleteChildren(path); + }); + }) + .declareAcquiredMethod("deleteChildren", "deleteChildren") + .allowPublicAcquisition("deleteChildren", function (arr, scope) { + var g = this, + key, + i, + path = arr[0], + 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]; + } + } + } + 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); + } + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }) + .push(function () { + return g.rootNotifyChange({ + scope: scope, + path: path, + action: "delete" + }); + }) + .push(function () { + // remove gadget at end otherwise + // current queue canceled. + element.parentNode.removeChild(element); + }); + }) + + .declareAcquiredMethod('parentGetJsonPath', 'parentGetJsonPath') + .allowPublicAcquisition('parentGetJsonPath', function (arr, scope) { + var g = this, + key, + arrays = g.props.arrays, + array, + len, + i, + objects = g.props.objects, + o, + element = getSubGadgetElement(g, scope), + parent; + if (element) { + parent = element.getAttribute("data-json-parent"); + } else { + parent = arr[0]; + } + if (arrays.hasOwnProperty(parent)) { + array = arrays[parent] + .querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']"); + len = array.length; + for (i = 0; i < len; i += 1) { + if (array[i].getAttribute('data-gadget-scope') === scope) { + break; + } + } + return g.parentGetJsonPath(this.element.getAttribute("data-json-parent")) + .push(function (path) { + return path + parent + i; + }); + } + if (objects.hasOwnProperty(parent)) { + o = objects[parent]; + for (key in o) { + if (o.hasOwnProperty(key)) { + if (o[key] === scope) { + break; + } + } + } + return g.parentGetJsonPath(this.element.getAttribute("data-json-parent")) + .push(function (path) { + return path + parent + encodeJsonPointer(key); + }); + } + }) + .declareMethod('getJsonPath', function (parent_path) { + return this.parentGetJsonPath(this.element.getAttribute("data-json-parent")) + .push(function (p) { + if (parent_path) { + p = p + parent_path; + } + return p; + }); + }) + + .declareMethod('getGadgetByPath', 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.getGadgetByPath(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 { + gadget: g, + path: 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.getGadgetByPath(next_data_path); + }); + } + } + return { + gadget: g, + path: data_path + }; + }) + .declareMethod('getElementByPath', function (data_path) { + return this.getGadgetByPath(data_path) + .push(function (ret) { + return ret.gadget.element.querySelector("#" + + ret.gadget.element.getAttribute("data-gadget-scope") + + escapeId(ret.path)); + }); + }) + .declareAcquiredMethod("notifyValid", "notifyValid") + .declareAcquiredMethod("notifyInvalid", "notifyInvalid") + + .allowPublicAcquisition("notifyValid", function () { + return true; + }) + .allowPublicAcquisition("notifyChange", function (arr, sub_scope) { + var g = this, + evt = arr[0], + event_object; + event_object = g.props.add_custom_data[sub_scope]; + if (evt.type === "change") { + if (event_object) { + return event_object.event(); + } + return g.rootNotifyChange({ + path: evt.target.name + }); + } + }) + .declareMethod('renderForm', function (options) { + var g = this, + property_name = g.element.getAttribute('data-json-property-name'), + schema = options.schema_arr !== undefined && options.schema_arr[0].schema; + g.props.saveOrigValue = options.saveOrigValue; + g.props.path = options.path; // self gadget scope + if (!property_name || !options.display_label) { + property_name = ""; + } + if (options.delete_button === undefined) { + if (options.top) { + options.delete_button = false; + } else { + options.delete_button = !options.required; + } + } + 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); + if (checkSchemaIsMetaSchema(schema)) { + g.props.updatePropertySelectors = true; + g.props.current_document = options.document; + } + g.props.property_name = property_name; + g.props.schema_arr = options.schema_arr; + // XXX realized only for enum and object + g.props.ignore_incorrect = options.ignore_incorrect; + g.props.render_opt = { + type: options.type, + selected_schema: options.selected_schema, + required: options.required, + delete_button: options.delete_button, + top: options.top + }; + return g.rerender({value: options.document}); + }) + + .declareMethod('rerender', function (opt) { + this.props.rerender = true; + var g = this, + for_delete, + root = g.element.querySelector('[data-json-path="/"]'); + if (opt.ignore_incorrect !== undefined) { + g.props.ignore_incorrect = opt.ignore_incorrect; + } + g.props.changed = []; + g.props.inputs = []; + g.props.add_buttons = []; + g.props.add_custom_data = {}; + g.props.arrays = {}; + g.props.objects = {}; + if (!root) { + root = g.element; + } + for_delete = Array.from(root.childNodes); + if (opt.schema) { + if (g.props.render_opt.selected_schema) { + g.props.render_opt.selected_schema = + JSON.parse(JSON.stringify(g.props.render_opt.selected_schema)); + g.props.render_opt.selected_schema.schema = opt.schema; + } + g.props.schema_arr[0].schema = opt.schema; + } + return render_field(g, g.props.property_name, "", g.props.schema_arr, + opt.value, root, g.props.render_opt) + .push(function () { + var value = opt.value, + i; + for (i = 0; i < for_delete.length; i += 1) { + root.removeChild(for_delete[i]); + } + if (g.props.changed.length > 0) { + value = undefined; + } + g.props.changed = g.props.changed.map(function (el) { + if (el.name) { + return el.name; + } + return el; + }); + return g.checkValidity(value, opt.schema); + }) + .push(function () { + g.props.rerender = false; + return g.element; + }) + .push(undefined, function (err) { + console.error(err); + throw err; + }); + }) + + .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, + field_list = this.props.inputs, + input, + changed = false, + 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); + } + } + + 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; + } + break; + } + } + if (changed) { + return this.rootNotifyChange({ + path: input.name + }); + } + }) + + .declareAcquiredMethod("rootGetSchema", "getSchema") + .declareMethod('getSchema', function (json_document) { + var g = this, + schema_arr = g.props.schema_arr, + schema; + // XXX complex need simplify + if (g.props.render_opt.selected_schema) { + schema = g.props.render_opt.selected_schema; + } else { + if (json_document !== undefined && !g.props.render_opt.top) { + schema = schemaArrFilteredByDocument(schema_arr, json_document)[0]; + } else if (schema_arr.schema_path && !schema_arr.external_reference) { + schema = schema_arr; + } else if (json_document !== undefined) { + schema = schemaArrFilteredByDocument(schema_arr, json_document)[0]; + } else { + schema = schema_arr[0]; + } + } + if (schema_arr && schema_arr.external_reference) { + return schema; + } + return g.rootGetSchema(schema.schema_path); + }) + + .declareMethod('checkValidity', function (json_document, schema) { + var g = this; + return RSVP.Queue() + .push(function () { + if (json_document === undefined) { + return g.getContent(); + } + return json_document; + }) + .push(function (json_d) { + json_document = json_d; + if (schema === undefined) { + return g.getSchema(json_document); + } + return schema; + }) + .push(function (s) { + schema = s; + return tv4.validateMultiple(json_document, schema); + }) + .push(function (validation) { + var i, + error, + tasks = [], + errors = [], + self_scope = g.element.getAttribute("data-gadget-scope"), + ret_errors = []; + + errors = errors.concat(validation.errors); + errors = errors.concat(validation.missing); + + if (errors.length === 0) { + return g.notifyInvalid( + errors, + self_scope + ); + } + + function print_error(error) { + return function (ret) { + var scope = ret.gadget.element.getAttribute("data-gadget-scope"), + parent_scope = ret.gadget.element.getAttribute("data-gadget-parent-scope"); + if ((scope === self_scope && (g.props.render_opt.top || ret.path !== "/")) || + (parent_scope === self_scope && ret.path === "/")) { + error.element = ret.gadget.element.querySelector("#" + + scope + + escapeId(ret.path)); + ret_errors.push(error); + } + }; + } + for (i = 0; i < errors.length; i += 1) { + error = errors[i]; + tasks.push( + g.getGadgetByPath(error.dataPath || "/") + .push(print_error(error)) + ); + } + + return RSVP.Queue() + .push(function () { + return RSVP.all(tasks); + }) + .push(function () { + return g.notifyInvalid( + ret_errors, + self_scope + ); + }); + }); + }) + + .allowPublicAcquisition("printErrors", function () { + this.props.needValidate = true; + }) + .declareAcquiredMethod("parentPrintErrors", "printErrors") + .declareJob("reValidate", function (json_document, schema) { + var gadget = this; + return this.checkValidity(json_document, schema) + .push(function () { + return gadget.parentPrintErrors(); + }) + .push(function () { + gadget.props.needValidate = false; + }); + }) + + .onLoop(function () { + if (this.props.needValidate && !this.props.rerender) { + return this.reValidate(); + } + }, 500) + + .onEvent('input', function (evt) { + 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; + break; + } + } + if (changed) { + return gadget.rootNotifyChange({ + path: input.name + }); + } + }) + + .declareMethod('getContent', function () { + var g = this; + if (g.props.deleted) { + return; + } + 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, 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 0000000000000000000000000000000000000000..00514ccee83e70a05fd60d7c9b6f7df00c2b4241 --- /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 0000000000000000000000000000000000000000..820b4ab6fee5ba4ff2d7ca56d03a1e5242e7cb95 --- /dev/null +++ b/bt5/erp5_json_form/SkinTemplateItem/portal_skins/erp5_json_form/jsonform/tv4.js.js @@ -0,0 +1,1754 @@ +/* +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. +*/ +/*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); + } else if (typeof module !== 'undefined' && module.exports){ + // CommonJS. Define export. + module.exports = factory(); + } else { + // Browser globals + 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) { + 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 */ ) { + /*jslint bitwise: true */ + 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.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 === undefined || schema === true) { + 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.validateAllValidators(data, schema, dataPointerPath); + + 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) { + 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"); + } + 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.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; + } + 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 === 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 === 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; +}; + +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.validateArrayContains(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.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++) { + 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.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)) { + 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, + BOOLEAN_SCHEMA_FALSE: 14, + CONST_NOT_EQUAL: 15, + // 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, + 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, + // 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\"", + 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}", + 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})", + 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})", + // 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) { + /*jshint -W002: true*/ + 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 0000000000000000000000000000000000000000..af0ecfd7f377f7057ef68765096c4c18edb93ebc --- /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 0000000000000000000000000000000000000000..58718d3dc1d73abb27a8c3784039598c75d61dc4 --- /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 0000000000000000000000000000000000000000..db80eea7f74d654663adfb80d3bbfc5671366893 --- /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 0000000000000000000000000000000000000000..26febe9f6948c2eba71c398299b59e0bd8507dfb --- /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 0000000000000000000000000000000000000000..452d733bbaba8b9500bef8451d20525ed4bfe18d --- /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 0000000000000000000000000000000000000000..56a6051ca2b02b04ef92d5150c9ef600403cb1de --- /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 0000000000000000000000000000000000000000..d1e8bf126ce11a70b64e293c5314971a83a1288f --- /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 0000000000000000000000000000000000000000..d1e8bf126ce11a70b64e293c5314971a83a1288f --- /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 0000000000000000000000000000000000000000..48360de846a2e022a0b981d250895f20d3480d34 --- /dev/null +++ b/bt5/erp5_json_form/bt/version @@ -0,0 +1 @@ +5.4.7 \ No newline at end of file diff --git a/bt5/erp5_officejs_ooffice/PathTemplateItem/web_page_module/gadget_ooffice_spreadsheet_appcache.xml b/bt5/erp5_officejs_ooffice/PathTemplateItem/web_page_module/gadget_ooffice_spreadsheet_appcache.xml index 04e718e17f193b85418f9e977e310592a93b8208..1c9c9fe05194ea0cb1388797df78e7e0b4dbd6e8 100644 --- a/bt5/erp5_officejs_ooffice/PathTemplateItem/web_page_module/gadget_ooffice_spreadsheet_appcache.xml +++ b/bt5/erp5_officejs_ooffice/PathTemplateItem/web_page_module/gadget_ooffice_spreadsheet_appcache.xml @@ -232,6 +232,16 @@ gadget_ooffice_spreadsheet_router.html\n gadget_officejs_jio_spreadsheet_view.html\n gadget_officejs_jio_spreadsheet_view.js\n \n +#jsonform\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 #onlyoffice editor\n jio.js\n zipfilestorage-with-jszip.js\n @@ -239,6 +249,10 @@ onlyoffice.gadget.html\n onlyoffice.gadget.js\n onlyoffice.gadget.appcache\n #autogenerated for: erp5_onlyoffice_webapps\n +onlyoffice/remote_settings.html\n +onlyoffice/remote_settings.js\n +onlyoffice/remote_settings.json\n +onlyoffice/xmla_connection.json\n onlyoffice/web-apps/apps/common/Analytics.js\n onlyoffice/web-apps/apps/common/Gateway.js\n onlyoffice/web-apps/apps/common/IrregularStack.js\n @@ -337,6 +351,7 @@ onlyoffice/web-apps/apps/common/main/lib/view_folder/Plugins.js\n onlyoffice/web-apps/apps/common/main/lib/view_folder/RenameDialog.js\n onlyoffice/web-apps/apps/common/main/lib/view_folder/ReviewChanges.js\n onlyoffice/web-apps/apps/common/main/lib/view_folder/SearchDialog.js\n +onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js\n onlyoffice/web-apps/apps/css.js\n onlyoffice/web-apps/apps/documenteditor/main/app.js\n onlyoffice/web-apps/apps/documenteditor/main/app/collection/EquationGroups.js\n diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.appcache.appcache b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.appcache.appcache index b56bbcc2d223ae7ecf68c58a26d0c41db5dbdb59..3618a931f1894351ec455f643f7a594be9aa9bee 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.appcache.appcache +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.appcache.appcache @@ -4,7 +4,31 @@ rsvp.js renderjs.js jio.js jiodev.js + +#jsonform +gadget_erp5_global.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 + #autogenerated for: erp5_onlyoffice_webapps +onlyoffice/remote_settings.html +onlyoffice/remote_settings.js +onlyoffice/remote_settings.json +onlyoffice/xmla_connection.json +onlyoffice/olap_wizard.html +onlyoffice/olap_wizard.js +onlyoffice/olap_wizard.json +onlyoffice/xmla_client.html +onlyoffice/xmla_client.js onlyoffice/web-apps/apps/common/Analytics.js onlyoffice/web-apps/apps/common/Gateway.js onlyoffice/web-apps/apps/common/IrregularStack.js @@ -103,6 +127,8 @@ onlyoffice/web-apps/apps/common/main/lib/view_folder/Plugins.js onlyoffice/web-apps/apps/common/main/lib/view_folder/RenameDialog.js onlyoffice/web-apps/apps/common/main/lib/view_folder/ReviewChanges.js onlyoffice/web-apps/apps/common/main/lib/view_folder/SearchDialog.js +onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js +onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js onlyoffice/web-apps/apps/css.js onlyoffice/web-apps/apps/documenteditor/main/app.js onlyoffice/web-apps/apps/documenteditor/main/app/collection/EquationGroups.js diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.html.html b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.html.html index fe1ebb6453e20364313b6f7617b8114035c89875..5044803242669203d0a5b3bbdea77587b7698ff8 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.html.html +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.html.html @@ -72,5 +72,8 @@
+
\ No newline at end of file diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.js.js index efdab58f45def52d68d50f75393dcc2d09113073..914246e11e1f13c6d7681399a25829ba3bae34c0 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice.gadget.js.js @@ -1,6 +1,7 @@ /*global window, rJS, RSVP, DocsAPI, console, document, - Common, require, jIO, URL, FileReader, atob, ArrayBuffer, + Common, AscCommon, require, jIO, URL, FileReader, atob, ArrayBuffer, Uint8Array, XMLHttpRequest, Blob, Rusha, define, + Uint8ClampedArray, Asc, History, TextDecoder, DesktopOfflineAppDocumentEndSave*/ /*jslint nomen: true, maxlen:80, indent:2*/ "use strict"; @@ -51,6 +52,200 @@ DocsAPI.DocEditor.version = function () { return new Blob([ab], {type: mimeString}); } + function printOlapTable(xmla_client, data) { + var Api = Asc.editor, + s = Api.GetActiveSheet(), + connection_name, + start_row, + start_column; + + function endTransaction() { + s.worksheet.workbook.dependencyFormulas.unlockRecal(); + History.EndTransaction(); + Api._onUpdateAfterApplyChanges(); + Api._onUpdateDocumentCanSave(); + } + + function setCell(row, col, value, row1, col1) { + // setValue on range + s.GetRangeByNumber(row, col).range._foreach(function (cell) { + cell.setValue(value); + }); + if (typeof row1 === "number" && typeof col1 === "number") { + var range = s.worksheet.getRange3(row, col, row1, col1); + if (col1 !== col) { + range.setAlignHorizontal(AscCommon.align_Center); + } + if (row1 !== row) { + range.setAlignVertical(Asc.c_oAscVAlign.Top); + } + s.worksheet.mergeManager.add(range.bbox, 1); + } + } + + function print_titles(levels, begin_row, begin_column, columns) { + var members = [], + member, + i, + m, + col1, + row1, + func, + x, + z, + row, + col, + span, + repeats; + + function amp_arr_length(amp, arr) { + if (arr.length === 0) { + return amp; + } + return amp * arr.length; + } + + for (i = 0; i < levels.length; i += 1) { + members = levels[i]; + span = levels.slice(i + 1).reduce(amp_arr_length, 1); + repeats = levels.slice(0, i).reduce(amp_arr_length, 1); + for (z = 0; z < repeats * members.length * span; z += (members.length * span)) { + for (m = 0; m < members.length; m += 1) { + member = members[m]; + func = "=CUBEMEMBER(" + connection_name + ',"' + member.uname + '")'; + for (x = 1; x < span; x += 1) { + if (columns) { + row = begin_row + i; + col = begin_column + z + (m * span) + x; + } else { + row = begin_row + z + (m * span) + x; + col = begin_column + i; + } + setCell(row, col, func); + } + if (columns) { + row = begin_row + i; + col = begin_column + z + (m * span); + if (span > 1) { + row1 = row; + col1 = col + span - 1; + } else { + row1 = undefined; + col1 = undefined; + } + } else { + row = begin_row + z + (m * span); + col = begin_column + i; + if (span > 1) { + row1 = row + span - 1; + col1 = col; + } else { + row1 = undefined; + col1 = undefined; + } + } + setCell(row, col, func, row1, col1); + } + } + } + return repeats * members.length * span; + } + + if (!data.connection_name) { + return; + } + + return RSVP.Queue() + .push(function () { + var clean_range = s.worksheet.getRange3(0, 0, 10000, 10000); + // var active = s.GetActiveCell(); + // var row = active.GetRow(); + // var col = active.GetCol(); + start_row = 0; + start_column = 0; + History.Create_NewPoint(); + + s.worksheet.workbook.dependencyFormulas.lockRecal(); + + clean_range.cleanAll(); + s.worksheet.workbook.handlers.trigger("cleanCellCache", + s.worksheet.getId(), {0: clean_range.bbox}, + AscCommonExcel.c_oAscCanChangeColWidth.none); + AscCommonExcel.g_oVLOOKUPCache.clean(); + AscCommonExcel.g_oHLOOKUPCache.clean(); + + // (new Asc.asc_CDefName( + // "name111", + // "Sheet1!$A$3:$D$13", + // null, // or number of sheet + // this.props.asc_getIsTable(), + // false, // Hidden + // false // locked + // )); + // rows titles + + setCell(start_row, start_column, "Connection:"); + setCell(start_row, start_column + 1, data.connection_name); + connection_name = "$B$1"; + start_row += 2; + + // XXX default absent in json schema + data.rows = data.rows || []; + data.columns = data.columns || []; + + return RSVP.all([ + RSVP.all(data.rows + .filter(function (i) { + return i.hasOwnProperty("level"); + }) + .map(function (i) { + return xmla_client + .getMembersOnLevel(data.connection_name, i.level); + })), + RSVP.all(data.columns + .filter(function (i) { + return i.hasOwnProperty("level"); + }) + .map(function (i) { + return xmla_client + .getMembersOnLevel(data.connection_name, i.level); + })) + ]); + }) + .push(function (arr) { + var rows = arr[0], + columns = arr[1], + c, + c_len, + r, + r_len, + formula; + + r_len = print_titles(rows, start_row + columns.length, start_column, false); + c_len = print_titles(columns, start_row, start_column + rows.length, true); + + r_len = r_len + start_row + columns.length; + c_len = c_len + start_column + rows.length; + for (r = start_row + columns.length; r < r_len; r += 1) { + for (c = start_column + rows.length; c < c_len; c += 1) { + formula = "CUBEVALUE(" + connection_name + ',' + + s.worksheet.getRange3(r, start_column, r, start_column + rows.length -1).getName() + + ',' + + s.worksheet.getRange3(start_row, c, start_row + columns.length - 1, c).getName() + + ')'; + setCell(r, c, + "=IF(ISTEXT(" + formula + '),0,' + formula + ')'); + } + } + + endTransaction(); + }) + .push(undefined, function (error) { + endTransaction(); + throw error; + }); + } + rJS(window) .ready(function (g) { g.props = { @@ -69,11 +264,13 @@ DocsAPI.DocEditor.version = function () { .declareAcquiredMethod("triggerSubmit", "triggerSubmit") .declareAcquiredMethod("triggerMaximize", "triggerMaximize") .declareAcquiredMethod('getSetting', 'getSetting') + .declareAcquiredMethod('notifyChange', 'notifyChange') .declareMethod("jio_getAttachment", function (docId, attId, opt) { var g = this, - queue; + convert; + opt = opt || {}; if (attId === 'body.txt' || attId === 'Editor.bin') { - opt = 'asBinArray'; + opt = { 'format': 'bin_array' }; if (!docId) { docId = '/'; } @@ -82,48 +279,43 @@ DocsAPI.DocEditor.version = function () { docId = '/media/'; } } - queue = g.props.value_zip_storage.getAttachment(docId, attId) + if (opt.format === "blob_url") { + convert = opt.format; + delete opt.format; + } + if (opt.format === "bin_array") { + convert = opt.format; + opt.format = 'array_buffer'; + } + return g.props.value_zip_storage.getAttachment(docId, attId, opt) .push(function (blob) { - var data; - if (opt === "asText") { - data = jIO.util.readBlobAsText(blob) - .then(function (evt) { - return evt.target.result; - }); - } else if (opt === "asBinArray") { - data = jIO.util.readBlobAsArrayBuffer(blob) - .then(function (evt) { - return new Uint8ClampedArray(evt.target.result); - }); - } else if (opt === "asBlobURL") { - data = URL.createObjectURL(blob); - } else if (opt === "asDataURL") { - data = new RSVP.Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - resolve(reader.result); - }); - reader.addEventListener('error', reject); - reader.readAsDataURL(blob); - }); - } else { - data = blob; + if (convert === "bin_array") { + return new Uint8ClampedArray(blob); } - return data; + if (convert === "blob_url") { + return URL.createObjectURL(blob); + } + return blob; }); - return queue; }) .declareMethod("jio_putAttachment", function (docId, atId, data) { var g = this, zip = g.props.value_zip_storage, queue, content_type, - start = data.slice(0, 5); + start; if (!docId) { docId = '/media/'; } - if (typeof data === 'string' && start === "data:") { - data = dataURLtoBlob(data); + if (typeof data === 'string') { + start = data.slice(0, 5); + if (start === "data:") { + data = dataURLtoBlob(data); + } + } + if (typeof data === 'object' && + !(data instanceof Blob)) { + data = new Blob([JSON.stringify(data, undefined, 2)]); } if (atId) { queue = zip.putAttachment(docId, atId, data) @@ -168,6 +360,97 @@ DocsAPI.DocEditor.version = function () { } return queue; }) + .allowPublicAcquisition("notifyChange", function (arr, scope) { + var gadget = this, + content; + if (scope === "remote_settings") { + return this.getDeclaredGadget(scope) + .push(function (g) { + return g.getContent(); + }) + .push(function (data) { + content = data; + return gadget + .jio_putAttachment('/', 'remote_settings.json', data); + }) + .push(function () { + History.Create_NewPoint(); + Asc.editor._onUpdateDocumentCanSave(); + return gadget.changeState({changed: true}); + }) + .push(function () { + return gadget.getDeclaredGadget("xmla_client"); + }) + .push(function (g) { + return g.setConnectionsSettings(content); + }) + .push(function () { + return gadget.getDeclaredGadget("xmlawizard"); + }) + .push(function (g) { + return g.rerender(); + }) + .push(undefined, function (e) { + console.error(e); + }); + } + if (scope === "xmlawizard") { + return this.getDeclaredGadget(scope) + .push(function (g) { + return RSVP.all([ + gadget.getDeclaredGadget("xmla_client"), + g.getContent() + ]); + }) + .push(function (arr) { + return printOlapTable(arr[0], arr[1]); + }) + .push(function () { + return gadget.changeState({changed: true}); + }) + .push(undefined, function (e) { + console.error(e); + }); + } + }) + .allowPublicAcquisition("getRemoteSettings", function () { + return this.jio_getAttachment('/', 'remote_settings.json', {format: 'json'}) + .push(undefined, function (error) { + if (error.status_code === 404) { + return {}; + } + }); + }) + .allowPublicAcquisition("xmla_request", function (arr) { + return this.getDeclaredGadget("xmla_client") + .push(function (g) { + return g.request(arr[0], arr[1], arr[2]); + }) + .push(undefined, function (err) { + console.error(err); + }); + }) + .allowPublicAcquisition("xmla_getLevels", function (arr) { + return this.getDeclaredGadget("xmla_client") + .push(function (g) { + return g.getLevels(arr[0], arr[1], arr[2]); + }) + .push(undefined, function (err) { + console.error(err); + }); + }) + .allowPublicAcquisition("xmla_getDimension", function (arr) { + return this.getDeclaredGadget("xmla_client") + .push(function (g) { + return g.getDimension(arr[0], arr[1]); + }); + }) + .allowPublicAcquisition("xmla_getHierarchies", function (arr) { + return this.getDeclaredGadget("xmla_client") + .push(function (g) { + return g.getHierarchies(arr[0], arr[1]); + }); + }) // methods emulating Gateway used for connection with ooffice begin. .declareMethod('appReady', function () { @@ -386,7 +669,7 @@ DocsAPI.DocEditor.version = function () { config[old_url] = [ new_url, old_url - ]; + ]; } } } @@ -449,6 +732,12 @@ DocsAPI.DocEditor.version = function () { return loadScript(app_url); }) + .push(function () { + return g.getDeclaredGadget("xmla_client"); + }) + .push(function (xmla_client) { + return xmla_client.render(); + }) .push(undefined, function (error) { display_error(g, error); }); @@ -481,7 +770,7 @@ DocsAPI.DocEditor.version = function () { g.props.save_defer.resolve(); g.props.save_defer = null; } else { - g.triggerSubmit(); + return g.triggerSubmit(); } }); }) @@ -517,9 +806,8 @@ DocsAPI.DocEditor.version = function () { .push(function (Editor_bin) { if (Editor_bin) { return zip.getAttachment('/', '/'); - } else { - return new Blob(); } + return new Blob(); }) .push(function (zip_blob) { return jIO.util.readBlobAsDataURL(zip_blob); @@ -532,6 +820,15 @@ DocsAPI.DocEditor.version = function () { // it clear modification state onlyoffice DesktopOfflineAppDocumentEndSave(0); return data; + }) + .push(undefined, function (error) { + display_error(g, error); }); + }) + .onStateChange(function (m_dict) { + var g = this; + if (m_dict.changed === true) { + return g.notifyChange(); + } }); -}(rJS, RSVP, require, jIO)); \ No newline at end of file +}(rJS, RSVP, require, jIO)); diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.html.html b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.html.html new file mode 100644 index 0000000000000000000000000000000000000000..3bb01244cbbf4e4723c09cafd3f0553d9b3e1e19 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.html.html @@ -0,0 +1,25 @@ + + + + + + + OLAP Query editor + + + + + + + + +
+
+
+
+
+ + + \ No newline at end of file diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.html.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.html.xml new file mode 100644 index 0000000000000000000000000000000000000000..6bf38d5add91d6dc617dd41b0f3bde8458816878 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.html.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + olap_wizard.html + + + content_type + text/html + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.js.js new file mode 100644 index 0000000000000000000000000000000000000000..26c06529ce1d1676fea4cda72ab0c90c6fac0118 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.js.js @@ -0,0 +1,412 @@ +/*jslint nomen: true, maxlen: 200, indent: 2*/ +/*global rJS, console, window, document, RSVP, URL*/ + +(function (window, rJS) { + "use strict"; + + function get_used_hierarchies(g) { + return g.getContent() + .push(function (v) { + var hierarchies = [], + key, + hierarchy; + if (v) { + if (v.columns) { + for (key in v.columns) { + if (v.columns.hasOwnProperty(key)) { + hierarchy = v.columns[key].hierarchy; + if (hierarchy) { + hierarchies.push(hierarchy); + } + } + } + } + if (v.rows) { + for (key in v.rows) { + if (v.rows.hasOwnProperty(key)) { + hierarchy = v.rows[key].hierarchy; + if (hierarchy) { + hierarchies.push(hierarchy); + } + } + } + } + } + return hierarchies; + }); + } + function discoverDimensions(g, connection_name, used_hierarchies) { + return g.getHierarchies(connection_name) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + var dimensions = {}, + i, + row, + uname, + tasks = []; + if (response) { + for (i = 0; i < response.length; i += 1) { + row = response[i]; + uname = row.DIMENSION_UNIQUE_NAME; + if (!dimensions.hasOwnProperty(uname) && + used_hierarchies.indexOf(row.HIERARCHY_UNIQUE_NAME) < 0 && + row.DIMENSION_TYPE !== 2 // !measure + ) { + dimensions[uname] = true; + } + } + } + for (i in dimensions) { + if (dimensions.hasOwnProperty(i)) { + tasks.push(g.getDimension(connection_name, i)); + } + } + return RSVP.all(tasks); + }) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + var arr = [], + i, + row; + for (i = 0; i < response.length; i += 1) { + row = response[i]; + arr.push({ + const: row.DIMENSION_UNIQUE_NAME || undefined, + title: row.DIMENSION_NAME || undefined + }); + } + return arr; + }); + } + + function discoverHierarchies(g, connection_name, used_hierarchies, opt) { + return g.request("discoverMDHierarchies", connection_name, opt) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + var arr = [], + i, + row, + uname; + for (i = 0; i < response.length; i += 1) { + row = response[i]; + uname = row.HIERARCHY_UNIQUE_NAME; + if (used_hierarchies.indexOf(uname) < 0) { + arr.push({ + const: uname || undefined, + title: row.HIERARCHY_NAME || undefined + }); + } + } + return arr; + }); + } + + function discoverLevels(g, connection_name, opt) { + return g.getLevels(connection_name, opt) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + var arr = [], + i, + row; + for (i = 0; i < response.length; i += 1) { + row = response[i]; + if (row.LEVEL_CARDINALITY < 600 && + row.LEVEL_TYPE !== 1 // exclude all level type + ) { + arr.push({ + const: row.LEVEL_UNIQUE_NAME || undefined, + title: row.LEVEL_NAME || undefined + }); + } + } + return arr; + }); + } + + function generateChoiceSchema(g, connection_name, used_hierarchies, choice_settings) { + var schema = { + "type": "object", + "additionalProperties": false, + "properties": {} + }, + current_hierarchy; + if (!connection_name) { + return new RSVP.Queue() + .push(function () { + return schema; + }); + } + if (!choice_settings) { + choice_settings = {}; + } + + current_hierarchy = choice_settings.hierarchy; + if (current_hierarchy) { + used_hierarchies = used_hierarchies + .filter(function (h) { + return h !== current_hierarchy; + }); + } + + return new RSVP.Queue() + .push(function () { + var tasks = [discoverDimensions(g, connection_name, used_hierarchies)]; + + if (choice_settings.dimension) { + tasks.push( + discoverHierarchies(g, connection_name, + used_hierarchies, + {prop: { + restrictions: { + DIMENSION_UNIQUE_NAME: choice_settings.dimension + } + }}) + ); + } + if (choice_settings.hierarchy) { + tasks.push(discoverLevels(g, connection_name, { + DIMENSION_UNIQUE_NAME: choice_settings.dimension, + HIERARCHY_UNIQUE_NAME: choice_settings.hierarchy + })); + } + + return RSVP.all(tasks); + }) + .push(function (arr) { + if (arr[0].length !== 0) { + schema.properties.dimension = { + title: " ", + oneOf: arr[0] + }; + } + if (arr[1] && arr[1].length !== 0) { + schema.properties.hierarchy = { + title: " ", + oneOf: arr[1] + }; + } + if (arr[2] && arr[2].length !== 0) { + schema.properties.level = { + // type: "array", + // items: { + // oneOf: arr[2] + // } + title: " ", + oneOf: arr[2] + }; + } + + return schema; + }) + .push(undefined, function (err) { + console.error(err); + return schema; + }); + } + + rJS(window) + .ready(function (g) { + g.props = {}; + g.props.choices = []; + return g.render({ + schema_url: new URL("olap_wizard.json", window.location).toString(), + value: {} + }); + }) + .declareAcquiredMethod("getRemoteSettings", "getRemoteSettings") + .declareAcquiredMethod("request", "xmla_request") + .declareAcquiredMethod("getDimension", "xmla_getDimension") + .declareAcquiredMethod("getHierarchies", "xmla_getHierarchies") + .declareAcquiredMethod("getLevels", "xmla_getLevels") + .allowPublicAcquisition("notifyValid", function (arr, scope) { + }) + .allowPublicAcquisition("notifyInvalid", function (arr, scope) { + }) + .declareMethod("rerender", function () { + return this.getDeclaredGadget("olap_wizard") + .push(function (gadget) { + return gadget.rerender(); + }) + .push(undefined, function (err) { + console.error(err); + }); + }) + .declareMethod("render", function (opt) { + if (!opt) { + opt = {}; + } + return this.getDeclaredGadget("olap_wizard") + .push(function (gadget) { + return gadget.render(opt); + }); + }) + .declareMethod("getContent", function (path) { + return this.getDeclaredGadget("olap_wizard") + .push(function (g) { + return g.getContent(path); + }); + }) + .declareAcquiredMethod("notifyChange", "notifyChange") + .allowPublicAcquisition("notifyChange", function (arr, s) { + var g = this, + scope = arr[0].scope, + relPath = arr[0].rel_path, + action = arr[0].action, + used_hierarchy, + url = arr[0].ref, + allRerender, + q, + y; + + function rerender(sub_scope) { + var queue, + gadget_settings; + if (!used_hierarchy) { + queue = get_used_hierarchies(g) + .push(function (v) { + used_hierarchy = v; + }); + } else { + queue = RSVP.Queue(); + } + + function rerender_once(connection_name, sub_gadget) { + return sub_gadget.getContent() + .push(function (content) { + return generateChoiceSchema(g, connection_name, used_hierarchy, content); + }) + .push(function (schema) { + return gadget_settings.rerender({ + scope: sub_scope, + schema: schema, + ignore_incorrect: true + }); + }); + } + + return queue + .push(function () { + return g.getDeclaredGadget("olap_wizard"); + }) + .push(function (gadget) { + gadget_settings = gadget; + return RSVP.all([ + gadget.getContent("/connection_name"), + gadget.getSubGadget(sub_scope) + ]); + }) + .push(function (arr) { + var connection_name = arr[0], + sub_gadget = arr[1]; + return rerender_once(connection_name, sub_gadget) + .push(function (changed) { + if (changed && changed.length > 0) { + if (changed.indexOf('/hierarchy') >= 0) { + return allRerender(); + } + return rerender_once(connection_name, sub_gadget); + } + }) + .push(function (changed) { + if (changed && changed.length > 0) { + return rerender_once(connection_name, sub_gadget); + } + }); + }); + } + + allRerender = function () { + return get_used_hierarchies(g) + .push(function (v) { + used_hierarchy = v; + return RSVP.all(g.props.choices.map(function (q) { + return rerender(q); + })); + }); + }; + + if (action === "render") { + if ("urn:jio:choice.json" === url) { + g.props.choices.push(scope); + } + // XXX action `render` fake change so do nothing + } else if ("urn:jio:remote_connections.json" === url) { + q = allRerender(); + } else { + for (y = 0; y < g.props.choices.length; y += 1) { + s = g.props.choices[y]; + if (scope.startsWith(s)) { + if (action === "delete") { + g.props.choices.splice(y, 1); + q = allRerender(); + } else if (relPath === "/hierarchy") { + q = allRerender(); + } else { + q = rerender(s); + } + } + } + } + if (q) { + return q + .push(function () { + return g.notifyChange(); + }) + .push(undefined, function (err) { + console.log(err); + }); + } + }) + .allowPublicAcquisition("resolveExternalReference", function (arr) { + var g = this, + url = arr[0], + schema_path = arr[1], + path = arr[2]; + if ("urn:jio:remote_connections.json" === url) { + return new RSVP.Queue() + .push(function () { + return g.getRemoteSettings(); + }) + .push(function (connections) { + var key, + schema = { + enum: [] + }; + for (key in connections) { + if (connections.hasOwnProperty(key)) { + schema.enum.push(key); + } + } + return schema; + }); + } + if ("urn:jio:choice.json" === url) { + return new RSVP.Queue() + .push(function () { + return RSVP.all([ + g.getContent("/connection_name"), + get_used_hierarchies(g), + g.getContent(path) + ]); + }) + .push(function (ret_arr) { + var choice_settings; + + if (path !== "/columns/" && path !== "/rows/") { + choice_settings = ret_arr[2]; + } + return generateChoiceSchema(g, ret_arr[0], ret_arr[1], choice_settings); + }); + } + throw new Error("urn: '" + url + "' not supported"); + }); + +}(window, rJS)); \ No newline at end of file diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.js.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.js.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7995b3b2c4a0dc4463a69f689332770bd4e19c4 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.js.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + olap_wizard.js + + + content_type + text/javascript + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.json.json b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.json.json new file mode 100644 index 0000000000000000000000000000000000000000..2126a24d76274ba3cb1bf618ee0fa1f3e725c285 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.json.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "OLAP Query parameters", + "type": "object", + "definitions": { + "choice": { + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "urn:jio:choice.json" + } + } + }, + "properties": { + "connection_name": { + "$ref": "urn:jio:remote_connections.json" + }, + "columns": { + "title": "columns", + "$ref": "#/definitions/choice" + }, + "rows": { + "title": "rows", + "$ref": "#/definitions/choice" + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.json.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.json.xml new file mode 100644 index 0000000000000000000000000000000000000000..a120df71b6e6c8f9b9a420d8d24eee27ae345586 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/olap_wizard.json.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + olap_wizard.json + + + content_type + application/json + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.html.html b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.html.html new file mode 100644 index 0000000000000000000000000000000000000000..c7332e6b40af2201c4a81e40444db363c0cdafb4 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.html.html @@ -0,0 +1,25 @@ + + + + + + + Demo UI OLAP Query editor based on JSON Schema form generator + + + + + + + + +
+
+
+
+
+ + + \ No newline at end of file diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.html.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.html.xml new file mode 100644 index 0000000000000000000000000000000000000000..657ea7f3c8104305317cc35bda7bb1eb1aee2a04 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.html.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + remote_settings.html + + + content_type + text/html + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.js.js new file mode 100644 index 0000000000000000000000000000000000000000..c784703b9eb3cb57d9979cda368ecd72ae5481a6 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.js.js @@ -0,0 +1,246 @@ +/*jslint nomen: true, maxlen: 200, indent: 2*/ +/*global rJS, console, window, document, RSVP*/ + +(function (window, rJS) { + "use strict"; + + function discoverDataSources(g, opt) { + return g.request("discoverDataSources", undefined, opt) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + if (!response) { + return; + } + var arr = [], + i, + row; + for (i = 0; i < response.length; i += 1) { + row = response[i]; + arr.push({ + const: row["DataSourceInfo"] || undefined, + title: row["DataSourceName"] || undefined, + description: row["DataSourceDescription"] || undefined + }); + } + return arr; + }); + } + + function discoverDBCatalogs(g, opt) { + return g.request("discoverDBCatalogs", undefined, opt) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + if (!response) { + return; + } + var arr = [], + i, + row; + for (i = 0; i < response.length; i += 1) { + row = response[i]; + arr.push({ + const: row["CATALOG_NAME"] || undefined, + title: row["CATALOG_NAME"] || undefined + }); + } + return arr; + }); + } + + function discoverMDCubes(g, opt) { + return g.request("discoverMDCubes", undefined, opt) + .push(undefined, function (error) { + console.log(error); + }) + .push(function (response) { + if (!response) { + return; + } + var arr = [], + i, + row; + for (i = 0; i < response.length; i += 1) { + row = response[i]; + arr.push({ + const: row["CUBE_NAME"] || undefined, + title: row["CUBE_NAME"] || undefined + }); + } + return arr; + }); + } + + function generateSchema(g, settings) { + var schema = { + "type": "object", + "additionalProperties": false, + "required": ["Cube"], + "properties": { + "DataSourceInfo": {"type": "string"}, + "Catalog": {"type": "string"}, + "Cube": {"type": "string"} + } + }; + if (!settings) { + return new RSVP.Queue() + .push(function () { + return schema; + }); + } + if (!settings.hasOwnProperty('properties')) { + settings.properties = {}; + } + return new RSVP.Queue() + .push(function () { + return RSVP.all([ + discoverDataSources(g, { + urls: settings.urls, + prop: {} + }), + discoverDBCatalogs(g, { + urls: settings.urls, + prop: { + properties: { + DataSourceInfo: settings.properties.DataSourceInfo + } + } + }), + discoverMDCubes(g, { + urls: settings.urls, + prop: { + properties: { + DataSourceInfo: settings.properties.DataSourceInfo, + Catalog: settings.properties.Catalog + } + } + }) + ]); + }) + .push(function (arr) { + if (arr[0] && arr[0].length !== 0) { + schema.properties.DataSourceInfo = { + title: " ", + oneOf: arr[0] + }; + } + if (arr[1] && arr[1].length !== 0) { + schema.properties.Catalog = { + title: " ", + oneOf: arr[1] + }; + } + if (arr[2] && arr[2].length !== 0) { + schema.properties.Cube = { + title: " ", + oneOf: arr[2] + }; + } + return schema; + }); + } + + rJS(window) + .ready(function (g) { + g.props = {}; + g.props.xmla_connections = {}; + }) + .declareAcquiredMethod("request", "xmla_request") + .declareAcquiredMethod("getLevels", "xmla_getLevels") + .allowPublicAcquisition("notifyValid", function (arr, scope) { + }) + .allowPublicAcquisition("notifyInvalid", function (arr, scope) { + }) + .declareMethod("render", function (opt) { + var gadget = this; + return gadget.getDeclaredGadget("xmla_settings") + .push(function (g) { + return g.render(opt); + }); + }) + .declareMethod("getContent", function (sub_path) { + return this.getDeclaredGadget("xmla_settings") + .push(function (g) { + return g.getContent(sub_path); + }); + }) + .declareAcquiredMethod("notifyChange", "notifyChange") + .allowPublicAcquisition("notifyChange", function (arr, s) { + var g = this, + p = arr[0].path, + scope = arr[0].scope, + action = arr[0].action, + url = arr[0].ref, + connection_path, + path; + + function rerender(sub_scope, settings_path) { + var gadget_settings; + return g.getDeclaredGadget("xmla_settings") + .push(function (gadget) { + gadget_settings = gadget; + return gadget.getContent(settings_path); + }) + .push(function (settings) { + return generateSchema(g, settings); + }) + .push(function (schema) { + return gadget_settings.rerender({ + scope: sub_scope, + path: '/properties', + schema: schema, + ignore_incorrect: true + }); + }) + .push(function () { + return g.notifyChange(); + }); + } + + if (action === "render") { + if ("urn:jio:properties_from_xmla.connection.json" === url) { + connection_path = p.split('/').slice(0, -2).join('/'); + g.props.xmla_connections[connection_path] = scope.split('_').slice(0, -1).join('_'); + } + // action `render` fake change so do nothing + return; + } + for (path in g.props.xmla_connections) { + if (g.props.xmla_connections.hasOwnProperty(path)) { + if (p === path && action === "add") { + return rerender(scope, path); + } + s = g.props.xmla_connections[path]; + if (action === "delete") { + if (s === scope) { + delete g.props.xmla_connections[path]; + } + } else { + // check if receive message from gadget with scope == s or his sub_gadgets + if (scope.startsWith(s)) { + return rerender(s, path); + } + } + } + } + return g.notifyChange(); + }) + .allowPublicAcquisition("resolveExternalReference", function (arr) { + var g = this, + url = arr[0], + schema_path = arr[1], + path = arr[2], + connection_path = path.split('/').slice(0, -1).join('/'); + if ("urn:jio:properties_from_xmla.connection.json" === url) { + return this.getContent(connection_path) + .push(function (settings) { + return generateSchema(g, settings); + }); + } + throw new Error("urn: '" + url + "' not supported"); + }); + +}(window, rJS)); diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.js.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.js.xml new file mode 100644 index 0000000000000000000000000000000000000000..f23df563b11e997525abf7f693d9e3010c9e77ae --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.js.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + remote_settings.js + + + content_type + text/javascript + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.json.json b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.json.json new file mode 100644 index 0000000000000000000000000000000000000000..da31ea5b07d3364fd80f56e89c213232f7c3281c --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.json.json @@ -0,0 +1,8 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "remote XMLA connections", + "type": "object", + "additionalProperties": { + "$ref": "xmla_connection.json" + } +} diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.json.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.json.xml new file mode 100644 index 0000000000000000000000000000000000000000..31f226ee356628f3f4b3ac5f87dad91988958600 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/remote_settings.json.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + remote_settings.json + + + content_type + application/json + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/api.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/api.js.js index a8e21834cfd43e386f87d5ef780e5502ec2f7880..11e684c4c05b6996c3dcf2e98ab525ecbd2a621e 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/api.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/api.js.js @@ -1367,6 +1367,7 @@ var editor; this.CoAuthoringApi.saveChanges(arrChanges, deleteIndex, excelAdditionalInfo, this.canUnlockDocument2); History.CanNotAddChanges = true; } else { + this.CoAuthoringApi.onUnSaveLock(); this.CoAuthoringApi.unLockDocument(true, this.canUnlockDocument2); } this.canUnlockDocument2 = false; diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/cubeFunctions.xmla.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/cubeFunctions.xmla.js.js index a210ad21840908bf7c789aa77ffdb535b72cc502..bf502bcaeb5a229d65768e7488b88b6fe3d0bcb2 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/cubeFunctions.xmla.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/cubeFunctions.xmla.js.js @@ -1,3 +1,4 @@ +/*global AscCommonExcel, RSVP, Xmla, console*/ /* jshint -W040 */ /* * Copyright (c) 2017 Nexedi SA and Contributors. All Rights Reserved. @@ -38,9 +39,8 @@ * @param {Object} RSVP * @param {Xmla} Xmla * @param {console} console - * @param {undefined} undefined */ - function (window, RSVP, Xmla, console, undefined) { +function (window, RSVP, Xmla, console) { var cBaseFunction = AscCommonExcel.cBaseFunction; var cFormulaFunctionGroup = AscCommonExcel.cFormulaFunctionGroup, cElementType = AscCommonExcel.cElementType, @@ -66,24 +66,9 @@ cFormulaFunctionGroup.NotRealised.push(cCUBEKPIMEMBER, cCUBEMEMBERPROPERTY, cCUBERANKEDMEMBER, cCUBESET, cCUBESETCOUNT); - var xmla = new Xmla({ -// listeners: { -// events: Xmla.EVENT_ERROR, -// handler: function (eventName, eventData, xmla) { -// console.log(eventData.exception); -// // alert( -// // "Snap, an error occurred: " + eventData.exception.message + " (" + eventData.exception.code + ")" + -// // (eventData.exception.code === Xmla.Exception.HTTP_ERROR_CDE -// // ? "\nstatus: " + eventData.exception.data.status + "; statusText: " + eventData.exception.data.statusText -// // : "") -// // ); -// } -// }, - async: true - }); - function xmla_request(func, prop) { var xmla = new Xmla({async: true}); + prop = JSON.parse(JSON.stringify(prop)); // return function () { return new RSVP.Queue() .push(function () { @@ -99,32 +84,49 @@ }); } - function xmla_request_retry(func, prop) { - return xmla_request(func, prop) - .push(undefined, function (response) { - // fix mondrian Internal and Sql errors - if (response) { - switch (response["code"]) { - case "SOAP-ENV:Server.00HSBE02": - case "SOAP-ENV:00UE001.Internal Error": - // rarely server error, so try again - return xmla_request(func, prop); - } - } - throw response; - }); + function xmla_request_retry(func, settings) { + var queue, + urls = settings.urls || [""], + i; + + function make_request(url) { + return function (error) { + settings.prop.url = url; + return xmla_request(func, settings.prop) + .push(undefined, function (response) { + // fix mondrian Internal and Sql errors + if (response) { + switch (response["code"]) { + case "SOAP-ENV:Server.00HSBE02": + case "SOAP-ENV:00UE001.Internal Error": + // rarely server error, so try again + return xmla_request(func, settings.prop); + } + } + throw response; + }); + }; + } + + queue = make_request(urls[0])(); + for (i = 1; i < urls.length; i += 1) { + queue.push(undefined, make_request(urls[i])); + } + return queue; } function discover_hierarchies(connection) { - var settings = getProperties(connection), - prop = settings.prop; - prop.restrictions = { -// 'CATALOG_NAME': 'FoodMart', -// 'HIERARCHY_NAME': hierarchy_name, -// 'HIERARCHY_UNIQUE_NAME': hierarchy_name, - 'CUBE_NAME': settings["cube"] - }; - return xmla_request_retry("discoverMDHierarchies", prop) + return getProperties(connection) + .push(function (settings) { + var prop = settings.prop; + prop.restrictions = { + // 'CATALOG_NAME': 'FoodMart', + // 'HIERARCHY_NAME': hierarchy_name, + // 'HIERARCHY_UNIQUE_NAME': hierarchy_name, + 'CUBE_NAME': settings["cube"] + }; + return xmla_request_retry("discoverMDHierarchies", settings); + }) .push(function (response) { var hierarchies = {}, hierarchy, @@ -168,36 +170,35 @@ }); } - function getProperties(connection) { - var connections = { - "xmla": { - "prop": { - "url": "https://d1.erp5.ru/saiku/xmla", - "properties": { - "DataSourceInfo": "FoodMart", - "Catalog": "FoodMart" - } - }, - "cube": "Sales" - }, - "olapy": { - "prop": { - "url": "https://d1.erp5.ru/olapy/xmla", - "properties": { - "DataSourceInfo": "-", - "Catalog": "sales" - } - }, - "cube": "Sales" - } - }; - connection = connections[connection]; - if (!connection) { - throw "connection not exist"; - } - connection = JSON.parse(JSON.stringify(connection)); - return connection; - } + function getProperties(connection) { + return Common.Gateway.jio_getAttachment('/', 'remote_settings.json', {format: 'json'}) + .push(undefined, function (e) { + if (e.status_code === 404) { + return {}; + } + throw e; + }) + .push(function (value) { + var c; + if (!value.hasOwnProperty(connection)) { + throw "connection not exist"; + } + c = value[connection]; + if (!c.hasOwnProperty('properties')) { + c.properties = {}; + } + return { + urls: c.urls, + prop: { + properties: { + DataSourceInfo: c.properties.DataSourceInfo, + Catalog: c.properties.Catalog + } + }, + cube: c.properties.Cube + }; + }); + } function getScheme(connection) { var scheme = cubeScheme[connection], @@ -258,7 +259,15 @@ if (value.cube_value) { array = value.cube_value; } else { - array = value.value.split(','); + // split only member not part in member + // [Promotion].[Media Type].[Daily Paper, Radio, TV] + array = value.value + .replace(/^w*\[/, "") + .replace(/]w*$/, "") + .split(/]\w*,\w*\[/) + .map(function (x) { + return '[' + x + ']'; + }); } if (array.length > 0) { // filter members already existed @@ -324,16 +333,22 @@ scheme; if (!execution_scheme.execute) { execution_scheme.execute = RSVP.defer(); - return getScheme(connection) - .push(function (s) { - var settings = getProperties(connection), + return RSVP.Queue() + .push(function () { + return RSVP.all([ + getScheme(connection), + getProperties(connection) + ]); + }) + .push(function (arr) { + var settings = arr[1], prop = settings.prop, hierarchies = execution_scheme.hierarchies, hierarchy, mdx = [], tuple_str, all_member; - scheme = s; + scheme = arr[0]; for (hierarchy in hierarchies) { tuple_str = hierarchies[hierarchy].join(","); all_member = scheme.hierarchies[hierarchy]["all_member"]; @@ -344,7 +359,7 @@ } prop.statement = "SELECT " + mdx.join("*") + " ON 0 FROM [" + settings["cube"] + "]"; - return xmla_request("execute", prop); + return xmla_request_retry("execute", settings); }) .push(function (dataset) { var cellset = dataset.getCellset(), @@ -360,7 +375,7 @@ }; - for (axis_id = 0; axis_id < axis_count; axis_id++) { + for (axis_id = 0; axis_id < axis_count; axis_id += 1) { axis_array.push(dataset.getAxis(axis_id)); } @@ -409,86 +424,8 @@ return execution_scheme.execute.promise; } - function discover_members(connection, opt) { - return new RSVP.Queue() - .push(function () { - var settings = getProperties(connection), - prop = settings.prop, - cached_member, - scheme = getExecutionScheme(connection); - prop.restrictions = { -// 'CATALOG_NAME': 'FoodMart', - 'CUBE_NAME': settings["cube"] - }; - if (!opt) { - opt = {}; - } - if (opt.member_uname) { - prop.restrictions["MEMBER_UNIQUE_NAME"] = opt.member_uname; - cached_member = scheme.members[opt.member_uname]; - } - if (opt.level_uname) { - prop.restrictions["LEVEL_UNIQUE_NAME"] = opt.level_uname; - } - if (cached_member) { - return [cached_member]; - } else { - return xmla_request_retry("discoverMDMembers", prop) - .push(function (r) { - var ret = [], - uname, - level, - cached_member; - while (r.hasMoreRows()) { - uname = r["getMemberUniqueName"](); - level = r["getLevelUniqueName"](); - // we can check cache twice because fist check - // only if discover by member_uname - if (!scheme.members.hasOwnProperty(uname)) { - cached_member = { - uname: uname, - h: r["getHierarchyUniqueName"](), - level: r["getLevelUniqueName"](), - caption: r["getMemberCaption"](), - type: r["getMemberType"]() - }; - scheme.members[uname] = cached_member; - } else { - cached_member = scheme.members[uname]; - } - ret.push(cached_member); - r.nextRow(); - if (!scheme.levels.hasOwnProperty(level)) { - scheme.levels[level] = discover_level(connection, scheme, level); - } - } - return ret; - }); - } - }); - } - - function discover_level(connection, scheme, level) { - return discover_members(connection, { - level_uname: level - }) - .push(function (members) { - var i; - - function compare(a, b) { - if (a.uname < b.uname) - return -1; - if (a.uname > b.uname) - return 1; - return 0; - } - - members.sort(compare); - for (i = 0; i < members.length; i++) { - members[i].level_index = i; - } - scheme.levels[level] = members; - }); + function getXmlaClient() { + return Common.Gateway.getDeclaredGadget("xmla_client"); } function discover_members_for_arguments(connection, members) { @@ -498,22 +435,20 @@ function check_interseption(hierarchy) { if (hierarchies.hasOwnProperty(hierarchy)) { throw "The tuple is invalid because there is no intersection for the specified values."; - } else { - hierarchies[hierarchy] = 1; } + hierarchies[hierarchy] = 1; } members.forEach(function (member) { if (member) { promises .push( - discover_members(connection, { - member_uname: member - }) - .push(function (members) { - var member; - if (members.length > 0) { - member = members[0]; + getXmlaClient() + .push(function (xmla_client) { + return xmla_client.getMember(connection, member); + }) + .push(function (member) { + if (member) { check_interseption(member.h); return member; } else { @@ -572,7 +507,7 @@ caption; return queue .push(function (arg) { - connection = getCell(arg[0]); + connection = getCell(arg[0]).toString(); caption = getCell(arg[2]); if (caption) { caption = caption.getValue(); @@ -598,26 +533,21 @@ .push(undefined, error_handler(current_cell_id)); }; cCUBEMEMBER.prototype.changeOffsetElem = function (arg, offset) { - var connection = getCell(arg[0]), - scheme = getExecutionScheme(connection), - i, - elem, - member, - new_member, - level; - for (i = 0; i < arg.length; i++) { - elem = arg[i]; + var connection_name = getCell(arg[0]).toString(); + return RSVP.all(arg.slice(1).map(function (elem) { if (cElementType.string === elem.type) { - member = scheme.members[elem.value]; - if (member && (member.level_index >= 0)) { - level = scheme.levels[member.level]; - new_member = level[member.level_index + offset.offsetCol + offset.offsetRow]; - if (new_member) { - elem.value = new_member.uname; - } - } + return getXmlaClient() + .push(function (xmla_client) { + return xmla_client + .getMemberWithOffset(connection_name, elem.value, offset.offsetCol + offset.offsetRow); + }) + .push(function (member) { + if (member) { + elem.value = member.uname; + } + }); } - } + })); }; cCUBEMEMBER.prototype.getInfo = function () { return { @@ -690,7 +620,7 @@ waiter = AddCubeValueCalculate(current_cell_id); return queue .push(function (arg) { - connection = getCell(arg[0]); + connection = getCell(arg[0]).toString(); scheme = getExecutionScheme(connection); return parseArgs(arg.slice(1))(); }) @@ -732,25 +662,25 @@ ret; function getHierarchyByMember(member_path) { - var h; - h = cube.members[member_path]; - if (h === undefined) { + var hierarchy; + hierarchy = cube.members[member_path]; + if (hierarchy === undefined) { throw "query result not contain data for member:" + member_path; } - h = h.hierarchy; - h = cube.hierarchies[h]; - return h; + hierarchy = hierarchy.hierarchy; + hierarchy = cube.hierarchies[hierarchy]; + return hierarchy; } - for (i = 0; i < cube.hierarchies.length; i++) { + for (i = 0; i < cube.hierarchies.length; i += 1) { h = cube.hierarchies[i]; if (!coordinate[h.axis_id]) { coordinate[h.axis_id] = []; } coordinate[h.axis_id][h.tuple_id] = null; } - for (i = 0; i < members.length; i++) { + for (i = 0; i < members.length; i += 1) { member_path = members[i]; h = getHierarchyByMember(members[i]); coordinate[h.axis_id][h.tuple_id] = member_path; diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/informationFunctions.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/informationFunctions.js.js index d81013e1d638dbf8caef0a812aa39e2a66fba757..5e306ee18e62cb1acbf5c22fc0dc4e6ea1eb9f07 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/informationFunctions.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/informationFunctions.js.js @@ -453,7 +453,8 @@ arg0 = arg0.getValue(); } - if (arg0 instanceof cString) { + if (arg0 instanceof cString || + arg0.errorType === cErrorType.not_numeric) { return new cBool(true); } else { return new cBool(false); diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/parserFormula.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/parserFormula.js.js index 3f3d62cf5cb033820652655f539982c0a3849822..63421a819c2d80dfe86d1a5b0ffd2dc3c262b242 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/parserFormula.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/FormulaObjects/parserFormula.js.js @@ -5506,6 +5506,8 @@ parserFormula.prototype.setFormula = function(formula) { if (typeof value === "function") { this.value = new cError(cErrorType.getting_data); this.queue = true; + formula.ws.workbook.dependencyFormulas + .addToCleanCellCache(formula.ws.getId(), opt_bbox.r1, opt_bbox.c1); this.lazy_value = function () { formula.lazy_value = null; formula.queue = value() @@ -5513,10 +5515,6 @@ parserFormula.prototype.setFormula = function(formula) { formula.value = ret; formula.value.numFormat = numFormat; formula._endCalculate(); - // updateOnScreen cell - formula.ws.workbook.handlers.trigger("cleanCellCache", - formula.ws.getId(), {0: opt_bbox}, - AscCommonExcel.c_oAscCanChangeColWidth.none); formula.queue = false; // formula.lazy_value = null; return formula.value; diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/Workbook.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/Workbook.js.js index bb046c8eee89bbdeb908503d2291707cc508bcf4..bbca4f7fafe68a26350d9b9f65ce6281e0feb6d1 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/Workbook.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/cell/model/Workbook.js.js @@ -967,10 +967,7 @@ tasks.push(lazy_value()); } } - function end () { - //copy cleanCellCache to prevent recursion in trigger("cleanCellCache") - var tmpCellCache = dependency_graph.cleanCellCache; - dependency_graph.cleanCellCache = {}; + function end (tmpCellCache) { for (var i in tmpCellCache) { dependency_graph.wb.handlers.trigger("cleanCellCache", i, {0: tmpCellCache[i]}, AscCommonExcel.c_oAscCanChangeColWidth.none); @@ -980,12 +977,19 @@ } if (tasks.length > 0) { new RSVP.Queue() + .push(function () { + end(dependency_graph.cleanCellCache); + }) .push(function () { return RSVP.all(tasks); }) - .push(end); + .push(function () { + end(dependency_graph.cleanCellCache); + dependency_graph.cleanCellCache = {}; + }); } else { - end(); + end(dependency_graph.cleanCellCache); + dependency_graph.cleanCellCache = {}; } }, initOpen: function() { diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/common/GlobalLoaders.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/common/GlobalLoaders.js.js index 5e08741db3b8180f80d41b320b9499af0ac56d13..09d7a5067f053315b40e61ada812be50a212d85b 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/common/GlobalLoaders.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/sdkjs/common/GlobalLoaders.js.js @@ -509,7 +509,7 @@ queue, oThis = this; if (0 === start.indexOf('jio:')) { - queue = Common.Gateway.jio_getAttachment(this.Api.documentId, image_id.slice(4), 'asBlobURL') + queue = Common.Gateway.jio_getAttachment(this.Api.documentId, image_id.slice(4), {format:'blob_url'}) .push(undefined, function (error) { console.error(error); return ""; diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js.js new file mode 100644 index 0000000000000000000000000000000000000000..b45cbd82464f7187e69a817487f8741bc9effd9b --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js.js @@ -0,0 +1,123 @@ +define([ + 'common/main/lib/component/Window', + 'common/main/lib/component/LoadMask' +], function () { + 'use strict'; + Common.Views.RenderJSDialog = Common.UI.Window.extend(_.extend({ + initialize : function(options) { + var _options = {}; + _.extend(_options, { + title: this.textTitle, + width: Common.Utils.innerWidth() - 40, + height: Common.Utils.innerHeight() - 40, + header: true + }, options); + + this.template = [ + '
' + ].join(''); + + _options.tpl = _.template(this.template)(_options); + + Common.UI.Window.prototype.initialize.call(this, _options); + }, + + render: function() { + var q, + me = this, + element; + Common.UI.Window.prototype.render.call(this); + element = document.getElementById(this.options.scope); + this.$window.find('> .body').css({height: 'auto', overflow: 'hidden'}); + + // this.loadMask = new Common.UI.LoadMask({owner: $(element)}); + // this.loadMask.setTitle(this.textLoading); + // this.loadMask.show(); + + if (!me.gadget) { + q = Common.Gateway.declareGadget(this.options.gadget_url, { + scope: this.options.scope, + element: element, + sandbox: "iframe" + }) + .push(function (sub_gadget) { + me.gadget = sub_gadget; + var iframe = sub_gadget.element.querySelector("iframe"); + iframe.width = '100%'; + iframe.height = (Common.Utils.innerHeight() - 80) + 'px'; + iframe.setAttribute("frameBorder","0"); + // iframe.style = "border: none;"; + // iframe.align = "top"; + // iframe.scrolling = "no"; + + // this._eventfunc = function(msg) { + // me._onWindowMessage(msg); + // }; + // this._bindWindowEvents.call(this); + // + // this.on('close', function(obj){ + // me._unbindWindowEvents(); + // }); + }); + } else { + q = RSVP.Queue(); + } + return q.push(function () { + return me.gadget.render(me.options.gadget_render_opt); + }) + .push(undefined, function () { + // XXX + return; + }) + .push(function () { + me._onLoad(); + }); + }, + + _bindWindowEvents: function() { + if (window.addEventListener) { + window.addEventListener("message", this._eventfunc, false); + } else if (window.attachEvent) { + window.attachEvent("onmessage", this._eventfunc); + } + }, + + _unbindWindowEvents: function() { + if (window.removeEventListener) { + window.removeEventListener("message", this._eventfunc); + } else if (window.detachEvent) { + window.detachEvent("onmessage", this._eventfunc); + } + }, + + _onWindowMessage: function(msg) { + // TODO: check message origin + if (msg && window.JSON) { + try { + this._onMessage.call(this, window.JSON.parse(msg.data)); + } catch(e) {} + } + }, + + _onMessage: function(msg) { + if (msg && msg.file !== undefined) { + Common.NotificationCenter.trigger('window:close', this); + var me = this; + setTimeout(function() { + if ( !_.isEmpty(msg.file) ) { + me.trigger('mailmergerecepients', me, msg.file); + } + }, 50); + } + }, + + _onLoad: function() { + if (this.loadMask) + this.loadMask.hide(); + }, + + textTitle : 'Select Data Source', + textLoading : 'Loading' + }, Common.Views.RenderJSDialog || {})); + +}); diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6fd93de9d3c4514ebeb432ea590c8875abb6219 --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSDialog.js.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + RenderJSDialog.js + + + content_type + text/javascript + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js.js new file mode 100644 index 0000000000000000000000000000000000000000..de26c8daa427ca72a50f6d4282550041b513244e --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js.js @@ -0,0 +1,71 @@ +/** + * User: Julia.Radzhabova + * Date: 17.05.16 + * Time: 15:38 + */ + +if (Common === undefined) + var Common = {}; + +Common.Views = Common.Views || {}; + +define([ + 'common/main/lib/util/utils', + 'common/main/lib/component/BaseView', + 'common/main/lib/component/Layout', + 'common/main/lib/component/Window' +], function (template) { + 'use strict'; + + Common.Views.RenderJSPanel = Common.UI.BaseView.extend(_.extend({ + initialize: function (options) { + _.extend(this, options); + Common.UI.BaseView.prototype.initialize.call(this, arguments); + }, + + render: function () { + var me = this, + element = me.$el[0], + q = RSVP.Queue(); + + if (!me.gadget) { + q = Common.Gateway.declareGadget(this.gadget_url, { + scope: this.scope, + element: element, + sandbox: "iframe" + }) + .push(function (sub_gadget) { + me.gadget = sub_gadget; + var iframe = sub_gadget.element.querySelector("iframe"); + iframe.width = '100%'; + iframe.height = (Common.Utils.innerHeight() - 80) + 'px'; + iframe.setAttribute("frameBorder", "0"); + me.$el = $(sub_gadget.element); + }); + } else { + q = RSVP.Queue(); + } + return q.push(function () { + return me.gadget.render(me.gadget_render_opt); + }) + .push(function () { + return me; + }) + .push(undefined, function (e) { + console.error(e); + }); + + }, + + show: function () { + Common.UI.BaseView.prototype.show.call(this,arguments); + this.fireEvent('show', this ); + }, + + hide: function () { + Common.UI.BaseView.prototype.hide.call(this,arguments); + this.fireEvent('hide', this ); + } + + }, Common.Views.RenderJSPanel || {})); +}); \ No newline at end of file diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js.xml b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c6b89ac96e26c5cf506dec82c61fc8a393c6b0c --- /dev/null +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/common/main/lib/view_folder/RenderJSPanel.js.xml @@ -0,0 +1,32 @@ + + + + + + + + + + _Cacheable__manager_id + http_cache + + + __name__ + RenderJSPanel.js + + + content_type + text/javascript + + + precondition + + + + title + + + + + + diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/LeftMenu.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/LeftMenu.js.js index 687ff54f60add0bf90758724a0e2e8344a7bc65a..6222be76ce017eae032e55eb03b123ecca04d6a7 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/LeftMenu.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/LeftMenu.js.js @@ -34,7 +34,8 @@ define([ 'core', 'common/main/lib/util/Shortcuts', 'spreadsheeteditor/main/app/view/LeftMenu', - 'spreadsheeteditor/main/app/view/FileMenu' + 'spreadsheeteditor/main/app/view/FileMenu', + 'common/main/lib/view/RenderJSDialog' ], function () { 'use strict'; @@ -88,6 +89,7 @@ define([ onLaunch: function() { this.leftMenu = this.createView('LeftMenu').render(); this.leftMenu.btnSearch.on('toggle', _.bind(this.onMenuSearch, this)); + this.leftMenu.btnRemote.on('toggle', _.bind(this.onRemote, this)); Common.util.Shortcuts.delegateShortcuts({ shortcuts: { @@ -476,6 +478,51 @@ define([ this.showSearchDlg(show); }, + onRemote: function(obj, show) { + var queue, + me = this; + if ( !this.dlgRemote ) { + queue = Common.Gateway.jio_getAttachment('/', 'remote_settings.json', {format: 'json'}) + .push(undefined, function (e) { + if (e.status_code === 404) { + return {}; + } + throw e; + }) + .push(function (value) { + me.dlgRemote = new Common.Views.RenderJSDialog({ + toolclose: "hide", + gadget_url: "onlyoffice/remote_settings.html", + scope: "remote_settings", + gadget_render_opt: { + schema_url: "remote_settings.json", + value: value + } + }); + me.dlgRemote.on("hide", _.bind(function () { + this.leftMenu.btnRemote.toggle(false, true); + }, me)); + }); + } else { + queue = RSVP.Queue(); + } + queue.push(function () { + if (show) { + if (me.dlgRemote.isVisible()) { + me.dlgRemote.focus(); + } else { + me.dlgRemote.show(); + } + + me.api.asc_closeCellEditor(); + } + + }) + .push(undefined, function (e) { + console.error(e); + }); + }, + onSearchDlgHide: function() { this.leftMenu.btnSearch.toggle(false, true); $(this.leftMenu.btnSearch.el).blur(); @@ -716,4 +763,4 @@ define([ textSearch: 'Search', textLookin: 'Look in' }, SSE.Controllers.LeftMenu || {})); -}); \ No newline at end of file +}); diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/Main.js.js b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/Main.js.js index 9a757f3265f64345985b7be816f5777a2a1df10f..7c82b1b43507354588be7677f406dc1b96e999c7 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/Main.js.js +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/controller/Main.js.js @@ -716,7 +716,7 @@ define([ Common.Gateway.on('processrightschange', _.bind(me.onProcessRightsChange, me)); Common.Gateway.on('processmouse', _.bind(me.onProcessMouse, me)); Common.Gateway.on('save', function () { - if (me.api.asc_isDocumentModified()) { + if (me.api.asc_isDocumentModified() && me.api.asc_isDocumentCanSave()) { me.api.asc_Save(); return true; } diff --git a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/template/LeftMenu.template.html b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/template/LeftMenu.template.html index 72e9669316c96ca7cf67e3d9c8aa9cf652762192..d1ea7c5a310d9160ad73c7244aa2088ee4f70af9 100644 --- a/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/template/LeftMenu.template.html +++ b/bt5/erp5_only_office/SkinTemplateItem/portal_skins/erp5_only_office/onlyoffice/web-apps/apps/spreadsheeteditor/main/app/template/LeftMenu.template.html @@ -1,20 +1,23 @@ -
-
- - - - - - - - - -
-
- -