Commit f0fd3841 authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_renderjs_ui] Reimplement multilistfield

Reuse listfield gadget for the rendering.

Dynamically add/remove listfield to improve usage.
parent c27b1d1b
...@@ -8,21 +8,10 @@ ...@@ -8,21 +8,10 @@
<!-- renderjs --> <!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script> <script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script> <script src="renderjs.js" type="text/javascript"></script>
<script src="handlebars.js" type="text/javascript"></script>
<!-- custom script --> <!-- custom script -->
<script src="gadget_erp5_field_multilist.js" type="text/javascript"></script> <script src="gadget_erp5_field_multilist.js" type="text/javascript"></script>
<script id="option-template" type="text/x-handlebars-template">
<option value="{{value}}" data-i18n="{{text}}">{{text}}</option>
</script>
<script id="selected-option-template" type="text/x-handlebars-template">
<option selected="selected" data-i18n="{{text}}" value="{{value}}">{{text}}</option>
</script>
</head> </head>
<body> <body>
<fieldset class="ui-controlgroup ui-corner-all ui-controlgroup-vertical">
<div class="ui-controlgroup-controls">
</div>
</fieldset>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>940.61935.4199.24456</string> </value> <value> <string>954.38753.57848.4522</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -252,8 +252,8 @@ ...@@ -252,8 +252,8 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1424105340.28</float> <float>1476452909.56</float>
<string>GMT</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
</object> </object>
......
/*global window, rJS, Handlebars, document, RSVP, loopEventListener*/ /*global window, rJS, document, RSVP*/
/*jslint nomen: true, indent: 2, maxerr: 3 */ /*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80, unparam: true */
(function (window, rJS, Handlebars, document, RSVP) { (function (window, rJS, document, RSVP) {
'use strict'; 'use strict';
/////////////////////////////////////////////////////////////////
// Handlebars function appendListField(gadget, value, item_list) {
///////////////////////////////////////////////////////////////// var div = document.createElement('div');
// Precompile the templates while loading the first gadget instance gadget.element.appendChild(div);
var gadget_klass = rJS(window), return new RSVP.Queue()
option_source = gadget_klass.__template_element .push(function () {
.getElementById("option-template") return gadget.declareGadget('gadget_erp5_field_list.html',
.innerHTML, {element: div});
option_template = Handlebars.compile(option_source), })
selected_option_source = gadget_klass.__template_element .push(function (result) {
.getElementById("selected-option-template") var state = {
.innerHTML, value: value,
selected_option_template = Handlebars.compile(selected_option_source); items: item_list,
gadget_klass editable: gadget.state.editable,
.ready(function (g) { // Single listfield is never mandatory.
g.props = {}; // Check requirement globally instead
required: 0,
key: 'sub',
title: gadget.state.title
};
return result.render({field_json: state});
});
}
rJS(window)
.declareMethod('render', function (options) {
var field_json = options.field_json || {},
state_dict = {
value_list: JSON.stringify(field_json.value ||
field_json.default || []),
item_list: JSON.stringify(field_json.items),
editable: field_json.editable,
required: field_json.required,
name: field_json.key,
title: field_json.title,
sub_select_key: field_json.sub_select_key,
sub_input_key: field_json.sub_input_key
};
return this.changeState(state_dict);
}) })
// Assign the element to a variable
.ready(function (g) { .onStateChange(function () {
return g.getElement() var i,
.push(function (element) { value_list = JSON.parse(this.state.value_list),
g.props.element = element; item_list = JSON.parse(this.state.item_list),
}); queue = new RSVP.Queue(),
element = this.element,
gadget = this;
// Always display an empty value at the end
value_list.push("");
// Clear first to DOM, append after to reduce flickering/manip
while (element.firstChild) {
element.removeChild(element.firstChild);
}
function enQueue() {
var argument_list = arguments;
queue
.push(function () {
return appendListField.apply(this, argument_list);
});
}
for (i = 0; i < value_list.length; i += 1) {
enQueue(gadget, value_list[i], item_list);
}
return queue;
}) })
.declareAcquiredMethod("translateHtml", "translateHtml")
.declareMethod('render', function (options) { .declareMethod('getContent', function () {
var gadget = this, var i,
selects = [], element = this.element,
tmp, queue = new RSVP.Queue(),
template, final_result = {},
container, result_list = [],
field_json = options.field_json, gadget = this;
i,
j; function calculateSubContent(node) {
gadget.props.field_json = field_json; queue
container = gadget.props.element.querySelector(".ui-controlgroup-controls"); .push(function () {
field_json.default[field_json.default.length] = ""; var scope = node.getAttribute('data-gadget-scope');
for (i = 0; i < field_json.default.length; i += 1) { if (scope !== null) {
tmp = ""; return gadget.getDeclaredGadget(
selects[i] = document.createElement("select"); node.getAttribute('data-gadget-scope')
container.appendChild(selects[i]); )
for (j = 0; j < field_json.items.length; j += 1) { .push(function (result) {
if (field_json.items[j][1] === field_json.default[i]) { return result.getContent();
template = selected_option_template; })
} else { .push(function (result) {
template = option_template; result_list.push(result.sub);
} });
tmp += template({ }
value: field_json.items[j][1],
text: field_json.items[j][0]
}); });
}
if (this.state.editable) {
for (i = 0; i < element.childNodes.length; i += 1) {
calculateSubContent(element.childNodes[i]);
} }
selects[i].innerHTML = tmp; return queue
.push(function () {
final_result[gadget.state.sub_select_key] = result_list;
final_result[gadget.state.sub_input_key] = 0;
return final_result;
});
} }
return new RSVP.Queue() return final_result;
.push(function () { })
var list = [];
for (i = 0; i < selects.length; i += 1) { /*
list.push(gadget.translateHtml(selects[i].outerHTML)); .declareMethod('getTextContent', function () {
} // I don't know if a multilistfield was ever used in a listbox
return RSVP.all(list); // Skip for now
throw new Error('not implemented');
})
*/
.allowPublicAcquisition('notifyValid', function () {
return;
})
.declareAcquiredMethod("notifyValid", "notifyValid")
.declareAcquiredMethod("notifyInvalid", "notifyInvalid")
.declareAcquiredMethod("notifyChange", "notifyChange")
.allowPublicAcquisition('notifyChange', function (argument_list, scope) {
// An empty listfield should be created when the last one is modified
// An empty listfield should be removed
var gadget = this,
sub_gadget;
return gadget.getDeclaredGadget(scope)
.push(function (result) {
sub_gadget = result;
return sub_gadget.getContent();
}) })
.push(function (translated_htmls) { .push(function (result) {
var select_div, var value = result.sub;
wrapper_class_string, if (sub_gadget.element === gadget.element.lastChild) {
div = document.createElement("div"); if (value) {
for (i = 0; i < translated_htmls.length; i += 1) { return appendListField(gadget, "",
div.innerHTML = translated_htmls[i]; JSON.parse(gadget.state.item_list));
select_div = div.querySelector("select");
selects[i].innerHTML = select_div.innerHTML;
if (field_json.editable !== 1) {
selects[i].setAttribute('readonly', 'readonly');
wrapper_class_string = wrapper_class_string || "";
wrapper_class_string += 'ui-state-readonly ';
}
// XXX add first + last class, needs to be improved
if (i === 0) {
wrapper_class_string = wrapper_class_string || "";
wrapper_class_string += 'ui-first-child';
} }
if (i === translated_htmls.length - 1) { } else {
wrapper_class_string = wrapper_class_string || ""; if (!value) {
wrapper_class_string += 'ui-last-child'; gadget.element.removeChild(sub_gadget.element);
}
if (wrapper_class_string) {
selects[i].setAttribute('data-wrapper-class', wrapper_class_string);
wrapper_class_string = undefined;
} }
} }
})
.push(function () {
return gadget.notifyChange();
}); });
}) })
.declareMethod('getContent', function () {
var gadget = this,
result = {},
tmp = [],
selects = this.props.element.querySelectorAll('select'),
i;
for (i = 0; i < selects.length; i += 1) { .declareMethod('checkValidity', function () {
tmp.push(selects[i].options[selects[i].selectedIndex].value); var gadget = this,
empty = true;
if (this.state.editable && this.state.required) {
return this.getContent()
.push(function (result) {
var value_list = result[gadget.state.sub_select_key],
i;
for (i = 0; i < value_list.length; i += 1) {
if (value_list[i]) {
empty = false;
}
}
if (empty) {
return gadget.notifyInvalid("Please fill out this field.");
}
return gadget.notifyValid();
})
.push(function () {
return !empty;
});
} }
result[gadget.props.field_json.sub_select_key] = tmp; return true;
result[gadget.props.field_json.sub_input_key] = 0;
return result;
}); });
}(window, rJS, Handlebars, document, RSVP));
\ No newline at end of file }(window, rJS, document, RSVP));
\ No newline at end of file
...@@ -216,7 +216,7 @@ ...@@ -216,7 +216,7 @@
</item> </item>
<item> <item>
<key> <string>actor</string> </key> <key> <string>actor</string> </key>
<value> <string>xiaowu</string> </value> <value> <string>zope</string> </value>
</item> </item>
<item> <item>
<key> <string>comment</string> </key> <key> <string>comment</string> </key>
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>944.12751.13272.54476</string> </value> <value> <string>954.38943.62606.2730</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -248,8 +248,8 @@ ...@@ -248,8 +248,8 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1436170826.41</float> <float>1476458904.36</float>
<string>GMT+2</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
</object> </object>
......
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