Commit 0b866318 authored by Boris Kocherov's avatar Boris Kocherov

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

parent d0e41b15
/*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/ /*jslint nomen: true, maxlen: 200, indent: 2, maxerr: 100*/
/*global window, document, URL, rJS, RSVP, jIO, tv4, Blob */ /*global window, document, URL, rJS, RSVP, jIO, Blob */
(function (window, document, Blob, rJS, RSVP, jIO) { (function (window, document, Blob, rJS, RSVP, jIO) {
"use strict"; "use strict";
...@@ -676,14 +676,13 @@ ...@@ -676,14 +676,13 @@
kk = decodeJsonPointer(key_list[ii]); kk = decodeJsonPointer(key_list[ii]);
if (ii === key_list.length - 1) { if (ii === key_list.length - 1) {
return d[kk]; return d[kk];
} else { }
if (!d.hasOwnProperty(kk)) { if (!d.hasOwnProperty(kk)) {
return; return;
} }
d = d[kk]; d = d[kk];
} }
} }
}
rJS(window) rJS(window)
.ready(function () { .ready(function () {
...@@ -967,25 +966,48 @@ ...@@ -967,25 +966,48 @@
console.error(err); console.error(err);
}); });
}) })
.declareMethod('rerender', function (path, schema) { .declareMethod('rerender', function (opt) {
var g = this, var g = this,
gadget; gadget,
if (path) { queue = RSVP.Queue();
return g.props.form_gadget.getGadgetByPath(path) if (opt.scope) {
queue
.push(function () {
return g.props.form_gadget.getDeclaredGadget(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) { .push(function (ret) {
gadget = ret.gadget; gadget = ret.gadget;
});
}
return queue
.push(function () {
return gadget.getContent(); return gadget.getContent();
}) })
.push(function (value) { .push(function (value) {
return gadget.rerender({ return gadget.rerender({
schema: schema, schema: opt.schema,
value: value value: value,
ignore_incorrect: opt.ignore_incorrect
}) })
.push(function () { .push(function () {
return gadget.reValidate(value, schema); if (gadget.props.changed) {
value = undefined;
}
return gadget.reValidate(value, opt.schema);
}); });
}); });
}
}) })
.allowPublicAcquisition("expandSchema", function (arr) { .allowPublicAcquisition("expandSchema", function (arr) {
......
...@@ -125,24 +125,23 @@ ...@@ -125,24 +125,23 @@
return schema; return schema;
} }
function render_enum(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, ser_value,
selected = false, selected = false,
empty_option,
enum_arr = schema['enum']; enum_arr = schema['enum'];
input.size = 1; input.size = 1;
option = document.createElement("option"); empty_option = document.createElement("option");
option.value = ""; empty_option.value = "";
if (json_document === undefined) { if (json_document === undefined) {
option.selected = true; empty_option.selected = true;
} }
input.appendChild(option); input.appendChild(empty_option);
for (i = 0; i < enum_arr.length; i += 1) { for (i = 0; i < enum_arr.length; i += 1) {
if (enum_arr.hasOwnProperty(i)) {
option = document.createElement("option"); option = document.createElement("option");
// XXX use number id for speedup
ser_value = JSON.stringify(enum_arr[i]); ser_value = JSON.stringify(enum_arr[i]);
option.value = ser_value; option.value = ser_value;
if (typeof enum_arr[i] === "string") { if (typeof enum_arr[i] === "string") {
...@@ -156,8 +155,11 @@ ...@@ -156,8 +155,11 @@
} }
input.appendChild(option); input.appendChild(option);
} }
}
if (json_document !== undefined && !selected) { if (json_document !== undefined && !selected) {
if (g.props.ignore_incorrect) {
empty_option.selected = true;
g.props.changed = true;
} else {
// save original json_document even if it // save original json_document even if it
// not support with schema // not support with schema
// XXX element should be removed on first user interact // XXX element should be removed on first user interact
...@@ -172,11 +174,13 @@ ...@@ -172,11 +174,13 @@
option.selected = true; option.selected = true;
input.appendChild(option); input.appendChild(option);
} }
}
return input; return input;
} }
function render_enum_with_title(schema_arr, json_document, selected_schema) { function render_enum_with_title(g, schema_arr, json_document, selected_schema) {
var input = document.createElement("select"), var input = document.createElement("select"),
empty_option,
option, option,
i, i,
ser_value, ser_value,
...@@ -185,12 +189,12 @@ ...@@ -185,12 +189,12 @@
if (json_document === undefined && selected_schema !== undefined) { if (json_document === undefined && selected_schema !== undefined) {
json_document = selected_schema.schema.const; json_document = selected_schema.schema.const;
} }
option = document.createElement("option"); empty_option = document.createElement("option");
option.value = ""; empty_option.value = "";
if (json_document === undefined) { if (json_document === undefined) {
option.selected = true; empty_option.selected = true;
} }
input.appendChild(option); input.appendChild(empty_option);
for (i = 0; i < schema_arr.length; i += 1) { for (i = 0; i < schema_arr.length; i += 1) {
option = document.createElement("option"); option = document.createElement("option");
// XXX use number id for speedup // XXX use number id for speedup
...@@ -210,6 +214,10 @@ ...@@ -210,6 +214,10 @@
input.appendChild(option); input.appendChild(option);
} }
if (json_document !== undefined && !selected) { if (json_document !== undefined && !selected) {
if (g.props.ignore_incorrect) {
empty_option.selected = true;
g.props.changed = true;
} else {
// save original json_document even if it // save original json_document even if it
// not support with schema // not support with schema
// XXX element should be removed on first user interact // XXX element should be removed on first user interact
...@@ -224,10 +232,11 @@ ...@@ -224,10 +232,11 @@
option.selected = true; option.selected = true;
input.appendChild(option); input.appendChild(option);
} }
}
return input; return input;
} }
function render_boolean(json_document) { function render_boolean(g, json_document) {
var input, var input,
schema_for_selection = { schema_for_selection = {
type: "boolean", type: "boolean",
...@@ -240,7 +249,7 @@ ...@@ -240,7 +249,7 @@
if (json_document === "false") { if (json_document === "false") {
json_document = false; json_document = false;
} }
input = render_enum(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;
} }
...@@ -281,6 +290,14 @@ ...@@ -281,6 +290,14 @@
return input; 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) { function addSubForm(options) {
var input_element = options.element, var input_element = options.element,
g = options.gadget, g = options.gadget,
...@@ -288,7 +305,7 @@ ...@@ -288,7 +305,7 @@
parent_path, parent_path,
scope; scope;
scope = "j" + Math.random().toString(36).substr(2, 9); scope = generateUid(g);
parent_path = options.parent_path; parent_path = options.parent_path;
if (options.parent_type !== "array") { if (options.parent_type !== "array") {
property_name = options.property_name; property_name = options.property_name;
...@@ -328,6 +345,7 @@ ...@@ -328,6 +345,7 @@
document: options.json_document, document: options.json_document,
display_label: options.parent_type !== "array", display_label: options.parent_type !== "array",
saveOrigValue: g.props.saveOrigValue, saveOrigValue: g.props.saveOrigValue,
ignore_incorrect: g.props.ignore_incorrect,
scope: scope scope: scope
}) })
.push(function () { .push(function () {
...@@ -625,11 +643,16 @@ ...@@ -625,11 +643,16 @@
gadget.props.add_custom_data[scope] = { gadget.props.add_custom_data[scope] = {
element: g.element, element: g.element,
event: function () { event: function () {
var notify = {
action: "add"
};
return g.getContent() return g.getContent()
.push(function (value) { .push(function (value) {
return event(schema_alternatives[value[scope]].value); return event(schema_alternatives[value[scope]].value);
}) })
.push(function () { .push(function (v) {
notify.scope = v.scope;
notify.path = v.path;
if (rerender) { if (rerender) {
return rerender(g, schema_alternatives); return rerender(g, schema_alternatives);
} }
...@@ -639,9 +662,7 @@ ...@@ -639,9 +662,7 @@
return g.render(render_options); return g.render(render_options);
}) })
.push(function () { .push(function () {
// XXX need path argument return gadget.rootNotifyChange(notify);
// absent in current context
return gadget.rootNotifyChange();
}); });
}, },
rerender: function () { rerender: function () {
...@@ -684,8 +705,13 @@ ...@@ -684,8 +705,13 @@
gadget.props.add_buttons.push({ gadget.props.add_buttons.push({
element: input, element: input,
event: function () { event: function () {
var notify = {
action: "add"
};
return event(schema_alternatives[0].value) return event(schema_alternatives[0].value)
.push(function () { .push(function (v) {
notify.scope = v.scope;
notify.path = v.path;
if (rerender) { if (rerender) {
return rerender(undefined, schema_alternatives); return rerender(undefined, schema_alternatives);
} }
...@@ -697,9 +723,7 @@ ...@@ -697,9 +723,7 @@
} else { } else {
input.removeAttribute("style"); input.removeAttribute("style");
} }
// XXX need path argument return gadget.rootNotifyChange(notify);
// absent in current context
return gadget.rootNotifyChange();
}); });
}, },
rerender: function () { rerender: function () {
...@@ -729,8 +753,23 @@ ...@@ -729,8 +753,23 @@
}); });
} }
function get_scope_path_from_element(gadget, element) {
var scope = element.getAttribute("data-gadget-scope");
return gadget.getDeclaredGadget(scope)
.push(function (g) {
return g.getJsonPath();
})
.push(function (path) {
return {
scope: scope,
path: path
};
});
}
function render_array(gadget, schema, json_document, div_input, path, schema_path) { function render_array(gadget, schema, json_document, div_input, path, schema_path) {
var input, var input,
array_path,
is_items_arr = schema.items instanceof Array, is_items_arr = schema.items instanceof Array,
minItems = schema.minItems || 0; minItems = schema.minItems || 0;
if (json_document instanceof Array && if (json_document instanceof Array &&
...@@ -738,10 +777,36 @@ ...@@ -738,10 +777,36 @@
div_input.setAttribute("data-json-empty-array", "true"); 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) { function element_append(child) {
if (child) { if (child) {
input.parentNode.insertBefore(child, input); input.parentNode.insertBefore(child, input);
div_input.removeAttribute("data-json-empty-array"); div_input.removeAttribute("data-json-empty-array");
return get_scope_path_from_element(gadget, child);
} }
} }
...@@ -756,6 +821,7 @@ ...@@ -756,6 +821,7 @@
// input = render_textarea(schema, default_value, "array"); // input = render_textarea(schema, default_value, "array");
return gadget.getJsonPath(path) return gadget.getJsonPath(path)
.push(function (p) { .push(function (p) {
array_path = p;
return RSVP.all([ return RSVP.all([
expandItems(gadget, schema.items, schema_path + '/items', p, minItems), expandItems(gadget, schema.items, schema_path + '/items', p, minItems),
gadget.expandSchema(schema.additionalItems, schema_path + '/additionalItems', p, false) gadget.expandSchema(schema.additionalItems, schema_path + '/additionalItems', p, false)
...@@ -839,17 +905,9 @@ ...@@ -839,17 +905,9 @@
})); }));
} else { } else {
if (minItems > len && checkSchemaArrOneChoise(schema_arr)) { if (minItems > len && checkSchemaArrOneChoise(schema_arr)) {
for (i = 0; i < (minItems - len); i += 1) { for (i = len; i < minItems; i += 1) {
queue queue
.push( .push(add_item_form(i, true))
addSubForm.bind(gadget, {
gadget: gadget,
parent_type: 'array',
parent_path: path,
schema_arr: schema_arr,
required: true
})
)
.push(div_append); .push(div_append);
} }
} }
...@@ -857,14 +915,7 @@ ...@@ -857,14 +915,7 @@
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 add_item_form(current_array_length(), false)(value)
gadget: gadget,
parent_type: 'array',
parent_path: path,
type: value.type,
selected_schema: value,
schema_arr: schema_arr
})
.push(element_append); .push(element_append);
})); }));
} }
...@@ -956,13 +1007,13 @@ ...@@ -956,13 +1007,13 @@
// render input begin // render input begin
if (!input && schema_arr[0].is_arr_of_const && schema_arr.length > 1) { if (!input && schema_arr[0].is_arr_of_const && schema_arr.length > 1) {
input = render_enum_with_title(schema_arr, json_document, options.selected_schema); input = render_enum_with_title(gadget, schema_arr, json_document, options.selected_schema);
} }
if (!input && schema.const !== undefined) { if (!input && schema.const !== undefined) {
input = render_const(gadget, schema, json_document); input = render_const(gadget, schema, json_document);
} }
if (!input && schema.enum !== undefined) { if (!input && schema.enum !== undefined) {
input = render_enum(schema, json_document); input = render_enum(gadget, schema, json_document);
// XXX take in account existing type with enum // XXX take in account existing type with enum
type_changed = false; type_changed = false;
} }
...@@ -972,7 +1023,7 @@ ...@@ -972,7 +1023,7 @@
} }
if (!input && type === "boolean") { if (!input && type === "boolean") {
input = render_boolean(json_document); input = render_boolean(gadget, json_document);
} }
if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) { if (!input && ["string", "integer", "number", "null"].indexOf(type) >= 0) {
...@@ -1351,6 +1402,7 @@ ...@@ -1351,6 +1402,7 @@
if (child) { if (child) {
// insert additionalProperty before selector // insert additionalProperty before selector
selector.element.parentNode.insertBefore(child, selector.element); selector.element.parentNode.insertBefore(child, selector.element);
return get_scope_path_from_element(g, child);
} }
} }
...@@ -1521,6 +1573,10 @@ ...@@ -1521,6 +1573,10 @@
return queue; return queue;
}) })
.push(function () { .push(function () {
if (g.props.ignore_incorrect) {
g.props.changed = true;
return;
}
var key, var key,
queue = RSVP.Queue(); queue = RSVP.Queue();
for (key in json_document) { for (key in json_document) {
...@@ -1753,15 +1809,16 @@ ...@@ -1753,15 +1809,16 @@
g.options = {}; g.options = {};
}) })
.declareAcquiredMethod("rNotifyChange", "rootNotifyChange") .declareAcquiredMethod("rNotifyChange", "rootNotifyChange")
.declareMethod("rootNotifyChange", function (path) { .declareMethod("rootNotifyChange", function (v) {
var g = this; var g = this;
this.props.needValidate = true; this.props.needValidate = true;
return g.getJsonPath(path) return g.getJsonPath(v.path)
.push(function (p) { .push(function (p) {
return g.rNotifyChange({ return g.rNotifyChange({
scope: g.element.getAttribute("data-gadget-scope"), scope: v.scope || g.element.getAttribute("data-gadget-scope"),
rel_path: path, rel_path: v.path,
path: p path: p,
action: v.action
}); });
}); });
}) })
...@@ -1781,7 +1838,10 @@ ...@@ -1781,7 +1838,10 @@
return RSVP.all(tasks); return RSVP.all(tasks);
}) })
.push(function () { .push(function () {
return g.deleteChildren(); return g.getJsonPath();
})
.push(function (path) {
return g.deleteChildren(path);
}); });
}) })
.declareAcquiredMethod("deleteChildren", "deleteChildren") .declareAcquiredMethod("deleteChildren", "deleteChildren")
...@@ -1789,6 +1849,7 @@ ...@@ -1789,6 +1849,7 @@
var g = this, var g = this,
key, key,
i, i,
path = arr[0],
button_list = this.props.add_buttons, button_list = this.props.add_buttons,
objects = this.props.objects, objects = this.props.objects,
element = getSubGadgetElement(g, scope), element = getSubGadgetElement(g, scope),
...@@ -1815,7 +1876,11 @@ ...@@ -1815,7 +1876,11 @@
return RSVP.all(tasks); return RSVP.all(tasks);
}) })
.push(function () { .push(function () {
return g.rootNotifyChange(); return g.rootNotifyChange({
scope: scope,
path: path,
action: "delete"
});
}) })
.push(function () { .push(function () {
// remove gadget at end otherwise // remove gadget at end otherwise
...@@ -1978,13 +2043,14 @@ ...@@ -1978,13 +2043,14 @@
if (event_object && evt.type === "change") { if (event_object && evt.type === "change") {
return event_object.event(); return event_object.event();
} }
return g.rootNotifyChange(evt.target.name); return g.rootNotifyChange({
path: evt.target.name
});
}) })
.declareMethod('renderForm', function (options) { .declareMethod('renderForm', function (options) {
var g = this, var g = this,
property_name = g.element.getAttribute('data-json-property-name'), property_name = g.element.getAttribute('data-json-property-name'),
schema = options.schema_arr !== undefined && options.schema_arr[0].schema; schema = options.schema_arr !== undefined && options.schema_arr[0].schema;
g.props.changed = false;
g.props.saveOrigValue = options.saveOrigValue; g.props.saveOrigValue = options.saveOrigValue;
g.props.path = options.path; // self gadget scope g.props.path = options.path; // self gadget scope
if (!property_name || !options.display_label) { if (!property_name || !options.display_label) {
...@@ -2009,6 +2075,8 @@ ...@@ -2009,6 +2075,8 @@
} }
g.props.property_name = property_name; g.props.property_name = property_name;
g.props.schema_arr = options.schema_arr; 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 = { g.props.render_opt = {
type: options.type, type: options.type,
selected_schema: options.selected_schema, selected_schema: options.selected_schema,
...@@ -2023,6 +2091,10 @@ ...@@ -2023,6 +2091,10 @@
var g = this, var g = this,
for_delete, for_delete,
root = g.element.querySelector('[data-json-path="/"]'); root = g.element.querySelector('[data-json-path="/"]');
if (opt.ignore_incorrect !== undefined) {
g.props.ignore_incorrect = opt.ignore_incorrect;
}
g.props.changed = false;
g.props.inputs = []; g.props.inputs = [];
g.props.add_buttons = []; g.props.add_buttons = [];
g.props.add_custom_data = {}; g.props.add_custom_data = {};
...@@ -2034,6 +2106,8 @@ ...@@ -2034,6 +2106,8 @@
for_delete = Array.from(root.childNodes); for_delete = Array.from(root.childNodes);
if (opt.schema) { if (opt.schema) {
if (g.props.render_opt.selected_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.render_opt.selected_schema.schema = opt.schema;
} }
g.props.schema_arr[0].schema = opt.schema; g.props.schema_arr[0].schema = opt.schema;
...@@ -2233,7 +2307,9 @@ ...@@ -2233,7 +2307,9 @@
} }
} }
if (changed) { if (changed) {
return gadget.rootNotifyChange(input.name); return gadget.rootNotifyChange({
path: input.name
});
} }
}) })
......
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