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

[erp5_web_renderjs_ui] Header: reduce number of DOM modifications

parent 636ecab1
...@@ -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,135 +8,24 @@ ...@@ -8,135 +8,24 @@
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// 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
header_title_link_source = gadget_klass.__template_element
.getElementById("header-title-link-template") .getElementById("header-title-link-template")
.innerHTML, .innerHTML),
header_title_link_template = Handlebars.compile(header_title_link_source), sub_header_template = Handlebars.compile(template_element
sub_header_source = gadget_klass.__template_element
.getElementById("sub-header-template") .getElementById("sub-header-template")
.innerHTML, .innerHTML),
sub_header_template = Handlebars.compile(sub_header_source), header_button_template = Handlebars.compile(template_element
header_button_source = gadget_klass.__template_element
.getElementById("header-button-template") .getElementById("header-button-template")
.innerHTML, .innerHTML),
header_button_template = Handlebars.compile(header_button_source), header_link_template = Handlebars.compile(template_element
header_link_source = gadget_klass.__template_element
.getElementById("header-link-template") .getElementById("header-link-template")
.innerHTML, .innerHTML),
header_link_template = Handlebars.compile(header_link_source);
gadget_klass
/////////////////////////////////////////////////////////////////
// ready
/////////////////////////////////////////////////////////////////
// Init local properties
.ready(function (g) {
g.props = {};
g.stats = {
loaded: false,
modified: false,
submitted: true,
error: false,
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
//////////////////////////////////////////////
.declareAcquiredMethod("translateHtml", "translateHtml")
.declareAcquiredMethod("triggerSubmit", "triggerSubmit")
.declareAcquiredMethod("triggerPanel", "triggerPanel")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.declareMethod('notifyError', function () {
this.stats.loaded = true;
this.stats.submitted = 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 () {
if (this.stats.loaded) {
this.stats.loaded = false;
return this.render(this.stats.options);
}
})
.declareMethod('notifyLoaded', function () {
if (!this.stats.loaded) {
this.stats.loaded = true;
return this.render(this.stats.options);
}
})
.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 () {
if (this.stats.submitted) {
this.stats.submitted = false;
return this.render(this.stats.options);
}
})
.declareMethod('notifySubmitted', function () {
var render_needed = false;
if (!this.stats.submitted) {
render_needed = true;
this.stats.submitted = true;
}
if (this.stats.modified) {
render_needed = true;
// Change modify here, to allow user to redo some modification and being correctly notified
this.stats.modified = false;
}
if (render_needed) {
return this.render(this.stats.options);
}
})
.declareMethod('render', function (options) {
var gadget = this,
possible_left_link_list = [],
possible_left_button_list = [ possible_left_button_list = [
['panel_action', 'Menu', 'bars', 'panel'] ['panel_action', 'Menu', 'bars', 'panel']
], ],
...@@ -168,83 +57,224 @@ ...@@ -168,83 +57,224 @@
['add_url', 'Add', 'plus'], ['add_url', 'Add', 'plus'],
['previous_url', 'Previous', 'carat-l'], ['previous_url', 'Previous', 'carat-l'],
['next_url', 'Next', 'carat-r'] ['next_url', 'Next', 'carat-r']
], ];
i,
gadget_klass
.setState({
loaded: false,
modified: false,
submitted: true,
error: false,
title_text: '',
title_icon: undefined,
title_url: undefined
})
/////////////////////////////////////////////////////////////////
// ready
/////////////////////////////////////////////////////////////////
// Init local properties
.ready(function () {
this.props = {
element_list: [
this.element.querySelector("h1"),
this.element.querySelector(".ui-btn-left > div"),
this.element.querySelector(".ui-btn-right > div"),
this.element.querySelector(".ui-subheader").querySelector("ul")
]
};
})
//////////////////////////////////////////////
// acquired methods
//////////////////////////////////////////////
.declareAcquiredMethod("translateHtml", "translateHtml")
.declareAcquiredMethod("triggerSubmit", "triggerSubmit")
.declareAcquiredMethod("triggerPanel", "triggerPanel")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.declareMethod('notifyLoaded', function () {
return this.changeState({
loaded: true
});
})
.declareMethod('notifyLoading', function () {
return this.changeState({
loaded: false
});
})
.declareMethod('notifySubmitted', function () {
return this.changeState({
submitted: true,
// Change modify here, to allow user to redo some modification and being correctly notified
modified: false
});
})
.declareMethod('notifySubmitting', function () {
return this.changeState({
submitted: false
});
})
.declareMethod('notifyError', function () {
return this.changeState({
loaded: true,
submitted: true,
error: true
});
})
.declareMethod('notifyChange', function () {
return this.changeState({
modified: true
});
})
/*
.declareMethod('notifyUpdate', function () {
return this.render(this.stats.options);
})
*/
.declareMethod('render', function (options) {
var state = {
error: false,
title_text: '',
title_icon: undefined,
title_url: undefined,
left_button_title: undefined,
left_button_icon: undefined,
left_button_name: undefined,
right_link_title: undefined,
right_link_icon: undefined,
right_link_url: undefined,
right_link_class: undefined,
right_button_title: undefined,
right_button_icon: undefined,
right_button_name: undefined
},
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))); // Left button
} else { for (i = 0; i < possible_left_button_list.length; i += 1) {
promise_list.push(gadget.translateHtml(header_title_template(title_link))); if (options.hasOwnProperty(possible_left_button_list[i][0])) {
state.left_button_title = possible_left_button_list[i][1];
state.left_button_icon = possible_left_button_list[i][2];
state.left_button_name = possible_left_button_list[i][3];
}
}
// Handle right link
for (i = 0; i < possible_right_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_link_list[i][0])) {
klass = "";
if (!options[possible_right_link_list[i][0]]) {
klass = "ui-disabled";
}
state.right_link_title = possible_right_link_list[i][1];
state.right_link_icon = possible_right_link_list[i][2];
state.right_link_url = options[possible_right_link_list[i][0]];
state.right_link_class = klass;
}
}
for (i = 0; i < possible_right_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_button_list[i][0])) {
state.right_button_title = possible_right_button_list[i][1];
state.right_button_icon = possible_right_button_list[i][2];
state.right_button_name = possible_right_button_list[i][3];
}
} }
// Handle left link // Sub header
for (i = 0; i < possible_left_link_list.length; i += 1) { for (i = 0; i < possible_sub_header_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_link_list[i][0])) { if (options.hasOwnProperty(possible_sub_header_list[i][0])) {
klass = ""; klass = "";
if (!options[possible_left_link_list[i][0]]) { if (!options[possible_sub_header_list[i][0]]) {
klass = "ui-disabled"; klass = "ui-disabled";
} }
left_link = { sub_header_list.push({
title: possible_left_link_list[i][1], title: possible_sub_header_list[i][1],
icon: possible_left_link_list[i][2], icon: possible_sub_header_list[i][2],
url: options[possible_left_link_list[i][0]], url: options[possible_sub_header_list[i][0]],
class: klass class: klass
}; });
} }
} }
for (i = 0; i < possible_left_button_list.length; i += 1) { state.sub_header_list = sub_header_list;
if (options.hasOwnProperty(possible_left_button_list[i][0])) {
left_button = { return this.changeState(state);
title: possible_left_button_list[i][1], })
icon: possible_left_button_list[i][2],
name: possible_left_button_list[i][3] .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)));
} }
}
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 { } else {
promise_list.push(null);
}
// Left button
if (modification_dict.hasOwnProperty('left_button_title') ||
modification_dict.hasOwnProperty('left_button_icon') ||
modification_dict.hasOwnProperty('left_button_name')) {
if (gadget.state.left_button_title === undefined) {
promise_list.push(""); 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);
} }
// Handle right link // Handle right link
if (gadget.stats.error) { 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"; default_right_icon = "exclamation";
} else if (!gadget.stats.loaded) { } else if (!gadget.state.loaded) {
default_right_icon = "spinner"; default_right_icon = "spinner";
// Show default loading information // Show default loading information
right_link = { right_link = {
...@@ -253,38 +283,31 @@ ...@@ -253,38 +283,31 @@
url: "", url: "",
class: "ui-disabled ui-icon-spin" class: "ui-disabled ui-icon-spin"
}; };
} else if (!gadget.stats.submitted) { } else if (!gadget.state.submitted) {
default_right_icon = "spinner"; default_right_icon = "spinner";
} else if (gadget.stats.modified) { } else if (gadget.state.modified) {
default_right_text = "Save";
default_right_icon = "warning"; default_right_icon = "warning";
} }
for (i = 0; i < possible_right_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_link_list[i][0])) { if (gadget.state.right_link_title !== undefined) {
klass = "";
if (!options[possible_right_link_list[i][0]]) {
klass = "ui-disabled";
}
right_link = { right_link = {
title: possible_right_link_list[i][1], title: gadget.state.right_link_title,
icon: default_right_icon || possible_right_link_list[i][2], icon: default_right_icon || gadget.state.right_link_icon,
url: options[possible_right_link_list[i][0]], url: gadget.state.right_link_url,
class: klass class: gadget.state.right_link_class
}; };
} }
} if (gadget.state.right_button_title !== undefined) {
for (i = 0; i < possible_right_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_button_list[i][0])) {
right_button = { right_button = {
title: default_right_text || possible_right_button_list[i][1], title: gadget.state.right_button_title,
icon: default_right_icon || possible_right_button_list[i][2], icon: default_right_icon || gadget.state.right_button_icon,
name: possible_right_button_list[i][3] name: gadget.state.right_button_name
}; };
if (gadget.stats.error) { if (gadget.state.error) {
right_button.class = "ui-disabled"; right_button.class = "ui-disabled";
} }
} }
}
if (right_button !== undefined) { if (right_button !== undefined) {
if (right_button.icon === 'spinner') { if (right_button.icon === 'spinner') {
right_button.class = "ui-disabled ui-icon-spin"; right_button.class = "ui-disabled ui-icon-spin";
...@@ -298,75 +321,45 @@ ...@@ -298,75 +321,45 @@
} else { } else {
promise_list.push(""); promise_list.push("");
} }
} else {
// Handle sub header promise_list.push(null);
for (i = 0; i < possible_sub_header_list.length; i += 1) {
if (options.hasOwnProperty(possible_sub_header_list[i][0])) {
klass = "";
if (!options[possible_sub_header_list[i][0]]) {
klass = "ui-disabled";
}
sub_header_list.push({
title: possible_sub_header_list[i][1],
icon: possible_sub_header_list[i][2],
url: options[possible_sub_header_list[i][0]],
class: klass,
block: alphabet.charAt(count)
});
count += 1;
}
}
if (sub_header_list.length !== 0) {
sub_header_list[0].class += " ui-first-child";
sub_header_list[sub_header_list.length - 1].class += " ui-last-child";
} }
// gadget.props.sub_header_ul.textContent = JSON.stringify(options);
//gadget.props.sub_header_ul.innerHTML = sub_header_template({
// sub_header_list: sub_header_list
//});
// Handle sub header
if (modification_dict.hasOwnProperty('sub_header_list')) {
promise_list.push(gadget.translateHtml(sub_header_template({ promise_list.push(gadget.translateHtml(sub_header_template({
sub_header_list: sub_header_list 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");
function formSubmit(evt) {
var button = evt.target[0],
name = button.getAttribute("name");
if (name === "panel") { if (name === "panel") {
return form_gadget.triggerPanel(); return this.triggerPanel();
} }
if (name === "submit") { if (name === "submit") {
return form_gadget.triggerSubmit(); return this.triggerSubmit();
} }
throw new Error("Unsupported button " + name); throw new Error("Unsupported button " + name);
}
// Listen to form submit
return loopEventListener(
form_gadget.props.element,
'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