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 @@
</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>
</html>
\ No newline at end of file
......@@ -234,7 +234,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>951.35286.47701.22630</string> </value>
<value> <string>955.10496.5559.9130</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -252,7 +252,7 @@
</tuple>
<state>
<tuple>
<float>1466516947.72</float>
<float>1479462688.84</float>
<string>UTC</string>
</tuple>
</state>
......
/*jslint nomen: true, indent: 2, maxerr: 3 */
/*global window, rJS, Handlebars, document, loopEventListener, RSVP */
(function (window, rJS, Handlebars, document, loopEventListener, RSVP) {
/*global window, rJS, Handlebars, document, RSVP */
(function (window, rJS, Handlebars, document, RSVP) {
"use strict";
/////////////////////////////////////////////////////////////////
......@@ -8,135 +8,24 @@
/////////////////////////////////////////////////////////////////
// Precompile the templates while loading the first gadget instance
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")
.innerHTML,
header_title_template = Handlebars.compile(header_title_source),
header_title_link_source = gadget_klass.__template_element
.innerHTML),
header_title_link_template = Handlebars.compile(template_element
.getElementById("header-title-link-template")
.innerHTML,
header_title_link_template = Handlebars.compile(header_title_link_source),
sub_header_source = gadget_klass.__template_element
.innerHTML),
sub_header_template = Handlebars.compile(template_element
.getElementById("sub-header-template")
.innerHTML,
sub_header_template = Handlebars.compile(sub_header_source),
header_button_source = gadget_klass.__template_element
.innerHTML),
header_button_template = Handlebars.compile(template_element
.getElementById("header-button-template")
.innerHTML,
header_button_template = Handlebars.compile(header_button_source),
header_link_source = gadget_klass.__template_element
.innerHTML),
header_link_template = Handlebars.compile(template_element
.getElementById("header-link-template")
.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: {}
};
})
.innerHTML),
// 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 = [
['panel_action', 'Menu', 'bars', 'panel']
],
......@@ -168,83 +57,224 @@
['add_url', 'Add', 'plus'],
['previous_url', 'Previous', 'carat-l'],
['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,
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 = [],
alphabet = "abcdefghijklmnopqrstuvwxyz",
promise_list = [];
i;
gadget.stats.options = options;
// Handle main title
// Main title
if (options.hasOwnProperty("page_title")) {
title_link.title = options.page_title;
// Updating globally the page title. Does not follow RenderJS philosophy, but, it is enough for now
document.title = title_link.title;
state.title_text = options.page_title;
}
// Handle main link
for (i = 0; i < possible_main_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_main_link_list[i][0])) {
title_link.icon = possible_main_link_list[i][2];
title_link.url = options[possible_main_link_list[i][0]];
state.title_icon = possible_main_link_list[i][2];
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)));
// Left button
for (i = 0; i < possible_left_button_list.length; i += 1) {
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
for (i = 0; i < possible_left_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_link_list[i][0])) {
// Sub header
for (i = 0; i < possible_sub_header_list.length; i += 1) {
if (options.hasOwnProperty(possible_sub_header_list[i][0])) {
klass = "";
if (!options[possible_left_link_list[i][0]]) {
if (!options[possible_sub_header_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]],
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
};
});
}
}
for (i = 0; i < possible_left_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_button_list[i][0])) {
left_button = {
title: possible_left_button_list[i][1],
icon: possible_left_button_list[i][2],
name: possible_left_button_list[i][3]
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)));
}
}
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(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("");
} 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
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";
} else if (!gadget.stats.loaded) {
} else if (!gadget.state.loaded) {
default_right_icon = "spinner";
// Show default loading information
right_link = {
......@@ -253,38 +283,31 @@
url: "",
class: "ui-disabled ui-icon-spin"
};
} else if (!gadget.stats.submitted) {
} else if (!gadget.state.submitted) {
default_right_icon = "spinner";
} else if (gadget.stats.modified) {
default_right_text = "Save";
} else if (gadget.state.modified) {
default_right_icon = "warning";
}
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";
}
if (gadget.state.right_link_title !== undefined) {
right_link = {
title: possible_right_link_list[i][1],
icon: default_right_icon || possible_right_link_list[i][2],
url: options[possible_right_link_list[i][0]],
class: klass
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
};
}
}
for (i = 0; i < possible_right_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_button_list[i][0])) {
if (gadget.state.right_button_title !== undefined) {
right_button = {
title: default_right_text || possible_right_button_list[i][1],
icon: default_right_icon || possible_right_button_list[i][2],
name: possible_right_button_list[i][3]
title: gadget.state.right_button_title,
icon: default_right_icon || gadget.state.right_button_icon,
name: gadget.state.right_button_name
};
if (gadget.stats.error) {
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";
......@@ -298,75 +321,45 @@
} else {
promise_list.push("");
}
// Handle sub header
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";
} 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
//});
// Handle sub header
if (modification_dict.hasOwnProperty('sub_header_list')) {
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()
.push(function () {
return RSVP.all(promise_list);
})
.push(function (my_translated_html_list) {
gadget.props.title_element.innerHTML = my_translated_html_list[0];
gadget.props.left_link.innerHTML = my_translated_html_list[1];
gadget.props.right_link.innerHTML = my_translated_html_list[2];
gadget.props.sub_header_ul.innerHTML = my_translated_html_list[3];
.push(function (result_list) {
var j;
for (j = 0; j < result_list.length; j += 1) {
if (result_list[j] !== null) {
gadget.props.element_list[j].innerHTML = result_list[j];
}
}
});
})
//////////////////////////////////////////////
// handle button click
// handle button submit
//////////////////////////////////////////////
.declareService(function () {
var form_gadget = this;
function formSubmit(evt) {
var button = evt.target[0],
name = button.getAttribute("name");
.onEvent('submit', function (evt) {
var name = evt.target[0].getAttribute("name");
if (name === "panel") {
return form_gadget.triggerPanel();
return this.triggerPanel();
}
if (name === "submit") {
return form_gadget.triggerSubmit();
return this.triggerSubmit();
}
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));
\ No newline at end of file
}(window, rJS, Handlebars, document, RSVP));
\ No newline at end of file
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>953.40680.32628.45004</string> </value>
<value> <string>955.23807.51206.64836</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1472723487.54</float>
<float>1479483026.71</float>
<string>UTC</string>
</tuple>
</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