Commit 586467b7 authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_renderjs_ui] Header: reduce number of DOM modifications

parent 636ecab1
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<div class="ui-controlgroup-controls"> <div class="ui-controlgroup-controls">
</div> </div>
</div> </div>
<h1 class="ui-title"></h1> <h1 class="ui-title"></h1>
<div class="ui-controlgroup ui-controlgroup-horizontal ui-btn-right"> <div class="ui-controlgroup ui-controlgroup-horizontal ui-btn-right">
...@@ -54,16 +54,5 @@ ...@@ -54,16 +54,5 @@
</div> </div>
</div> </div>
<!-- First navigation line -->
<!--header data-role="header">
<div><a href="#leftpanel" class="responsive ui-btn ui-icon-bars ui-btn-icon-left">Menu</a></div>
<div data-gadget-url="gadget_erp5_breadcrumb.html"
data-gadget-scope="breadcrumb"
data-gadget-sandbox="public"></div>
<div><a class="responsive ui-btn ui-icon-plus ui-btn-icon-left ui-disabled" role="button" data-role="button">New</a></div>
</header>
<div>
</div-->
</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>951.35286.47701.22630</string> </value> <value> <string>955.10496.5559.9130</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1466516947.72</float> <float>1479462688.84</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint nomen: true, indent: 2, maxerr: 3 */ /*jslint nomen: true, indent: 2, maxerr: 3 */
/*global window, rJS, Handlebars, document, loopEventListener, RSVP */ /*global window, rJS, Handlebars, document, RSVP */
(function (window, rJS, Handlebars, document, loopEventListener, RSVP) { (function (window, rJS, Handlebars, document, RSVP) {
"use strict"; "use strict";
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -8,59 +8,82 @@ ...@@ -8,59 +8,82 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Precompile the templates while loading the first gadget instance // Precompile the templates while loading the first gadget instance
var gadget_klass = rJS(window), var gadget_klass = rJS(window),
template_element = gadget_klass.__template_element,
header_title_source = gadget_klass.__template_element header_title_template = Handlebars.compile(template_element
.getElementById("header-title-template") .getElementById("header-title-template")
.innerHTML, .innerHTML),
header_title_template = Handlebars.compile(header_title_source), header_title_link_template = Handlebars.compile(template_element
.getElementById("header-title-link-template")
.innerHTML),
sub_header_template = Handlebars.compile(template_element
.getElementById("sub-header-template")
.innerHTML),
header_button_template = Handlebars.compile(template_element
.getElementById("header-button-template")
.innerHTML),
header_link_template = Handlebars.compile(template_element
.getElementById("header-link-template")
.innerHTML),
header_title_link_source = gadget_klass.__template_element possible_left_button_list = [
.getElementById("header-title-link-template") ['panel_action', 'Menu', 'bars', 'panel']
.innerHTML, ],
header_title_link_template = Handlebars.compile(header_title_link_source), possible_main_link_list = [
// ['menu_url', 'Menu', 'bars'],
sub_header_source = gadget_klass.__template_element ['front_url', 'Front', 'arrow-up'],
.getElementById("sub-header-template") ['selection_url', 'Previous', 'arrow-up'],
.innerHTML, ['cancel_url', 'Cancel', 'times'],
sub_header_template = Handlebars.compile(sub_header_source), ['back_url', 'Back', 'times']
],
header_button_source = gadget_klass.__template_element possible_right_link_list = [
.getElementById("header-button-template") ['edit_url', 'Editable', 'pencil'],
.innerHTML, ['view_url', 'Viewable', 'eye'],
header_button_template = Handlebars.compile(header_button_source), ['right_url', 'New', 'plus']
header_link_source = gadget_klass.__template_element ],
.getElementById("header-link-template") possible_right_button_list = [
.innerHTML, ['save_action', 'Save', 'check', 'submit'],
header_link_template = Handlebars.compile(header_link_source); ['submit_action', 'Proceed', 'check', 'submit'],
['add_action', 'Add', 'check', 'submit'],
['filter_action', 'Filter', 'filter', 'submit']
],
possible_sub_header_list = [
['tab_url', 'Views', 'eye'],
['jump_url', 'Jump', 'plane'],
['delete_url', 'Delete', 'times'],
['export_url', 'Export', 'share-square-o'],
['actions_url', 'Actions', 'cogs'],
['cut_url', 'Cut', 'scissors'],
['add_url', 'Add', 'plus'],
['previous_url', 'Previous', 'carat-l'],
['next_url', 'Next', 'carat-r']
];
gadget_klass gadget_klass
.setState({
loaded: false,
modified: false,
submitted: true,
error: false,
title_text: '',
title_icon: undefined,
title_url: undefined
})
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// ready // ready
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Init local properties // Init local properties
.ready(function (g) { .ready(function () {
g.props = {}; this.props = {
g.stats = { element_list: [
loaded: false, this.element.querySelector("h1"),
modified: false, this.element.querySelector(".ui-btn-left > div"),
submitted: true, this.element.querySelector(".ui-btn-right > div"),
error: false, this.element.querySelector(".ui-subheader").querySelector("ul")
options: {} ]
}; };
}) })
// Assign the element to a variable
.ready(function (g) {
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.sub_header_element = element.querySelector(".ui-subheader");
g.props.sub_header_ul = g.props.sub_header_element.querySelector("ul");
g.props.left_link = element.querySelector(".ui-btn-left > div");
g.props.right_link = element.querySelector(".ui-btn-right > div");
g.props.title_element = element.querySelector("h1");
});
})
////////////////////////////////////////////// //////////////////////////////////////////////
// acquired methods // acquired methods
////////////////////////////////////////////// //////////////////////////////////////////////
...@@ -71,235 +94,108 @@ ...@@ -71,235 +94,108 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// declared methods // declared methods
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
.declareMethod('notifyError', function () { .declareMethod('notifyLoaded', function () {
this.stats.loaded = true; return this.changeState({
this.stats.submitted = true; loaded: true
this.stats.error = true; });
var gadget = this;
return this.render(this.stats.options)
.push(function () {
gadget.stats.error = false;
});
})
.declareMethod('notifyUpdate', function () {
return this.render(this.stats.options);
}) })
.declareMethod('notifyLoading', function () { .declareMethod('notifyLoading', function () {
if (this.stats.loaded) { return this.changeState({
this.stats.loaded = false; loaded: false
return this.render(this.stats.options); });
}
}) })
.declareMethod('notifyLoaded', function () { .declareMethod('notifySubmitted', function () {
if (!this.stats.loaded) { return this.changeState({
this.stats.loaded = true; submitted: true,
return this.render(this.stats.options); // Change modify here, to allow user to redo some modification and being correctly notified
} modified: false
}) });
.declareMethod('notifyChange', function () {
if (!this.stats.modified) {
this.stats.modified = true;
// Directly modify the previous calculated header
// in order not to remove the submit input
// and still receive 'submit' event
var button = this.props.right_link.querySelector('button'),
class_list;
if (button !== null) {
class_list = button.classList;
if (class_list.contains('ui-icon-check')) {
class_list.remove('ui-icon-check');
class_list.add('ui-icon-warning');
}
}
}
}) })
.declareMethod('notifySubmitting', function () { .declareMethod('notifySubmitting', function () {
if (this.stats.submitted) { return this.changeState({
this.stats.submitted = false; submitted: false
return this.render(this.stats.options); });
}
}) })
.declareMethod('notifySubmitted', function () { .declareMethod('notifyError', function () {
var render_needed = false; return this.changeState({
if (!this.stats.submitted) { loaded: true,
render_needed = true; submitted: true,
this.stats.submitted = true; error: true
} });
if (this.stats.modified) { })
render_needed = true; .declareMethod('notifyChange', function () {
// Change modify here, to allow user to redo some modification and being correctly notified return this.changeState({
this.stats.modified = false; modified: true
} });
if (render_needed) { })
return this.render(this.stats.options); /*
} .declareMethod('notifyUpdate', function () {
return this.render(this.stats.options);
}) })
*/
.declareMethod('render', function (options) { .declareMethod('render', function (options) {
var gadget = this, var state = {
possible_left_link_list = [], error: false,
possible_left_button_list = [ title_text: '',
['panel_action', 'Menu', 'bars', 'panel'] title_icon: undefined,
], title_url: undefined,
possible_main_link_list = [ left_button_title: undefined,
// ['menu_url', 'Menu', 'bars'], left_button_icon: undefined,
['front_url', 'Front', 'arrow-up'], left_button_name: undefined,
['selection_url', 'Previous', 'arrow-up'], right_link_title: undefined,
['cancel_url', 'Cancel', 'times'], right_link_icon: undefined,
['back_url', 'Back', 'times'] right_link_url: undefined,
], right_link_class: undefined,
possible_right_link_list = [ right_button_title: undefined,
['edit_url', 'Editable', 'pencil'], right_button_icon: undefined,
['view_url', 'Viewable', 'eye'], right_button_name: undefined
['right_url', 'New', 'plus'] },
],
possible_right_button_list = [
['save_action', 'Save', 'check', 'submit'],
['submit_action', 'Proceed', 'check', 'submit'],
['add_action', 'Add', 'check', 'submit'],
['filter_action', 'Filter', 'filter', 'submit']
],
possible_sub_header_list = [
['tab_url', 'Views', 'eye'],
['jump_url', 'Jump', 'plane'],
['delete_url', 'Delete', 'times'],
['export_url', 'Export', 'share-square-o'],
['actions_url', 'Actions', 'cogs'],
['cut_url', 'Cut', 'scissors'],
['add_url', 'Add', 'plus'],
['previous_url', 'Previous', 'carat-l'],
['next_url', 'Next', 'carat-r']
],
i,
klass, klass,
count = 0,
//left_link = {
// title: "Menu",
// icon: "bars",
// url: "#leftpanel",
// class: "ui-disabled"
// },
left_link,
left_button,
right_link,
right_button,
default_right_text,
default_right_icon = "",
title_link = {},
sub_header_list = [], sub_header_list = [],
alphabet = "abcdefghijklmnopqrstuvwxyz", i;
promise_list = [];
gadget.stats.options = options; // Main title
// Handle main title
if (options.hasOwnProperty("page_title")) { if (options.hasOwnProperty("page_title")) {
title_link.title = options.page_title; state.title_text = options.page_title;
// Updating globally the page title. Does not follow RenderJS philosophy, but, it is enough for now
document.title = title_link.title;
} }
// Handle main link
for (i = 0; i < possible_main_link_list.length; i += 1) { for (i = 0; i < possible_main_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_main_link_list[i][0])) { if (options.hasOwnProperty(possible_main_link_list[i][0])) {
title_link.icon = possible_main_link_list[i][2]; state.title_icon = possible_main_link_list[i][2];
title_link.url = options[possible_main_link_list[i][0]]; state.title_url = options[possible_main_link_list[i][0]];
} }
} }
if (title_link.hasOwnProperty("url")) {
promise_list.push(gadget.translateHtml(header_title_link_template(title_link)));
} else {
promise_list.push(gadget.translateHtml(header_title_template(title_link)));
}
// Handle left link // Left button
for (i = 0; i < possible_left_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_link_list[i][0])) {
klass = "";
if (!options[possible_left_link_list[i][0]]) {
klass = "ui-disabled";
}
left_link = {
title: possible_left_link_list[i][1],
icon: possible_left_link_list[i][2],
url: options[possible_left_link_list[i][0]],
class: klass
};
}
}
for (i = 0; i < possible_left_button_list.length; i += 1) { for (i = 0; i < possible_left_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_button_list[i][0])) { if (options.hasOwnProperty(possible_left_button_list[i][0])) {
left_button = { state.left_button_title = possible_left_button_list[i][1];
title: possible_left_button_list[i][1], state.left_button_icon = possible_left_button_list[i][2];
icon: possible_left_button_list[i][2], state.left_button_name = possible_left_button_list[i][3];
name: possible_left_button_list[i][3]
};
} }
} }
if (left_link !== undefined) {
promise_list.push(gadget.translateHtml(header_link_template(left_link)));
} else if (left_button !== undefined) {
promise_list.push(gadget.translateHtml(header_button_template(left_button)));
} else {
promise_list.push("");
}
// Handle right link // Handle right link
if (gadget.stats.error) {
default_right_icon = "exclamation";
} else if (!gadget.stats.loaded) {
default_right_icon = "spinner";
// Show default loading information
right_link = {
title: "Loading",
icon: default_right_icon,
url: "",
class: "ui-disabled ui-icon-spin"
};
} else if (!gadget.stats.submitted) {
default_right_icon = "spinner";
} else if (gadget.stats.modified) {
default_right_text = "Save";
default_right_icon = "warning";
}
for (i = 0; i < possible_right_link_list.length; i += 1) { for (i = 0; i < possible_right_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_link_list[i][0])) { if (options.hasOwnProperty(possible_right_link_list[i][0])) {
klass = ""; klass = "";
if (!options[possible_right_link_list[i][0]]) { if (!options[possible_right_link_list[i][0]]) {
klass = "ui-disabled"; klass = "ui-disabled";
} }
right_link = { state.right_link_title = possible_right_link_list[i][1];
title: possible_right_link_list[i][1], state.right_link_icon = possible_right_link_list[i][2];
icon: default_right_icon || possible_right_link_list[i][2], state.right_link_url = options[possible_right_link_list[i][0]];
url: options[possible_right_link_list[i][0]], state.right_link_class = klass;
class: klass
};
} }
} }
for (i = 0; i < possible_right_button_list.length; i += 1) { for (i = 0; i < possible_right_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_button_list[i][0])) { if (options.hasOwnProperty(possible_right_button_list[i][0])) {
right_button = { state.right_button_title = possible_right_button_list[i][1];
title: default_right_text || possible_right_button_list[i][1], state.right_button_icon = possible_right_button_list[i][2];
icon: default_right_icon || possible_right_button_list[i][2], state.right_button_name = possible_right_button_list[i][3];
name: possible_right_button_list[i][3]
};
if (gadget.stats.error) {
right_button.class = "ui-disabled";
}
} }
} }
if (right_button !== undefined) {
if (right_button.icon === 'spinner') {
right_button.class = "ui-disabled ui-icon-spin";
}
promise_list.push(gadget.translateHtml(header_button_template(right_button)));
} else if (right_link !== undefined) {
if (right_link.icon === 'spinner') {
right_link.class = "ui-disabled ui-icon-spin";
}
promise_list.push(gadget.translateHtml(header_link_template(right_link)));
} else {
promise_list.push("");
}
// Handle sub header // Sub header
for (i = 0; i < possible_sub_header_list.length; i += 1) { for (i = 0; i < possible_sub_header_list.length; i += 1) {
if (options.hasOwnProperty(possible_sub_header_list[i][0])) { if (options.hasOwnProperty(possible_sub_header_list[i][0])) {
klass = ""; klass = "";
...@@ -310,63 +206,160 @@ ...@@ -310,63 +206,160 @@
title: possible_sub_header_list[i][1], title: possible_sub_header_list[i][1],
icon: possible_sub_header_list[i][2], icon: possible_sub_header_list[i][2],
url: options[possible_sub_header_list[i][0]], url: options[possible_sub_header_list[i][0]],
class: klass, class: klass
block: alphabet.charAt(count)
}); });
count += 1;
} }
} }
state.sub_header_list = sub_header_list;
return this.changeState(state);
})
.onStateChange(function (modification_dict) {
var gadget = this,
right_link,
right_button,
default_right_icon = "",
title_link,
promise_list = [];
// Main title
if (modification_dict.hasOwnProperty('title_text') ||
modification_dict.hasOwnProperty('title_icon') ||
modification_dict.hasOwnProperty('title_url')) {
// Updating globally the page title. Does not follow RenderJS philosophy, but, it is enough for now
document.title = gadget.state.title_text;
title_link = {
title: gadget.state.title_text,
icon: gadget.state.title_icon,
url: gadget.state.title_url
};
if (title_link.url === undefined) {
promise_list.push(gadget.translateHtml(header_title_template(title_link)));
} else {
promise_list.push(gadget.translateHtml(header_title_link_template(title_link)));
}
} else {
promise_list.push(null);
}
if (sub_header_list.length !== 0) { // Left button
sub_header_list[0].class += " ui-first-child"; if (modification_dict.hasOwnProperty('left_button_title') ||
sub_header_list[sub_header_list.length - 1].class += " ui-last-child"; modification_dict.hasOwnProperty('left_button_icon') ||
modification_dict.hasOwnProperty('left_button_name')) {
if (gadget.state.left_button_title === undefined) {
promise_list.push("");
} else {
promise_list.push(gadget.translateHtml(header_button_template({
title: gadget.state.left_button_title,
icon: gadget.state.left_button_icon,
name: gadget.state.left_button_name
})));
}
} else {
promise_list.push(null);
} }
// gadget.props.sub_header_ul.textContent = JSON.stringify(options);
//gadget.props.sub_header_ul.innerHTML = sub_header_template({
// sub_header_list: sub_header_list
//});
promise_list.push(gadget.translateHtml(sub_header_template({ // Handle right link
sub_header_list: sub_header_list if (modification_dict.hasOwnProperty('error') ||
}))); modification_dict.hasOwnProperty('loaded') ||
modification_dict.hasOwnProperty('modified') ||
modification_dict.hasOwnProperty('right_link_title') ||
modification_dict.hasOwnProperty('right_link_icon') ||
modification_dict.hasOwnProperty('right_link_url') ||
modification_dict.hasOwnProperty('right_link_class') ||
modification_dict.hasOwnProperty('right_button_title') ||
modification_dict.hasOwnProperty('right_button_icon') ||
modification_dict.hasOwnProperty('submitted')) {
if (gadget.state.error) {
default_right_icon = "exclamation";
} else if (!gadget.state.loaded) {
default_right_icon = "spinner";
// Show default loading information
right_link = {
title: "Loading",
icon: default_right_icon,
url: "",
class: "ui-disabled ui-icon-spin"
};
} else if (!gadget.state.submitted) {
default_right_icon = "spinner";
} else if (gadget.state.modified) {
default_right_icon = "warning";
}
if (gadget.state.right_link_title !== undefined) {
right_link = {
title: gadget.state.right_link_title,
icon: default_right_icon || gadget.state.right_link_icon,
url: gadget.state.right_link_url,
class: gadget.state.right_link_class
};
}
if (gadget.state.right_button_title !== undefined) {
right_button = {
title: gadget.state.right_button_title,
icon: default_right_icon || gadget.state.right_button_icon,
name: gadget.state.right_button_name
};
if (gadget.state.error) {
right_button.class = "ui-disabled";
}
}
if (right_button !== undefined) {
if (right_button.icon === 'spinner') {
right_button.class = "ui-disabled ui-icon-spin";
}
promise_list.push(gadget.translateHtml(header_button_template(right_button)));
} else if (right_link !== undefined) {
if (right_link.icon === 'spinner') {
right_link.class = "ui-disabled ui-icon-spin";
}
promise_list.push(gadget.translateHtml(header_link_template(right_link)));
} else {
promise_list.push("");
}
} else {
promise_list.push(null);
}
// Handle sub header
if (modification_dict.hasOwnProperty('sub_header_list')) {
promise_list.push(gadget.translateHtml(sub_header_template({
sub_header_list: gadget.state.sub_header_list
})));
} else {
promise_list.push(null);
}
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return RSVP.all(promise_list); return RSVP.all(promise_list);
}) })
.push(function (my_translated_html_list) { .push(function (result_list) {
gadget.props.title_element.innerHTML = my_translated_html_list[0]; var j;
gadget.props.left_link.innerHTML = my_translated_html_list[1]; for (j = 0; j < result_list.length; j += 1) {
gadget.props.right_link.innerHTML = my_translated_html_list[2]; if (result_list[j] !== null) {
gadget.props.sub_header_ul.innerHTML = my_translated_html_list[3]; gadget.props.element_list[j].innerHTML = result_list[j];
}
}
}); });
}) })
////////////////////////////////////////////// //////////////////////////////////////////////
// handle button click // handle button submit
////////////////////////////////////////////// //////////////////////////////////////////////
.declareService(function () { .onEvent('submit', function (evt) {
var form_gadget = this; var name = evt.target[0].getAttribute("name");
if (name === "panel") {
function formSubmit(evt) { return this.triggerPanel();
var button = evt.target[0],
name = button.getAttribute("name");
if (name === "panel") {
return form_gadget.triggerPanel();
}
if (name === "submit") {
return form_gadget.triggerSubmit();
}
throw new Error("Unsupported button " + name);
} }
if (name === "submit") {
// Listen to form submit return this.triggerSubmit();
return loopEventListener( }
form_gadget.props.element, throw new Error("Unsupported button " + name);
'submit',
false,
formSubmit
);
}); });
}(window, rJS, Handlebars, document, loopEventListener, RSVP)); }(window, rJS, Handlebars, document, RSVP));
\ No newline at end of file \ No newline at end of file
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>953.40680.32628.45004</string> </value> <value> <string>955.23807.51206.64836</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1472723487.54</float> <float>1479483026.71</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
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