Commit 7ec2fcd8 by Boris Kocherov

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

1 parent 2e43341d
......@@ -6,7 +6,6 @@
<title>ERP5</title>
<link rel="stylesheet" href="gadget_erp5_nojqm.css">
<script src="rsvp.js" type="text/javascript"></script>
<script src="jsonform/tv4.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="jio.js" type="text/javascript"></script>
<script src="jsonform.gadget.js" type="text/javascript"></script>
......
/*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/
/*global window, document, URL, rJS, RSVP, jIO, tv4, Blob */
(function (window, document, Blob, rJS, RSVP, jIO, tv4) {
(function (window, document, Blob, rJS, RSVP, jIO) {
"use strict";
var expandSchema;
......@@ -575,18 +575,32 @@
// 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;
}
if (schema.anyOf !== undefined) {
return anyOf(g, schema.anyOf, schema_path + '/anyOf', path, schema);
return anyOf(g, schema.anyOf, schema_p + '/anyOf', path, schema);
}
if (schema.oneOf !== undefined) {
return anyOf(g, schema.oneOf, schema_path + '/oneOf', path, schema);
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_path + '/allOf', path, schema);
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);
......@@ -655,6 +669,9 @@
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) {
......@@ -671,41 +688,43 @@
rJS(window)
.ready(function () {
var g = this;
g.props = {};
g.props = {
errors: {}
};
g.options = {};
})
.declareAcquiredMethod("resolveExternalReference", "resolveExternalReference")
.declareAcquiredMethod("notifyChange", "notifyChange")
.allowPublicAcquisition("rootNotifyChange", function (arr, scope) {
this.props.changed = true;
return this.notifyChange(arr[0], scope);
})
.declareAcquiredMethod("notifyValid", "notifyValid")
.declareAcquiredMethod("notifyInvalid", "notifyInvalid")
.allowPublicAcquisition("checkValidity", function (arr) {
return this.checkValidity(arr[0]);
.allowPublicAcquisition("notifyInvalid", function (arr) {
if (arr[0].length === 0) {
delete this.props.errors[arr[1]];
} else {
this.props.errors[arr[1]] = arr[0];
}
})
.declareMethod('getGadgetByPath', function (path) {
return this.props.form_gadget.getGadgetByPath(path || "/");
})
.declareMethod('checkValidity', function (json_document) {
// XXX need use local schema and local json document
// in every subgadget to take into account user anyOf choice
// and so more precisely point to issue
.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 () {
if (json_document === undefined) {
return g.getContent();
}
return json_document;
})
.push(function (json_d) {
gadget.state.value = JSON.stringify(json_d);
return tv4.validateMultiple(json_d, gadget.props.schema[""]);
})
.push(function (validation) {
var i,
error_id,
error,
......@@ -728,15 +747,18 @@
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]);
}
}
errors = errors.concat(validation.errors);
errors = errors.concat(validation.missing);
if (errors.length === 0) {
return gadget.notifyValid()
.push(function () {
......@@ -752,14 +774,14 @@
function print_error(error, errorUid, errorId) {
return function (element) {
var id = element.id,
error_message,
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 = document.getElementById(id).querySelector(".error");
error_message = element.querySelector(".error");
error_message.appendChild(a);
error_message.setAttribute("id", errorUid);
if (error.message instanceof Array) {
......@@ -785,10 +807,17 @@
for (i = 0; i < errors.length; i += 1) {
error = errors[i];
error_id = (i + 1).toString();
tasks.push(
g.getElementByPath(error.dataPath || "/")
.push(print_error(error, "error" + error_id, error_id))
);
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()
......@@ -824,7 +853,7 @@
z.schema = JSON.stringify(options.schema);
}
}
if (options.hasOwnProperty("schema_url")) {
if (options.schema_url) {
z.schema_url = (new URL(options.schema_url, window.location))
.toString();
}
......@@ -897,7 +926,7 @@
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);
queue = expandSchemaForField(g, schema, "/", "/", true);
} else {
schema_url = g.state.schema_url ||
(json_document && json_document.$schema);
......@@ -924,7 +953,7 @@
});
})
.push(function () {
return g.checkValidity();
return g.printErrors();
})
.push(function () {
if (g.props.form_gadget.props.changed) {
......@@ -935,21 +964,33 @@
return g;
})
.push(undefined, function (err) {
console.log(err);
console.error(err);
});
})
.declareMethod('rerender', function (path, schema) {
var g = this,
gadget;
if (path) {
return g.props.form_gadget.getGadgetByPath(path)
.push(function (ret) {
gadget = ret.gadget;
return gadget.getContent();
})
.push(function (value) {
return gadget.rerender({
schema: schema,
value: value
})
.push(function () {
return gadget.reValidate(value, schema);
});
});
}
})
.allowPublicAcquisition("expandSchema", function (arr) {
return expandSchemaForField(this, arr[0], arr[1], arr[2], arr[3]);
})
.onLoop(function () {
var gadget = this;
if (this.props.changed) {
return this.checkValidity()
.push(function () {
gadget.props.changed = false;
});
}
}, 500)
.declareMethod('getContent', function (sub_path) {
var g = this;
......@@ -976,4 +1017,4 @@
return {};
}, {mutex: 'changestate'});
}(window, document, Blob, rJS, RSVP, jIO, tv4));
\ No newline at end of file
}(window, document, Blob, rJS, RSVP, jIO));
\ No newline at end of file
......@@ -40,6 +40,10 @@
return _str.replace(/~/g, '~0').replace(/\//g, '~1');
}
function escapeId(s) {
return s.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, "\\$&");
}
function getDocumentType(doc) {
if (doc === undefined) {
return;
......@@ -1398,7 +1402,7 @@
gadget: g,
property_name: key,
parent_path: path,
delete_button: false,
delete_button: !schema_arr.external_reference,
schema_arr: filtered_schema_arr,
json_document: json_document[key]
})
......@@ -1743,18 +1747,44 @@
rJS(window)
.ready(function () {
var g = this;
g.props = {};
g.props = {
needValidate: false
};
g.options = {};
})
.declareAcquiredMethod("rNotifyChange", "rootNotifyChange")
.declareMethod("rootNotifyChange", function (path) {
var g = this;
return this.getJsonPath(path)
this.props.needValidate = true;
return g.getJsonPath(path)
.push(function (p) {
return g.rNotifyChange(p);
return g.rNotifyChange({
scope: g.element.getAttribute("data-gadget-scope"),
rel_path: path,
path: p
});
});
})
.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")));
return new RSVP.Queue()
.push(function () {
return RSVP.all(tasks);
})
.push(function () {
return g.deleteChildren();
});
})
.declareAcquiredMethod("selfRemove", "deleteChildren")
.declareAcquiredMethod("deleteChildren", "deleteChildren")
.allowPublicAcquisition("deleteChildren", function (arr, scope) {
var g = this,
key,
......@@ -1929,14 +1959,13 @@
.declareMethod('getElementByPath', function (data_path) {
return this.getGadgetByPath(data_path)
.push(function (ret) {
return document.getElementById(
ret.gadget.element.getAttribute("data-gadget-scope") + ret.path
);
return ret.gadget.element.querySelector("#" +
ret.gadget.element.getAttribute("data-gadget-scope") +
escapeId(ret.path));
});
})
.declareAcquiredMethod("notifyValid", "notifyValid")
.declareAcquiredMethod("notifyInvalid", "notifyInvalid")
.declareAcquiredMethod("checkValidity", "checkValidity")
.allowPublicAcquisition("notifyValid", function () {
return true;
......@@ -2004,14 +2033,25 @@
}
for_delete = Array.from(root.childNodes);
if (opt.schema) {
if (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 () {
for (var i = 0; i < for_delete.length; i += 1) {
var value = opt.value,
i;
for (i = 0; i < for_delete.length; i += 1) {
root.removeChild(for_delete[i]);
}
if (g.props.changed) {
value = undefined;
}
return g.checkValidity(value);
})
.push(function () {
return g.element;
});
})
......@@ -2055,6 +2095,120 @@
}
})
.declareAcquiredMethod("rootGetSchema", "getSchema")
.declareMethod('getSchema', function (json_document) {
var g = this,
schema_arr = g.props.schema_arr,
schema_path;
if (g.props.render_opt.selected_schema) {
schema_path = g.props.render_opt.selected_schema.schema_path;
} else {
if (json_document !== undefined && !g.props.render_opt.top) {
schema_path = schemaArrFilteredByDocument(schema_arr, json_document)[0].schema_path;
} else if (schema_arr.schema_path) {
schema_path = schema_arr.schema_path;
} else if (json_document !== undefined) {
schema_path = schemaArrFilteredByDocument(schema_arr, json_document)[0].schema_path;
} else {
schema_path = schema_arr[0].schema_path;
}
}
return g.rootGetSchema(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) {
return this.reValidate();
}
}, 500)
.onEvent('input', function (evt) {
var gadget = this,
field_list = this.props.inputs,
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!