Commit 298ee10d authored by Romain Courteaud's avatar Romain Courteaud

[erp5_web_renderjs_ui] Add context links in panel

The links are only visible in desktop display.
Links are only calculated for non module document in form_view/dialog
parent d2f55319
......@@ -42,6 +42,10 @@
};
}
function initPanelOptions(gadget) {
gadget.props.panel_argument_list = {};
}
function route(my_root_gadget, my_scope, my_method, argument_list) {
return RSVP.Queue()
.push(function () {
......@@ -67,6 +71,13 @@
});
}
function updatePanel(gadget) {
return gadget.getDeclaredGadget("panel")
.push(function (panel_gadget) {
return panel_gadget.render(gadget.props.panel_argument_list);
});
}
function increaseLoadingCounter(gadget) {
return new RSVP.Queue()
.push(function () {
......@@ -148,6 +159,10 @@
if (error instanceof Error) {
console.error(error.stack);
}
if (gadget.props === undefined) {
// Gadget has not yet been correctly initialized
throw error;
}
// XXX Improve error rendering
gadget.props.content_element.innerHTML = "<br/><br/><br/><pre></pre>";
gadget.props.content_element.querySelector('pre').textContent =
......@@ -235,13 +250,11 @@
return jio_gadget.createJio(setting.jio_storage_description);
})
.push(function () {
return gadget.getDeclaredGadget('panel');
})
.push(function (panel_gadget) {
return panel_gadget.render();
return panel_gadget.render({});
})
.push(function () {
return gadget.getDeclaredGadget('router');
})
......@@ -407,6 +420,12 @@
});
})
.allowPublicAcquisition("updatePanel", function (param_list) {
var gadget = this;
initPanelOptions(gadget);
gadget.props.panel_argument_list = param_list[0];
})
.allowPublicAcquisition('triggerPanel', function () {
return route(this, "panel", "toggle");
})
......@@ -487,7 +506,10 @@
content_container.appendChild(main_gadget.element);
element.appendChild(content_container);
return updateHeader(gadget);
return RSVP.all([
updateHeader(gadget),
updatePanel(gadget)
]);
// XXX Drop notification
// return header_gadget.notifyLoaded();
}
......@@ -500,7 +522,10 @@
return page_gadget.render(gadget.state.options);
})
.push(function () {
return updateHeader(gadget);
return RSVP.all([
updateHeader(gadget),
updatePanel(gadget)
]);
});
})
// Render the page
......@@ -512,6 +537,7 @@
// By default, init the header options to be empty
// (ERP5 title by default + sidebar)
initHeaderOptions(gadget);
initPanelOptions(gadget);
return new RSVP.Queue()
.push(function () {
return increaseLoadingCounter(gadget);
......
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>956.5832.50053.43878</string> </value>
<value> <string>957.35152.14703.9045</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1482250162.82</float>
<float>1487941504.18</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -488,25 +488,62 @@ div[data-gadget-scope='panel'] img {
text-align: left;
height: 100%;
}
div[data-gadget-scope='panel'] ul {
div[data-gadget-scope='panel'] ul:first-child {
margin-top: 30pt;
}
div[data-gadget-scope='panel'] ul li a {
color: #FFFFFF;
display: block;
padding: 3pt;
padding-left: 12pt;
display: block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
div[data-gadget-scope='panel'] ul li a:hover,
div[data-gadget-scope='panel'] ul li a:active {
background-color: #2b2b2b;
}
div[data-gadget-scope='panel'] ul li a::before {
width: 24pt;
}
div[data-gadget-scope='panel'] ul li a:hover,
div[data-gadget-scope='panel'] ul li a:active {
div[data-gadget-scope='panel'] dl {
background-color: #777777;
color: #1F1F1F;
transform-origin: 50% 0;
transform: scaleY(0);
transition: transform 0.2s ease-out;
}
div[data-gadget-scope='panel'] dl:not(:empty) {
transform: scaleY(1);
}
div[data-gadget-scope='panel'] dl dt {
padding: 3pt;
padding-left: 12pt;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
div[data-gadget-scope='panel'] dl dt::before {
width: 24pt;
}
div[data-gadget-scope='panel'] dl dd a {
color: #FFFFFF;
display: block;
padding: 3pt;
padding-left: 12pt;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
padding-left: 36pt;
}
div[data-gadget-scope='panel'] dl dd a:hover,
div[data-gadget-scope='panel'] dl dd a:active {
background-color: #2b2b2b;
}
div[data-gadget-scope='panel'] dl dd a::before {
width: 24pt;
}
/**********************************************
* Gadget: editor panel
**********************************************/
......
......@@ -242,7 +242,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>956.58713.6703.47906</string> </value>
<value> <string>957.39714.21193.35498</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -260,7 +260,7 @@
</tuple>
<state>
<tuple>
<float>1485423923.88</float>
<float>1488215480.92</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -35,9 +35,25 @@
<li><a href="{{preference_href}}" class="ui-btn ui-btn-icon-left ui-icon-gear" data-i18n="Preferences">Preferences</a></li>
<li class="ui-last-child"><a href="{{logout_href}}" class="ui-btn ui-btn-icon-left ui-icon-power-off" data-i18n="Logout" accesskey="o">Logout</a></li>
</ul>
<dl></dl>
</div>
</script>
<script id="panel-template-body-desktop" type="text/x-handlebars-template">
<dt class="ui-content-title ui-body-c ui-btn ui-btn-icon-left ui-icon-eye" data-i18n="Views">Views</dt>
{{#each view_list}}
<dd data-role="listview" data-theme="c" data-inset="true" class="document-listview">
<a data-i18n="{{title}}" class="ui-body-inherit" href="{{href}}">{{title}}</a>
</dd>
{{/each}}
<dt class="ui-content-title ui-body-c ui-btn ui-btn-icon-left ui-icon-cogs" data-i18n="Decisions">Decisions</dt>
{{#each workflow_list}}
<dd data-role="listview" data-theme="c" data-inset="true" class="document-listview">
<a data-i18n="{{title}}" class="ui-body-inherit" href="{{href}}">{{title}}</a>
</dd>
{{/each}}
</script>
<!-- custom script -->
<script src="gadget_erp5_panel.js" type="text/javascript"></script>
......
......@@ -234,7 +234,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>957.20614.31452.4437</string> </value>
<value> <string>957.39718.21180.26828</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -252,7 +252,7 @@
</tuple>
<state>
<tuple>
<float>1487069250.39</float>
<float>1488215553.05</float>
<string>UTC</string>
</tuple>
</state>
......
/*jslint nomen: true, indent: 2, maxerr: 3 */
/*global window, rJS, Handlebars, RSVP, Node */
(function (window, rJS, Handlebars, RSVP, Node) {
/*global window, document, rJS, Handlebars, RSVP, Node, loopEventListener */
(function (window, document, rJS, Handlebars, RSVP, Node, loopEventListener) {
"use strict";
/////////////////////////////////////////////////////////////////
......@@ -14,11 +14,15 @@
.innerHTML),
panel_template_body = Handlebars.compile(template_element
.getElementById("panel-template-body")
.innerHTML);
.innerHTML),
panel_template_body_desktop = Handlebars.compile(template_element
.getElementById("panel-template-body-desktop")
.innerHTML);
gadget_klass
.setState({
visible: false
visible: false,
desktop: false
})
//////////////////////////////////////////////
// acquired method
......@@ -40,48 +44,151 @@
});
})
.declareMethod('render', function () {
var g = this;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
g.getUrlFor({command: 'display', options: {page: "front"}}),
g.getUrlFor({command: 'display', options: {page: "history"}}),
g.getUrlFor({command: 'display', options: {page: "preference"}}),
g.getUrlFor({command: 'display', options: {page: "logout"}}),
g.getUrlFor({command: 'display', options: {page: "search"}}),
g.getUrlFor({command: 'display', options: {page: "worklist"}})
]);
})
.push(function (all_result) {
// XXX: Customize panel header!
return g.translateHtml(
panel_template_header() +
panel_template_body({
"module_href": all_result[0],
"history_href": all_result[1],
"preference_href": all_result[2],
"logout_href": all_result[3],
"search_href": all_result[4],
"worklist_href": all_result[5]
})
);
})
.push(function (my_translated_or_plain_html) {
g.element.querySelector("div").innerHTML = my_translated_or_plain_html;
});
.declareMethod('render', function (options) {
var erp5_document = options.erp5_document,
workflow_list,
view_list;
if (erp5_document !== undefined) {
workflow_list = erp5_document._links.action_workflow || [];
view_list = erp5_document._links.action_object_view || [];
if (workflow_list.constructor !== Array) {
workflow_list = [workflow_list];
}
if (view_list.constructor !== Array) {
view_list = [view_list];
}
// Prevent has much as possible to modify the DOM panel
// stateChange prefer to compare strings
workflow_list = JSON.stringify(workflow_list);
view_list = JSON.stringify(view_list);
}
return this.changeState({
workflow_list: workflow_list,
view_list: view_list,
global: true,
editable: options.editable
});
})
.onStateChange(function () {
if (this.state.visible) {
if (!this.element.classList.contains('visible')) {
this.element.classList.toggle('visible');
.onStateChange(function (modification_dict) {
var context = this,
gadget = this,
queue = new RSVP.Queue();
if (modification_dict.hasOwnProperty("visible")) {
if (this.state.visible) {
if (!this.element.classList.contains('visible')) {
this.element.classList.toggle('visible');
}
} else {
if (this.element.classList.contains('visible')) {
this.element.classList.remove('visible');
}
}
} else {
if (this.element.classList.contains('visible')) {
this.element.classList.remove('visible');
}
if (modification_dict.hasOwnProperty("global")) {
queue
.push(function () {
return RSVP.all([
context.getUrlFor({command: 'display', options: {page: "front"}}),
context.getUrlFor({command: 'display', options: {page: "history"}}),
context.getUrlFor({command: 'display', options: {page: "preference"}}),
context.getUrlFor({command: 'display', options: {page: "logout"}}),
context.getUrlFor({command: 'display', options: {page: "search"}}),
context.getUrlFor({command: 'display', options: {page: "worklist"}})
]);
})
.push(function (result_list) {
// XXX: Customize panel header!
return context.translateHtml(
panel_template_header() +
panel_template_body({
"module_href": result_list[0],
"history_href": result_list[1],
"preference_href": result_list[2],
"logout_href": result_list[3],
"search_href": result_list[4],
"worklist_href": result_list[5]
})
);
})
.push(function (my_translated_or_plain_html) {
context.element.querySelector("div").innerHTML = my_translated_or_plain_html;
return context.listenResize();
});
}
if ((this.state.global === true) &&
(modification_dict.hasOwnProperty("desktop") ||
modification_dict.hasOwnProperty("editable") ||
modification_dict.hasOwnProperty("workflow_list") ||
modification_dict.hasOwnProperty("view_list"))) {
if (!(this.state.desktop && (this.state.view_list !== undefined))) {
queue
.push(function () {
gadget.element.querySelector("dl").textContent = '';
});
} else {
queue
.push(function () {
var i = 0,
promise_list = [],
workflow_list = JSON.parse(gadget.state.workflow_list),
view_list = JSON.parse(gadget.state.view_list);
for (i = 0; i < workflow_list.length; i += 1) {
promise_list.push(
gadget.getUrlFor({
command: 'change',
options: {
view: workflow_list[i].href,
page: undefined
}
})
);
}
for (i = 0; i < view_list.length; i += 1) {
promise_list.push(
gadget.getUrlFor({
command: 'change',
options: {
view: view_list[i].href,
page: undefined
}
})
);
}
return RSVP.all(promise_list);
})
.push(function (result_list) {
var i,
result_workflow_list = [],
result_view_list = [],
workflow_list = JSON.parse(gadget.state.workflow_list),
view_list = JSON.parse(gadget.state.view_list);
for (i = 0; i < workflow_list.length; i += 1) {
result_workflow_list.push({
title: workflow_list[i].title,
href: result_list[i]
});
}
for (i = 0; i < view_list.length; i += 1) {
result_view_list.push({
title: view_list[i].title,
href: result_list[i + workflow_list.length]
});
}
gadget.element.querySelector("dl").innerHTML = panel_template_body_desktop({
workflow_list: result_workflow_list,
view_list: result_view_list
});
});
}
}
return queue;
})
/////////////////////////////////////////////////////////////////
......@@ -92,6 +199,30 @@
(evt.target.tagName === 'BUTTON')) {
return this.toggle();
}
}, false, false);
}, false, false)
.declareJob('listenResize', function () {
// resize should be only trigger after the render method
// as displaying the panel rely on external gadget (for translation for example)
var result,
event,
context = this;
function extractSizeAndDispatch() {
if (window.matchMedia("(min-width: 90em)").matches) {
return context.changeState({
desktop: true
});
}
return context.changeState({
desktop: false
});
}
result = loopEventListener(window, 'resize', false,
extractSizeAndDispatch);
event = document.createEvent("Event");
event.initEvent('resize', true, true);
window.dispatchEvent(event);
return result;
});
}(window, rJS, Handlebars, RSVP, Node));
}(window, document, rJS, Handlebars, RSVP, Node, loopEventListener));
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>955.32296.8972.20241</string> </value>
<value> <string>957.41111.56434.58897</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1479992698.26</float>
<float>1488299408.27</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -25,6 +25,7 @@
.declareAcquiredMethod("jio_getAttachment", "jio_getAttachment")
.declareAcquiredMethod("redirect", "redirect")
.declareAcquiredMethod("jio_allDocs", "jio_allDocs")
.declareAcquiredMethod("updatePanel", "updatePanel")
/////////////////////////////////////////////////////////////////
// declared methods
......@@ -131,6 +132,17 @@
element.appendChild(fragment);
});
}
})
.push(function () {
var jio_key = gadget.state.options.jio_key;
/*jslint regexp: true*/
if (/^[^\/]+_module\/[^\/]+$/.test(jio_key)) {
/*jslint regexp: false*/
return gadget.updatePanel({
erp5_document: JSON.parse(gadget.state.erp5_document),
editable: gadget.state.options.editable
});
}
});
})
.allowPublicAcquisition("displayFormulatorValidationError", function (param_list) {
......
......@@ -230,7 +230,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>954.44527.39200.57275</string> </value>
<value> <string>957.39730.12250.6587</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -248,7 +248,7 @@
</tuple>
<state>
<tuple>
<float>1476793905.11</float>
<float>1488216811.75</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -582,28 +582,66 @@ div[data-gadget-scope='panel'] {
}
.alignwithicon() {
padding: @half-margin-size;
padding-left: @double-margin-size;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
&::before {
// Use width instead of padding-right
// To keep text aligned
width: @quadruple-margin-size;
}
}
.alignwithouticon() {
.alignwithicon();
padding-left: @double-margin-size + @quadruple-margin-size;
}
.linkpanel() {
color: @white;
display: block;
&:hover, &:active {
background-color: darken(@panelbackgroundcolor, 10%);
}
}
ul {
margin-top: @headerheight;
&:first-child {
margin-top: @headerheight;
}
li {
a {
color: @white;
padding: @half-margin-size;
padding-left: @double-margin-size;
display: block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
.linkpanel();
.alignwithicon();
}
}
}
&::before {
// Use width instead of padding-right
// To keep text aligned
width: @quadruple-margin-size;
}
&:hover, &:active {
background-color: darken(@panelbackgroundcolor, 10%);
dl {
background-color: @grey;
color: @black;
// Animate when content is added
transform-origin: 50% 0;
transform: scaleY(0);
&:not(:empty) {
transform: scaleY(1);
}
transition: transform @transition-timing;
dt {
.alignwithicon();
}
dd {
a {
.linkpanel();
.alignwithouticon();
}
}
}
}
......
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