Commit c67dad31 authored by Boris Kocherov's avatar Boris Kocherov

erp5_json_form: update version from https://lab.nexedi.com/bk/rjs_json_form

parent 9acaa833
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
url = new URL(url, base_url); url = new URL(url, base_url);
if (urn_prefix) { if (urn_prefix) {
pathname = url.pathname.slice(1); pathname = url.pathname.slice(1);
return { this.href = urn_prefix + encodeURIComponent(pathname + url.search + url.hash);
href: urn_prefix + encodeURIComponent(pathname + url.search + url.hash), this.origin = urn_prefix;
origin: urn_prefix, this.pathname = encodeURIComponent(pathname);
pathname: encodeURIComponent(pathname), this.hash = url.hash;
hash: url.hash this.search = "";
}; return this;
} }
return url; return url;
} }
...@@ -119,9 +119,9 @@ ...@@ -119,9 +119,9 @@
base_url = convertToRealWorldSchemaPath(g, path), base_url = convertToRealWorldSchemaPath(g, path),
absolute_url; absolute_url;
if (base_url === "" || base_url.indexOf("#") === 0) { if (base_url === "" || base_url.indexOf("#") === 0) {
absolute_url = URLwithJio(url, base_url_failback); absolute_url = new URLwithJio(url, base_url_failback);
} else { } else {
absolute_url = URLwithJio(url, base_url); absolute_url = new URLwithJio(url, base_url);
} }
return absolute_url; return absolute_url;
} }
...@@ -181,54 +181,85 @@ ...@@ -181,54 +181,85 @@
} }
} }
function map_url(g, download_url) {
var mapped_url = download_url,
hash = mapped_url.hash,
i,
schemas = g.props.schemas,
next_mapped_url;
// simple defence forever loop
for (i = 0; i < Object.keys(schemas).length; i += 1) {
next_mapped_url = g.props.schemas[mapped_url.origin + mapped_url.pathname + mapped_url.search];
if (next_mapped_url === undefined) {
break;
}
mapped_url = next_mapped_url;
if (typeof mapped_url !== "string") {
mapped_url = resolveLocalReference(mapped_url, hash);
break;
}
mapped_url = new URL(mapped_url, g.__path);
if (hash[0] === '#') {
hash = hash.slice(1);
}
if (hash === '/') {
hash = '';
}
hash = mapped_url.hash + hash;
}
return mapped_url;
}
function loadJSONSchema(g, $ref, path) { function loadJSONSchema(g, $ref, path) {
var protocol, var protocol,
url, url,
download_url, download_url,
hash, hash,
schema_url_map, mapped_url,
queue; queue;
// XXX need use `id` property // XXX need use `id` property
if (!path) { if (!path) {
path = "/"; path = "/";
} }
url = convertUrlToAbsolute(g, path, $ref, window.location); url = convertUrlToAbsolute(g, path, decodeURI($ref), window.location);
download_url = url.origin + url.pathname; mapped_url = map_url(g, url);
schema_url_map = { if (mapped_url instanceof URL || mapped_url instanceof URLwithJio) {
"http://json-schema.org/draft-04/schema": "json-schema/schema4.json", url = mapped_url;
"http://json-schema.org/draft-06/schema": "json-schema/schema6.json",
"http://json-schema.org/draft-07/schema": "json-schema/schema7.json",
"http://json-schema.org/schema": "json-schema/schema7.json"
};
if (schema_url_map.hasOwnProperty(download_url)) {
url = new URL(schema_url_map[download_url], g.__path);
} }
protocol = url.protocol; protocol = url.protocol;
if (protocol === "http:" || protocol === "https:") { if (protocol === "http:" || protocol === "https:") {
if (window.location.protocol !== protocol) { if (window.location.protocol !== protocol) {
url = new URL($ref.replace(protocol + "//", window.location.protocol + "//")); url = new URL(decodeURI($ref).replace(protocol + "//", window.location.protocol + "//"));
// throw new Error("You cannot mixed http and https calls"); // throw new Error("You cannot mixed http and https calls");
} }
} }
download_url = url.origin + url.pathname; download_url = url.origin + url.pathname + url.search;
hash = url.hash; hash = url.hash;
url = url.href; url = url.href;
if (download_url.startsWith("urn:jio:")) { if (!(mapped_url instanceof URL || mapped_url instanceof URLwithJio)) {
queue = RSVP.Queue() queue = RSVP.Queue()
.push(function () { .push(function () {
return g.downloadJSON(download_url); return mapped_url;
}); });
} else { } else {
queue = RSVP.Queue() if (download_url.startsWith("urn:jio:")) {
.push(function () { queue = RSVP.Queue()
return downloadJSON(download_url); .push(function () {
return g.downloadJSON(download_url);
});
} else {
queue = RSVP.Queue()
.push(function () {
return downloadJSON(download_url);
});
}
queue
.push(function (json) {
checkCircular(g, path, url);
return resolveLocalReference(json, hash);
}); });
} }
return queue return queue
.push(function (json) {
checkCircular(g, path, url);
return resolveLocalReference(json, hash);
})
.push(undefined, function (err) { .push(undefined, function (err) {
// XXX it will be great to have ability convert json_pointers(hash) // XXX it will be great to have ability convert json_pointers(hash)
// in line numbers for pointed to line in rich editors. // in line numbers for pointed to line in rich editors.
...@@ -237,9 +268,9 @@ ...@@ -237,9 +268,9 @@
schema_a = document.createElement("a"), schema_a = document.createElement("a"),
pointed_a = document.createElement("a"); pointed_a = document.createElement("a");
schema_a.setAttribute("href", download_url); schema_a.setAttribute("href", download_url);
schema_a.text = (URLwithJio(download_url)).pathname; schema_a.text = (new URLwithJio(download_url)).pathname;
pointed_a.setAttribute("href", url_from_pointed); pointed_a.setAttribute("href", url_from_pointed);
pointed_a.text = (URLwithJio(url_from_pointed)).pathname; pointed_a.text = (new URLwithJio(url_from_pointed)).pathname;
g.props.schema_resolve_errors[url_from_pointed] = { g.props.schema_resolve_errors[url_from_pointed] = {
schemaPath: path, schemaPath: path,
message: [ message: [
...@@ -377,7 +408,8 @@ ...@@ -377,7 +408,8 @@
// XXX `if then else` construction can be simplify to // XXX `if then else` construction can be simplify to
// anyOf(allOf(if_schema, then_schema), else_schema) // anyOf(allOf(if_schema, then_schema), else_schema)
// and realized by existed rails // and realized by existed rails
if (schema === undefined) { if (schema === undefined ||
Object.keys(schema).length === 0) {
schema = true; schema = true;
} }
if (schema.anyOf !== undefined) { if (schema.anyOf !== undefined) {
...@@ -389,6 +421,24 @@ ...@@ -389,6 +421,24 @@
if (schema.$ref) { if (schema.$ref) {
return loadJSONSchema(g, schema.$ref, schema_path); return loadJSONSchema(g, schema.$ref, schema_path);
} }
if (schema.definitions) {
var key,
d,
url,
mapped_url;
for (key in schema.definitions) {
if (schema.definitions.hasOwnProperty(key)) {
d = schema.definitions[key];
url = d.$id || d.id;
if (url) {
mapped_url = convertUrlToAbsolute(g, schema_path, '#' + schema_path, window.location);
// XXX /?
mapped_url = mapped_url + 'definitions/' + key;
g.props.schemas[url] = mapped_url;
}
}
}
}
return RSVP.Queue() return RSVP.Queue()
.push(function () { .push(function () {
return [{ return [{
...@@ -499,7 +549,7 @@ ...@@ -499,7 +549,7 @@
a.setAttribute("href", "#" + errorUid); a.setAttribute("href", "#" + errorUid);
a.text = errorId; a.text = errorId;
element.setAttribute("class", "error-input"); element.setAttribute("class", "error-input");
error_message = element.querySelector("#" + id.replace(/\//g, "\\/") + " > .error"); error_message = document.getElementById(id).querySelector(".error");
error_message.appendChild(a); error_message.appendChild(a);
error_message.setAttribute("id", errorUid); error_message.setAttribute("id", errorUid);
if (error.message instanceof Array) { if (error.message instanceof Array) {
...@@ -548,16 +598,20 @@ ...@@ -548,16 +598,20 @@
.declareMethod('render', function (options) { .declareMethod('render', function (options) {
return this.changeState({ return this.changeState({
key: options.key, key: options.key,
value: JSON.stringify(options.value) || '""', value: JSON.stringify(options.value),
schema: JSON.stringify(options.schema), schema: JSON.stringify(options.schema),
saveOrigValue: options.saveOrigValue,
schema_url: options.schema_url, schema_url: options.schema_url,
editable: options.editable === undefined ? true : options.editable editable: options.editable === undefined ? true : options.editable
}); });
}) })
.onStateChange(function () { .onStateChange(function () {
var g = this, var g = this,
json_document = JSON.parse(g.state.value), json_document = g.state.value,
schema; schema;
if (json_document !== undefined) {
json_document = JSON.parse(json_document);
}
if (g.state.schema !== undefined) { if (g.state.schema !== undefined) {
schema = JSON.parse(g.state.schema); schema = JSON.parse(g.state.schema);
} }
...@@ -567,6 +621,12 @@ ...@@ -567,6 +621,12 @@
// it's need for schema uri computation // it's need for schema uri computation
g.props.schema = {}; g.props.schema = {};
g.props.schema_map = {}; g.props.schema_map = {};
g.props.schemas = {
"http://json-schema.org/draft-04/schema": "json-schema/schema4.json",
"http://json-schema.org/draft-06/schema": "json-schema/schema6.json",
"http://json-schema.org/draft-07/schema": "json-schema/schema7.json",
"http://json-schema.org/schema": "json-schema/schema7.json"
};
// schema_required_urls[path] = [ // schema_required_urls[path] = [
// stack required urls, on every unrequired field stack begining from [] // stack required urls, on every unrequired field stack begining from []
// "url1", // "url1",
...@@ -590,14 +650,28 @@ ...@@ -590,14 +650,28 @@
} }
}) })
.push(function () { .push(function () {
if (schema) { var schema_url,
return schema; queue;
if (schema !== undefined) {
schema_url = g.state.schema_url ||
schema.$id ||
schema.id ||
window.location.toString();
g.props.schema[""] = schema;
g.props.schema_map["/"] = schema_url;
g.props.schemas[schema_url] = schema;
queue = expandSchemaForField(g, schema, "/", true);
} else {
schema_url = g.state.schema_url ||
(json_document && json_document.$schema);
if (schema_url) {
queue = loadJSONSchema(g, schema_url);
}
} }
var schema_url = g.state.schema_url || if (queue) {
(json_document && json_document.$schema); return queue
if (schema_url) {
return loadJSONSchema(g, schema_url)
.push(function (schema_arr) { .push(function (schema_arr) {
// XXX for root of form use first schema selection
return schema_arr[0].schema; return schema_arr[0].schema;
}); });
} }
...@@ -608,6 +682,7 @@ ...@@ -608,6 +682,7 @@
schema: schema, schema: schema,
schema_path: "", schema_path: "",
document: json_document, document: json_document,
saveOrigValue: g.state.saveOrigValue,
required: true, required: true,
top: true top: true
}); });
...@@ -615,6 +690,11 @@ ...@@ -615,6 +690,11 @@
.push(function () { .push(function () {
return g.checkValidity(); return g.checkValidity();
}) })
.push(function () {
if (g.props.form_gadget.props.changed) {
g.notifyChange();
}
})
.push(function () { .push(function () {
return g; return g;
}); });
......
...@@ -5,6 +5,31 @@ ...@@ -5,6 +5,31 @@
"use strict"; "use strict";
var render_object; 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) { function decodeJsonPointer(_str) {
// https://tools.ietf.org/html/rfc6901#section-5 // https://tools.ietf.org/html/rfc6901#section-5
return _str.replace(/~1/g, '/').replace(/~0/g, '~'); return _str.replace(/~1/g, '/').replace(/~0/g, '~');
...@@ -16,12 +41,60 @@ ...@@ -16,12 +41,60 @@
} }
function getDocumentType(doc) { function getDocumentType(doc) {
if (doc === undefined) {
return;
}
if (doc === null) {
return "null";
}
if (doc instanceof Array) { if (doc instanceof Array) {
return "array"; return "array";
} }
return typeof doc; 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) { function createElement(type, props) {
var element = document.createElement(type), var element = document.createElement(type),
key; key;
...@@ -48,15 +121,18 @@ ...@@ -48,15 +121,18 @@
return schema; return schema;
} }
function render_selection(schema, json_document) { function render_enum(g, schema, json_document) {
var input = document.createElement("select"), var input = document.createElement("select"),
option, option,
i, i,
ser_value,
selected = false,
enum_arr = schema['enum']; enum_arr = schema['enum'];
input.size = 1; input.size = 1;
if (schema.default) { if (schema.default) {
if (json_document === undefined) { if (json_document === undefined) {
json_document = schema.default; json_document = schema.default;
g.props.changed = true;
} }
} else { } else {
option = document.createElement("option"); option = document.createElement("option");
...@@ -69,18 +145,40 @@ ...@@ -69,18 +145,40 @@
for (i = 0; i < enum_arr.length; i += 1) { for (i = 0; i < enum_arr.length; i += 1) {
if (enum_arr.hasOwnProperty(i)) { if (enum_arr.hasOwnProperty(i)) {
option = document.createElement("option"); option = document.createElement("option");
option.value = enum_arr[i]; // XXX use number id for speedup
option.textContent = enum_arr[i]; ser_value = JSON.stringify(enum_arr[i]);
if (enum_arr[i] === json_document) { 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; option.selected = true;
selected = true;
} }
input.appendChild(option); input.appendChild(option);
} }
} }
if (json_document !== undefined && !selected) {
// save original json_document even if it
// not support with schema
// XXX element should be removed on first user interact
option = document.createElement("option");
ser_value = JSON.stringify(json_document);
option.value = ser_value;
if (typeof json_document === "string") {
option.textContent = json_document;
} else {
option.textContent = ser_value;
}
option.selected = true;
input.appendChild(option);
}
return input; return input;
} }
function render_boolean(schema, json_document) { function render_boolean(g, schema, json_document) {
var input, var input,
schema_for_selection = { schema_for_selection = {
type: "boolean", type: "boolean",
...@@ -96,11 +194,27 @@ ...@@ -96,11 +194,27 @@
if (getDocumentType(schema.default) === "boolean") { if (getDocumentType(schema.default) === "boolean") {
schema_for_selection.default = schema.default; schema_for_selection.default = schema.default;
} }
input = render_selection(schema_for_selection, json_document); input = render_enum(g, schema_for_selection, json_document);
input.setAttribute('data-json-type', "boolean"); input.setAttribute('data-json-type', "boolean");
return input; return input;
} }
function render_const(schema, json_document) {
var input = document.createElement("input"),
ser_doc = JSON.stringify(json_document),
ser_const = JSON.stringify(schema.const);
input.setAttribute('readonly', true);
if (json_document === undefined || deepEqual(json_document, schema.const)) {
input.setAttribute('data-origin-value', ser_const);
input.value = ser_const;
} else {
input.value = ser_doc + '' + ser_const;
input.setAttribute('data-origin-value', ser_doc);
input.setAttribute('data-const-value', ser_const);
}
return input;
}
function render_textarea(json_document, data_format) { function render_textarea(json_document, data_format) {
var input = document.createElement("textarea"); var input = document.createElement("textarea");
if (json_document !== undefined) { if (json_document !== undefined) {
...@@ -160,8 +274,30 @@ ...@@ -160,8 +274,30 @@
schema_path: options.schema_path, schema_path: options.schema_path,
document: options.default_dict, document: options.default_dict,
display_label: options.parent_type !== "array", display_label: options.parent_type !== "array",
saveOrigValue: g.props.saveOrigValue,
scope: scope scope: scope
}); })
.push(function () {
if (form_gadget.props.changed) {
g.props.changed = true;
}
return form_gadget.element;
});
});
}
function expandItems(g, items, schema_path, minItems) {
if (!(items instanceof Array)) {
return g.expandSchema(items, schema_path, minItems !== 0);
}
var i,
tasks = [];
for (i = 0; i < items.length; i += 1) {
tasks.push(g.expandSchema(items[i], schema_path + '/' + i, i < minItems));
}
return RSVP.Queue()
.push(function () {
return RSVP.all(tasks);
}); });
} }
...@@ -197,7 +333,9 @@ ...@@ -197,7 +333,9 @@
function checkSchemaArrOneChoise(schema_arr) { function checkSchemaArrOneChoise(schema_arr) {
if (schema_arr.length === 1) { if (schema_arr.length === 1) {
if (schema_arr[0].schema === true) { if (schema_arr[0].schema === true ||
!(schema_arr[0].schema.hasOwnProperty('type') ||
schema_arr[0].schema.hasOwnProperty('enum'))) {
return false; return false;
} }
if (schema_arr[0].schema.type instanceof Array) { if (schema_arr[0].schema.type instanceof Array) {
...@@ -312,7 +450,9 @@ ...@@ -312,7 +450,9 @@
for (i = 0; i < schema_arr.length; i += 1) { for (i = 0; i < schema_arr.length; i += 1) {
schema_item = schema_arr[i]; schema_item = schema_arr[i];
description = schema_item.title; description = schema_item.title;
if (schema_item.schema === true) { if (schema_item.schema === true ||
!(schema_item.schema.hasOwnProperty('type') ||
schema_item.schema.hasOwnProperty('enum'))) {
generateItemsForAny(schema_item.property_name, schema_item.schema_path); generateItemsForAny(schema_item.property_name, schema_item.schema_path);
} else if (getDocumentType(schema_item.schema.type) === "array") { } else if (getDocumentType(schema_item.schema.type) === "array") {
description = description || schema_item.schema.description; description = description || schema_item.schema.description;
...@@ -473,46 +613,64 @@ ...@@ -473,46 +613,64 @@
}); });
} }
function render_array(gadget, schema, json_document, root, path, schema_path) { function render_array(gadget, schema, json_document, div_input, path, schema_path) {
var div, var input,
div_input, is_items_arr = schema.items instanceof Array,
input,
minItems = schema.minItems || 0; minItems = schema.minItems || 0;
div = document.createElement("div"); if (schema.default === undefined &&
div.setAttribute("class", "jsonformfield"); json_document === undefined) {
div.title = schema.description; div_input.setAttribute("data-undefined", "true");
}
div_input = document.createElement("div");
div_input.setAttribute("class", "input");
function element_append(child) { function element_append(child) {
if (child) { if (child) {
input.parentNode.insertBefore(child, input); input.parentNode.insertBefore(child, input);
div_input.removeAttribute("data-undefined");
} }
} }
function div_append(child) { function div_append(child) {
if (child) { if (child) {
div_input.appendChild(child); div_input.appendChild(child);
div_input.removeAttribute("data-undefined");
} }
} }
// XXX add failback rendering if json_document not array // XXX add failback rendering if json_document not array
// input = render_textarea(schema, default_value, "array"); // input = render_textarea(schema, default_value, "array");
return gadget.expandSchema(schema.items, schema_path + '/items', minItems !== 0) return RSVP.Queue()
.push(function (schema_arr) { .push(function () {
return RSVP.all([
expandItems(gadget, schema.items, schema_path + '/items', minItems),
gadget.expandSchema(schema.additionalItems, schema_path + '/additionalItems', false)
]);
})
.push(function (arr) {
var queue = RSVP.Queue(), var queue = RSVP.Queue(),
i, i,
schema_path_item = schema_path + '/items',
schema_arr_arr = arr[0],
additionalItems = arr[1],
schema_arr = schema_arr_arr,
len = 0; len = 0;
// XXX rewrite loading document for anyOf schema // XXX rewrite loading document for anyOf schema
if (json_document) { if (json_document) {
for (i = 0; i < json_document.length; i = i + 1) { for (i = 0; i < json_document.length; i = i + 1) {
if (is_items_arr) {
if (i < schema_arr_arr.length) {
schema_arr = schema_arr_arr[i];
schema_path_item = schema_path + '/items/' + i;
} else {
schema_arr = additionalItems;
schema_path_item = schema_path + '/additionalItems';
}
}
queue queue
.push( .push(
addSubForm.bind(gadget, { addSubForm.bind(gadget, {
gadget: gadget, gadget: gadget,
parent_type: 'array', parent_type: 'array',
schema_path: schema_path + '/items', schema_path: schema_path_item,
schema_part: schema_arr, schema_part: schema_arr,
default_dict: json_document[i], default_dict: json_document[i],
required: i < minItems required: i < minItems
...@@ -523,34 +681,78 @@ ...@@ -523,34 +681,78 @@
len = json_document.length; len = json_document.length;
} }
if (checkSchemaArrOneChoise(schema_arr) && minItems > len) { if (is_items_arr) {
for (i = 0; i < (minItems - len); i += 1) { if (minItems > len) {
queue for (i; i < (minItems - len); i += 1) {
.push( if (i < schema_arr_arr.length) {
addSubForm.bind(gadget, { schema_arr = schema_arr_arr[i];
gadget: gadget, } else {
parent_type: 'array', schema_arr = additionalItems;
schema_path: schema_arr[0].schema_path, }
schema_part: schema_arr[0].schema, if (!checkSchemaArrOneChoise(schema_arr)) {
required: true break;
}) }
) queue
.push(div_append); .push(
addSubForm.bind(gadget, {
gadget: gadget,
parent_type: 'array',
schema_path: schema_arr[0].schema_path,
schema_part: schema_arr[0].schema,
required: true
})
)
.push(div_append);
}
}
if (i < schema_arr_arr.length) {
schema_arr = schema_arr_arr[i];
} else {
schema_arr = additionalItems;
}
// XXX rerender on next item in schema.items
queue.push(render_schema_selector.bind(gadget,
gadget, "add item to array",
schema_arr, function (value) {
return addSubForm({
gadget: gadget,
parent_type: 'array',
type: value.type,
schema_path: value.schema_path,
schema_part: value.schema
})
.push(element_append);
}));
} else {
if (minItems > len && checkSchemaArrOneChoise(schema_arr)) {
for (i = 0; i < (minItems - len); i += 1) {
queue
.push(
addSubForm.bind(gadget, {
gadget: gadget,
parent_type: 'array',
schema_path: schema_arr[0].schema_path,
schema_part: schema_arr[0].schema,
required: true
})
)
.push(div_append);
}
} }
}
queue.push(render_schema_selector.bind(gadget, queue.push(render_schema_selector.bind(gadget,
gadget, "add item to array", gadget, "add item to array",
schema_arr, function (value) { schema_arr, function (value) {
return addSubForm({ return addSubForm({
gadget: gadget, gadget: gadget,
parent_type: 'array', parent_type: 'array',
type: value.type, type: value.type,
schema_path: value.schema_path, schema_path: value.schema_path,
schema_part: value.schema schema_part: value.schema
}) })
.push(element_append); .push(element_append);
})); }));
}
return queue; return queue;
}) })
.push(function (element) { .push(function (element) {
...@@ -559,8 +761,7 @@ ...@@ -559,8 +761,7 @@
// XXX update on every add/delete item // XXX update on every add/delete item
// input.hidden = maxItems !== undefined && json_document.length >= maxItems; // input.hidden = maxItems !== undefined && json_document.length >= maxItems;
div_input.appendChild(input); div_input.appendChild(input);
div.appendChild(div_input); gadget.props.arrays[path] = div_input;
root.appendChild(div);
}); });
} }
...@@ -575,6 +776,7 @@ ...@@ -575,6 +776,7 @@
error_message, error_message,
input, input,
first_path, first_path,
type_changed,
queue = RSVP.Queue(); queue = RSVP.Queue();
if (json_field instanceof Array) { if (json_field instanceof Array) {
...@@ -598,20 +800,33 @@ ...@@ -598,20 +800,33 @@
if (getDocumentType(json_field.type) === "string") { if (getDocumentType(json_field.type) === "string") {
type = json_field.type; type = json_field.type;
} // else json_field.type is array so we use type } else if (type === undefined &&
default_value === undefined &&
getDocumentType(json_field.type) === "array") {
type = json_field.type[0];
}
if (["object", "array"].indexOf(type) >= 0 &&
!(path !== "" && default_value === undefined) &&
getDocumentType(default_value) !== type) {
if (gadget.props.saveOrigValue) {
// XXX is not useful for user
// only for tests
json_field = {
const: default_value
};
} else {
gadget.props.changed = true;
}
}
if (type === undefined && default_value !== undefined) { if (type === undefined && default_value !== undefined) {
type = getDocumentType(default_value); type = getDocumentType(default_value);
} }
// XXX bad peace of code if (typeof type === "string") {
// i do not sure that type can be computed so // it's only for simple types so we not use
// but our schema in slapos bad // complex type detection
if (!type) { type_changed = default_value !== undefined &&
if (json_field.properties && typeof default_value !== type;
json_field.required &&
json_field.required.length > 0) {
type = "object";
}
} }
div = document.createElement("div"); div = document.createElement("div");
...@@ -664,34 +879,53 @@ ...@@ -664,34 +879,53 @@
div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/'); div_input.setAttribute("id", gadget.element.getAttribute("data-gadget-scope") + first_path + '/');
div_input.setAttribute("class", "input"); div_input.setAttribute("class", "input");
if (json_field.enum !== undefined) { if (json_field.const !== undefined) {
input = render_selection(json_field, default_value); input = render_const(json_field, default_value);
} else if (json_field.enum !== undefined) {
input = render_enum(gadget, json_field, default_value);
// XXX take in account existing type with enum
type_changed = false;
} }
if (type === "boolean") { if (!input && type === "null") {
input = render_boolean(json_field, default_value); input = render_const({const: null}, default_value);
} }
if (!input && ["string", "integer", "number"].indexOf(type) >= 0) { if (!input && type === "boolean") {
input = render_boolean(gadget, json_field, default_value);
}
if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) {
if (json_field.contentMediaType === "text/plain") { if (json_field.contentMediaType === "text/plain") {
input = render_textarea(default_value, "string"); input = render_textarea(default_value, "string");
} else { } else {
input = document.createElement("input"); input = document.createElement("input");
if (default_value !== undefined) { if (default_value !== undefined) {
if (typeof default_value === "object") { if (typeof default_value === "object") {
default_value = JSON.stringify(default_value); input.value = JSON.stringify(default_value);
} else {
input.value = default_value;
} }
input.value = default_value;
} }
if (type === "integer" || type === "number") { if (type === "integer" || type === "number") {
if (default_value === undefined && typeof json_field.default === "number") { if (default_value === undefined && typeof json_field.default === "number") {
input.value = json_field.default; input.value = json_field.default;
gadget.props.changed = true;
} }
input.type = "number";
input.setAttribute("data-json-type", type); input.setAttribute("data-json-type", type);
if (default_value === undefined || default_value === null ||
typeof default_value === "number") {
input.type = "number";
}
if (type === "integer") { if (type === "integer") {
input.setAttribute("step", "1"); input.setAttribute("step", "1");
if (typeof default_value === "number" &&
parseInt(default_value, 10) !== default_value) {
// original json_document contain float schema
// limit integer we can save original document
type_changed = true;
}
} }
if (type === "number") { if (type === "number") {
input.setAttribute("step", "any"); input.setAttribute("step", "any");
...@@ -699,6 +933,7 @@ ...@@ -699,6 +933,7 @@
} else { } else {
if (default_value === undefined && typeof json_field.default === "string") { if (default_value === undefined && typeof json_field.default === "string") {
input.value = json_field.default; input.value = json_field.default;
gadget.props.changed = true;
} }
input.type = "text"; input.type = "text";
if (json_field.pattern) { if (json_field.pattern) {
...@@ -712,7 +947,7 @@ ...@@ -712,7 +947,7 @@
} }
} }
if (type === "array") { if (!input && type === "array") {
queue = render_array( queue = render_array(
gadget, gadget,
json_field, json_field,
...@@ -721,10 +956,9 @@ ...@@ -721,10 +956,9 @@
first_path + '/', first_path + '/',
schema_path schema_path
); );
gadget.props.arrays[first_path + '/'] = div;
} }
if (type === "object") { if (!input && type === "object") {
queue queue
.push(function () { .push(function () {
return render_object( return render_object(
...@@ -744,6 +978,9 @@ ...@@ -744,6 +978,9 @@
gadget.props.inputs.push(input); gadget.props.inputs.push(input);
input.name = first_path; input.name = first_path;
input.required = options.required; input.required = options.required;
if (type_changed) {
input.setAttribute('data-origin-value', JSON.stringify(default_value));
}
// XXX for gui // XXX for gui
//input.setAttribute("class", "slapos-parameter"); //input.setAttribute("class", "slapos-parameter");
div_input.appendChild(input); div_input.appendChild(input);
...@@ -831,6 +1068,9 @@ ...@@ -831,6 +1068,9 @@
} }
function checkSchemaIsMetaSchema(schema) { function checkSchemaIsMetaSchema(schema) {
if (!schema) {
return false;
}
if (schema instanceof Array) { if (schema instanceof Array) {
var i, var i,
sch; sch;
...@@ -1215,7 +1455,8 @@ ...@@ -1215,7 +1455,8 @@
array = options.arrays[path] array = options.arrays[path]
.querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']"); .querySelectorAll("div[data-gadget-parent-scope='" + g.element.getAttribute("data-gadget-scope") + "']");
len = array.length; len = array.length;
if (len === 0) { if (len === 0 &&
!options.arrays[path].hasAttribute('data-undefined')) {
convertOnMultiLevel(multi_level_dict, path.slice(0, -1), []); convertOnMultiLevel(multi_level_dict, path.slice(0, -1), []);
} }
for (i = 0; i < len; i = i + 1) { for (i = 0; i < len; i = i + 1) {
...@@ -1246,26 +1487,33 @@ ...@@ -1246,26 +1487,33 @@
var json_dict = {}, var json_dict = {},
k; k;
g.props.inputs.forEach(function (input) { g.props.inputs.forEach(function (input) {
if (input.required || input.value !== "") { if (input.hasAttribute('data-origin-value')) {
var type = input.getAttribute('data-json-type'); json_dict[input.name] = JSON.parse(input.getAttribute('data-origin-value'));
if (type === 'number') { } else {
json_dict[input.name] = parseFloat(input.value); if (input.value !== "") {
} else if (type === "integer") { var type = input.getAttribute('data-json-type');
json_dict[input.name] = parseInt(input.value, 10); if (input.tagName === "SELECT" && input.value) {
} else if (type === "boolean") { // selection used for enums
if (input.value === "true") { json_dict[input.name] = JSON.parse(input.value);
json_dict[input.name] = true; } else if (type === 'number') {
} else if (input.value === "false") { json_dict[input.name] = parseFloat(input.value);
json_dict[input.name] = false; } else if (type === "integer") {
} json_dict[input.name] = parseInt(input.value, 10);
} else if (input.tagName === "TEXTAREA") { } else if (type === "boolean") {
if (input["data-format"] === "string") { if (input.value === "true") {
json_dict[input.name] = input.value; 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 { } else {
json_dict[input.name] = input.value.split('\n'); json_dict[input.name] = input.value;
} }
} else {
json_dict[input.name] = input.value;
} }
} }
}); });
...@@ -1275,7 +1523,20 @@ ...@@ -1275,7 +1523,20 @@
} }
} }
if (count_of_values === 0) { if (count_of_values === 0) {
return; switch (g.props.type) {
case "string":
return "";
case "number":
return null;
case "boolean":
return null;
case "array":
return [];
case "object":
return {};
default:
return;
}
} }
return multi_level_dict[""]; return multi_level_dict[""];
}); });
...@@ -1322,7 +1583,7 @@ ...@@ -1322,7 +1583,7 @@
.push(function () { .push(function () {
return g.element.setAttribute('data-json-property-name', new_name); return g.element.setAttribute('data-json-property-name', new_name);
}) })
.push(undefined, function (error) { .push(undefined, function () {
// XXX notify user // XXX notify user
event.srcElement.value = name; event.srcElement.value = name;
event.srcElement.focus(); event.srcElement.focus();
...@@ -1443,7 +1704,7 @@ ...@@ -1443,7 +1704,7 @@
.declareAcquiredMethod("notifyInvalid", "notifyInvalid") .declareAcquiredMethod("notifyInvalid", "notifyInvalid")
.declareAcquiredMethod("checkValidity", "checkValidity") .declareAcquiredMethod("checkValidity", "checkValidity")
.allowPublicAcquisition("notifyValid", function (arr, sub_scope) { .allowPublicAcquisition("notifyValid", function () {
return true; return true;
}) })
.allowPublicAcquisition("notifyChange", function (arr, sub_scope) { .allowPublicAcquisition("notifyChange", function (arr, sub_scope) {
...@@ -1461,6 +1722,8 @@ ...@@ -1461,6 +1722,8 @@
property_name = g.element.getAttribute('data-json-property-name'), property_name = g.element.getAttribute('data-json-property-name'),
schema = options.schema, schema = options.schema,
root; root;
g.props.changed = false;
g.props.saveOrigValue = options.saveOrigValue;
g.props.inputs = []; g.props.inputs = [];
g.props.add_buttons = []; g.props.add_buttons = [];
g.props.add_custom_data = {}; g.props.add_custom_data = {};
...@@ -1481,12 +1744,12 @@ ...@@ -1481,12 +1744,12 @@
options.delete_button = !options.required; options.delete_button = !options.required;
} }
} }
if (options.top && !options.type && !schema.type) { if (!options.type && schema && !schema.type) {
// XXX use "object" as type for support buggy options.type = guessSchemaType(schema);
// slapos schemas where some times type absent
// i need remove it in future
options.type = "object";
} }
// used for empty document generation
g.props.type = (schema && typeof schema.type === "string" && schema.type) ||
options.type || getDocumentType(options.document);
while (root.firstChild) { while (root.firstChild) {
root.removeChild(root.firstChild); root.removeChild(root.firstChild);
} }
...@@ -1515,6 +1778,9 @@ ...@@ -1515,6 +1778,9 @@
var link = evt.target.getAttribute("data-error-link"), var link = evt.target.getAttribute("data-error-link"),
button_list = this.props.add_buttons, button_list = this.props.add_buttons,
field_list = this.props.inputs,
input,
changed = false,
i; i;
if (link) { if (link) {
location.href = link; location.href = link;
...@@ -1526,6 +1792,21 @@ ...@@ -1526,6 +1792,21 @@
return button_list[i].event(evt); return button_list[i].event(evt);
} }
} }
for (i = 0; i < field_list.length; i = i + 1) {
if (evt.target === field_list[i]) {
input = evt.target;
if (input.hasAttribute('data-const-value')) {
input.value = input.getAttribute('data-const-value');
input.setAttribute('data-origin-value', input.value);
input.removeAttribute('data-const-value');
changed = true;
}
}
}
if (changed) {
return this.rootNotifyChange();
}
}) })
.onEvent('input', function (evt) { .onEvent('input', function (evt) {
...@@ -1536,10 +1817,21 @@ ...@@ -1536,10 +1817,21 @@
var gadget = this, var gadget = this,
field_list = this.props.inputs, field_list = this.props.inputs,
i, i,
input,
changed = false; changed = false;
// on form data field // on form data field
for (i = 0; i < field_list.length; i = i + 1) { for (i = 0; i < field_list.length; i = i + 1) {
if (evt.target === field_list[i]) { 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; changed = true;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment