[REF] web_planner: javascript & dom cleaning

* Correct inheritance of async method
* Correct calls to do_hide/show
* Fetch the template in `willStart`
* Correct bootstrap structure for the layout, remove useless branding
  and dom depth
* Each planner page is now in its own bootstrap grid
* Compatibility between both webclients
This commit is contained in:
Simon Lejeune
2015-07-23 14:02:40 +02:00
parent 2de2a8064c
commit 5666cd3643
7 changed files with 159 additions and 176 deletions
+1
View File
@@ -135,6 +135,7 @@ var Menu = Widget.extend({
var $clicked_menu, $sub_menu, $main_menu;
$clicked_menu = this.$el.add(this.$secondary_menus).find('a[data-menu=' + id + ']');
this.trigger('open_menu', id, $clicked_menu);
core.bus.trigger('change_menu_section', $clicked_menu.parents('.oe_secondary_menu').data('menu-parent') || 0);
if (this.$secondary_menus.has($clicked_menu).length) {
$sub_menu = $clicked_menu.parents('.oe_secondary_menu');
@@ -6,7 +6,7 @@ var Model = require('web.Model');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var planner = require('web.planner.common');
var WebClient = require('web.WebClient');
var webclient = require('web.web_client');
var PlannerDialog = planner.PlannerDialog;
@@ -18,19 +18,19 @@ var PlannerLauncher = Widget.extend({
init: function(parent) {
this._super(parent);
this.planner_by_menu = {};
this.webclient = parent.getParent();
this.need_reflow = false;
},
start: function() {
var self = this;
self._super();
self.webclient.menu.on("open_menu", self, self.on_menu_clicked);
self.$el.hide(); // hidden by default
return self.fetch_application_planner().done(function(apps) {
core.bus.on("change_menu_section", self, self.on_menu_clicked);
var res = self._super.apply(this, arguments).then(function() {
return self.fetch_application_planner();
}).then(function(apps) {
self.do_hide(); // hidden by default
self.planner_apps = apps;
return apps;
});
return res;
},
fetch_application_planner: function() {
var self = this;
@@ -48,13 +48,12 @@ var PlannerLauncher = Widget.extend({
}
return def;
},
on_menu_clicked: function(id, $clicked_menu) {
var menu_id = $clicked_menu.parents('.oe_secondary_menu').data('menu-parent') || 0; // find top menu id
on_menu_clicked: function(menu_id) {
if (_.contains(_.keys(this.planner_apps), menu_id.toString())) {
this.setup(this.planner_apps[menu_id]);
this.need_reflow = true;
} else {
this.$el.hide();
this.do_hide();
this.hide_dialog();
this.need_reflow = true;
}
@@ -65,9 +64,6 @@ var PlannerLauncher = Widget.extend({
},
setup: function(planner){
var self = this;
var webclient = this.findAncestor(function (a) {
return a instanceof WebClient;
});
this.planner = planner;
if (this.dialog) {
@@ -81,30 +77,25 @@ var PlannerLauncher = Widget.extend({
self.update_parent_progress_bar(percent);
});
},
// event
update_parent_progress_bar: function(percent) {
if (percent == 100) {
this.$(".progress").hide();
} else {
this.$(".progress").show();
}
this.$el.show();
this.do_show();
this.$(".progress-bar").css('width', percent+"%");
},
hide_dialog: function() {
if (this.dialog) {
this.dialog.$el.hide();
this.dialog.do_hide();
}
},
toggle_dialog: function() {
this.dialog.$el.toggle();
this.dialog.do_toggle();
}
});
// add planner launcher to the systray
// if it is empty, it won't be display. Then, each time a top menu is clicked
// a planner will be given to the launcher. The launcher will appears if the
// given planner is not null.
SystrayMenu.Items.push(PlannerLauncher);
return {
@@ -112,3 +103,4 @@ return {
};
});
@@ -7,7 +7,6 @@ var Widget = require('web.Widget');
var utils = require('web.utils');
var QWeb = core.qweb;
var bus = core.bus;
var Page = core.Class.extend({
init: function (dom, page_index) {
@@ -36,13 +35,6 @@ var Page = core.Class.extend({
},
});
/*
Template rules:
Input elements (select, textarea, radio, ...) MUST HAVE an 'id' as 'input_element_#####', where ##### is a string.
Page div MUST HAVE the class "o_planner_page" and an 'id' as 'planner_page#', where # is ideally a
number. The declaration order of the page are important. The 'id' number is NOT the sequence order.
Menu item MUST HAVE an href attribute containing the id of the page they are referencing.
*/
var PlannerDialog = Widget.extend({
template: "PlannerDialog",
pages: [],
@@ -51,32 +43,46 @@ var PlannerDialog = Widget.extend({
currently_active_menu_item: null,
category_selector: 'div[menu-category-id]',
events: {
'click li a[href^="#"]': 'change_page',
'click li a[href^="#"]:not([data-toggle="collapse"])': 'change_page',
'click button.mark_as_done': 'click_on_done',
'click a.btn-next': 'change_to_next_page',
},
init: function(parent, planner) {
this._super(parent);
this.planner_launcher = parent;
this.planner = planner;
this.cookie_name = this.planner['planner_application'] + '_last_page';
this.cookie_name = this.planner.planner_application + '_last_page';
this.set('progress', 0);
this.pages = [];
this.menu_items = [];
},
/**
* Fetch the planner's rendered template
*/
willStart: function() {
var self = this;
var res = this._super.apply(this, arguments).then(function() {
return (new Model('web.planner')).call('render', [self.planner.view_id[0], self.planner.planner_application]);
}).then(function(template) {
self.$res = $(template);
});
return res;
},
start: function() {
var self = this;
this._super.apply(this, arguments);
self.$el.hide();
return (new Model('web.planner')).call('render', [self.planner.view_id[0], self.planner.planner_application]).then(function(res) {
var $res = $(res);
$res.find('.o_planner_page').each(function(index, dom_page) {
var page = new Page(dom_page, index);
return this._super.apply(this, arguments).then(function() {
self.do_hide();
self.$el.on('keyup', "textarea", function() {
if (this.scrollHeight != this.clientHeight) {
this.style.height = this.scrollHeight + "px";
}
});
self.$res.find('.o_planner_page').andSelf().filter('.o_planner_page').each(function(index, dom_page) {
var page = new Page(dom_page, index);
self.pages.push(page);
});
var $menu = self.render_menu($res);
var $menu = self.render_menu(); // wil use self.$res
self.$('.o_planner_menu ul').html($menu);
self.menu_items = self.$('.o_planner_menu li');
@@ -84,7 +90,7 @@ var PlannerDialog = Widget.extend({
page.menu_item = self._find_menu_item_by_page_id(page.id);
});
self.$('.o_content_page').html($res);
self.$el.append(self.$res);
// update the planner_data with the new inputs of the view
var actual_vals = self._get_values();
@@ -93,24 +99,20 @@ var PlannerDialog = Widget.extend({
self._set_values(self.planner.data);
// show last opened page
self._show_last_open_page();
self.$el.on('keyup', "textarea", function() {
if (this.scrollHeight != this.clientHeight) {
this.style.height = this.scrollHeight + "px";
}
});
}).then(function() {
self.prepare_planner_event();
});
},
// This method should be overridden in other planners to bind their custom events, once the view is loaded.
/**
* This method should be overridden in other planners to bind their custom events once the
* view is loaded.
*/
prepare_planner_event: function() {
var self = this;
self.on('change:progress', self, function(){
this.on('change:progress', this, function() {
self.trigger('planner_progress_changed', self.get('progress'));
});
this.on('planner_progress_changed', this, this.update_ui_progress_bar);
this.set('progress', this.planner.progress); // init progress to trigger ui update
this.set('progress', this.planner.progress); // set progress to trigger initial UI update
},
_render_done_page: function (page) {
var mark_as_done_button = this.$('.mark_as_done');
@@ -140,7 +142,7 @@ var PlannerDialog = Widget.extend({
var last_open_page = utils.get_cookie(this.cookie_name);
if (! last_open_page) {
last_open_page = this.planner.data['last_open_page'] || false;
last_open_page = this.planner.data.last_open_page || false;
}
if (last_open_page) {
@@ -152,7 +154,7 @@ var PlannerDialog = Widget.extend({
update_ui_progress_bar: function(percent) {
this.$(".progress-bar").css('width', percent+"%");
},
create_menu_item: function(page, menu_items, menu_item_page_map) {
_create_menu_item: function(page, menu_items, menu_item_page_map) {
var $page = $(page.dom);
var $menu_item_element = $page.find('h1[data-menutitle]');
var menu_title = $menu_item_element.data('menutitle') || $menu_item_element.text();
@@ -168,14 +170,13 @@ var PlannerDialog = Widget.extend({
// pages with no category
self.pages.forEach(function(page) {
var $page = $(page.dom);
if (! page.hide_from_menu && ! page.get_category_name(self.category_selector)) {
self.create_menu_item(page, orphan_pages, menu_item_page_map);
self._create_menu_item(page, orphan_pages, menu_item_page_map);
}
});
// pages with a category
$res.find(self.category_selector).each(function(index, menu_category) {
self.$res.filter(self.category_selector).each(function(index, menu_category) {
var $menu_category = $(menu_category);
var menu_category_item = {
name: $menu_category.attr('menu-category-id'),
@@ -185,11 +186,15 @@ var PlannerDialog = Widget.extend({
self.pages.forEach(function(page) {
if (! page.hide_from_menu && page.get_category_name(self.category_selector) === menu_category_item.name) {
self.create_menu_item(page, menu_category_item.menu_items, menu_item_page_map);
self._create_menu_item(page, menu_category_item.menu_items, menu_item_page_map);
}
});
menu_categories.push(menu_category_item);
// remove the branding used to separate the pages
self.$res = self.$res.not($menu_category);
self.$res = self.$res.add($menu_category.contents());
});
var menu = QWeb.render('PlannerMenu', {
@@ -204,7 +209,7 @@ var PlannerDialog = Widget.extend({
var self = this;
var current_page_found = false;
var next_page_id = null;
self.pages.every(function(page) {
this.pages.every(function(page) {
if (current_page_found) {
next_page_id = page.id;
return false;
@@ -282,9 +287,10 @@ var PlannerDialog = Widget.extend({
this.$('.o_planner_title').text(this.currently_shown_page.title);
this._render_done_page(this.currently_shown_page);
this.planner.data['last_open_page'] = page_id;
this.planner.data.last_open_page = page_id;
utils.set_cookie(this.cookie_name, page_id, 8*60*60); // create cookie for 8h
this.$(".o_content_page").scrollTop("0");
this.$(".o_planner_page").scrollTop("0");
autosize(this.$("textarea"));
},
// planner data functions
_get_values: function(page){
@@ -297,16 +303,16 @@ var PlannerDialog = Widget.extend({
_.each(inputs, function(elem){
var $elem = $(elem);
var tid = $elem.attr('id');
if ($elem.prop("tagName") == 'BUTTON'){
if ($elem.prop("tagName") === 'BUTTON'){
if($elem.hasClass('fa-check-square-o')){
values[tid] = 'marked';
}else{
values[tid] = '';
}
}
if ($elem.prop("tagName") == 'INPUT' || $elem.prop("tagName") == 'TEXTAREA'){
if ($elem.prop("tagName") === 'INPUT' || $elem.prop("tagName") === 'TEXTAREA'){
var ttype = $elem.attr('type');
if (ttype == 'checkbox' || ttype == 'radio'){
if (ttype === 'checkbox' || ttype === 'radio'){
values[tid] = '';
if ($elem.is(':checked')){
values[tid] = 'checked';
@@ -326,16 +332,16 @@ var PlannerDialog = Widget.extend({
var self = this;
_.each(values, function(val, id){
var $elem = self.$('[id="'+id+'"]');
if ($elem.prop("tagName") == 'BUTTON'){
if(val == 'marked'){
if ($elem.prop("tagName") === 'BUTTON'){
if(val === 'marked'){
$elem.addClass('fa-check-square-o btn-default').removeClass('fa-square-o btn-primary');
self.$("li a[href=#"+$elem.data('pageid')+"] span").addClass('fa-check');
}
}
if ($elem.prop("tagName") == 'INPUT' || $elem.prop("tagName") == 'TEXTAREA'){
if ($elem.prop("tagName") === 'INPUT' || $elem.prop("tagName") === 'TEXTAREA'){
var ttype = $elem.attr("type");
if (ttype == 'checkbox' || ttype == 'radio'){
if (val == 'checked') {
if (ttype === 'checkbox' || ttype === 'radio'){
if (val === 'checked') {
$elem.attr('checked', 'checked');
}
}else{
@@ -376,18 +382,17 @@ var PlannerDialog = Widget.extend({
_save_planner_data: function() {
return (new Model('web.planner')).call('write', [this.planner.id, {'data': JSON.stringify(this.planner.data), 'progress': this.planner.progress}]);
},
// user actions
click_on_done: function(ev) {
ev.preventDefault();
this.currently_shown_page.toggle_done();
this._render_done_page(this.currently_shown_page);
this.update_planner();
},
on_webclient_action: function(e) {
this.$('#PlannerDialog').hide();
},
});
return {
PlannerDialog: PlannerDialog,
};
});
@@ -204,35 +204,44 @@
width: @o_planner_width;
z-index: 1001; // z-index website + 1
padding-bottom: 80px;
.row { // website adds negative margins
margin-left: 0px;
margin-right: 0px;
}
.box-shadow(@shadow) {
-webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1
box-shadow: @shadow;
}
.box-shadow(0 3px 9px #666666);
background-color: white;
-webkit-box-shadow: 0 3px 9px #666666;
box-shadow: 0 3px 9px #666666;
.o_planner_header {
display: inline-block;
width: 33.33333333%;
padding: 5px 5px 5px 5px;
}
h1 {
font-size: 3.5em;
font-weight: 100;
.o_planner_menu {
> a.btn {
width: 100%;
}
> ul {
> h4 {
> i.fa {
margin-right: 5px;
}
}
}
}
.o_content_page {
.o_planner_page {
display: none;
padding-left: 15px;
padding-right: 15px;
height: 100%;
overflow: auto;
.marked:after {
> h1 {
font-size: 3.5em;
font-weight: 100;
}
&.marked:after {
position: absolute;
top: 0;
left: 105px;
@@ -261,6 +270,7 @@
-ms-transform-origin: 50% 50%;
-ms-animation-fill-mode:forwards; /*IE 10+*/
}
//NOTEBOOK
.o_planner_notebook_container {
margin: 20px 0;
@@ -273,18 +283,20 @@
position: relative;
background-color: #fcf8e3;
textarea,input {
textarea, input {
background: #fcf8e3;
border: none;
width: 100%;
max-width: 100%;
}
> li {
list-style: none;
border-bottom: 1px dashed #C1D6DA;
padding: 10px 10px 5px 55px;
text-transform: capitalize;
margin: 0;
span {
position: absolute;
left: 9px;
@@ -293,10 +305,22 @@
font-weight: bold;
}
}
> li:last-child { border-bottom: 0;}
> li.row {
span {
left: -50px; // make up for the li's left padding
}
}
> li:last-child {
border-bottom: 0;
}
.o_planner_notebook_header {
div.dropdown { display: inline;float:right; }
div.dropdown {
display: inline;
float:right;
}
a {
color: #C4A87A;
position: absolute;
@@ -332,6 +356,7 @@
}
}
}
// WHITE BOX
.o_planner_white_box{
.panel{
@@ -344,6 +369,7 @@
}
}
}
// TROPHY
.o_planner_trophy {
font-size: 11em;
@@ -367,52 +393,25 @@
opacity: 0.6;
}
}
}
a {
color: #2E917D
}
.btn-default {
background-color: transparent;
color: #7C7C7C;
line-height: 19px;
}
.btn-default:hover {
color: #333;
}
.btn-primary {
background: #21b799;
border-color: #26A38A;
color: white;
}
.btn-primary:hover {
background-color: #2E917D;
color: white;
}
.odoo_purple, a.btn.odoo_purple {
background-color: #A24689;
color: white;
}
.odoo_purple.btn:hover {
background: #a24689;
color: #fff;
}
.odoo_purple, a.btn.odoo_purple, .btn.odoo_purple:hover {
background-color: #A24689;
color: white;
}
.o_planner_page {
display : none;
}
// PARAGRAPHS
.o_planner_paragraphs .icon {
text-align: center;
font-size: 2em;
margin: 1em auto .5em;
color: #21b799;
}
// PARAGRAPHS
.o_planner_paragraphs .icon {
text-align: center;
font-size: 2em;
margin: 1em auto .5em;
color: #21b799;
}
// INSTALL APP
.o_planner_row_apps{
.col-md-4{
margin-top: 20px;
// INSTALL APP
.o_planner_row_apps{
.col-md-4{
margin-top: 20px;
}
}
}
}
}
@@ -15,26 +15,24 @@
<t t-name="PlannerDialog">
<div id="PlannerDialog" tabindex="-1">
<div class="row dropdown o_planner_menu">
<a class="col-xs-12 btn btn-default" data-toggle="dropdown" href="#" aria-expanded="false">Steps <span class="caret"></span></a>
<div class="dropdown o_planner_menu">
<a class="btn btn-default" data-toggle="dropdown" href="#" aria-expanded="false">Steps <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"/>
</div>
<div class="row o_planner_header">
<div class="col-xs-4">
<button class='fa fa-square-o btn btn-primary mark_as_done'>
<i/>
<span>Mark As Done</span>
</button>
</div>
<div class="col-xs-4 text-center"><span class="help-block span-next o_planner_title"/></div>
<div class="col-xs-4">
<a class="pull-right btn btn-next">
Next step
<i class="fa fa-angle-right"></i>
</a>
</div>
<div class="o_planner_header">
<button class='fa fa-square-o btn btn-primary mark_as_done'>
<i/>
<span>Mark As Done</span>
</button>
</div><div class="o_planner_header text-center">
<span class="help-block span-next o_planner_title"/>
</div><div class="o_planner_header text-right">
<a class="btn btn-next">
Next step
<i class="fa fa-angle-right"></i>
</a>
</div>
<div class="row o_content_page"/>
</div>
</t>
@@ -14,9 +14,7 @@
</template>
<template id="pages">
<div class ="row">
<t t-raw="0"/>
</div>
<t t-raw="0"/>
</template>
<template id="category">
@@ -26,7 +24,7 @@
</template>
<template id="page">
<div t-att-id="page_id" t-att-title="page_title" t-att-hide-from-menu="hide_from_menu" t-att-hide-mark-as-done="hide_mark_as_done" class="o_planner_page">
<div t-att-id="page_id" t-att-title="page_title" t-att-hide-from-menu="hide_from_menu" t-att-hide-mark-as-done="hide_mark_as_done" class="o_planner_page container-fluid">
<h1 t-esc="page_title" t-att-data-menutitle="page_menutitle or page_title"/>
<t t-raw="0"/>
</div>
@@ -6,7 +6,7 @@ var core = require('web.core');
var Model = require('web.Model');
var Widget = require('web.Widget');
var planner = require('web.planner.common');
var base = require('web_editor.base');
require('web_editor.base'); // wait for implicit dependencies to load
var qweb = core.qweb;
@@ -14,17 +14,15 @@ if(!$('#oe_systray').length) {
return $.Deferred().reject("DOM doesn't contain '#oe_systray'");
}
var PlannerDialog = planner.PlannerDialog;
planner.WebsitePlannerLauncher = Widget.extend({
var WebsitePlannerLauncher = Widget.extend({
template: "PlannerLauncher",
events: {
'click .o_planner_progress': 'toggle_dialog'
},
start: function() {
var self = this;
this._super.apply(this, arguments);
return this.get_website_planner().then(function(planner) {
var res = this._super.apply(this, arguments);
return res.then(this.get_website_planner.bind(this)).then(function(planner) {
if (planner.length) {
self.planner = planner[0];
self.planner.data = $.parseJSON(planner[0].data) || {};
@@ -37,33 +35,25 @@ planner.WebsitePlannerLauncher = Widget.extend({
},
setup: function() {
var self = this;
this.dialog = new PlannerDialog(this, this.planner);
this.dialog = new planner.PlannerDialog(this, this.planner);
this.dialog.appendTo(document.body);
this.$(".o_planner_progress").tooltip({html: true, title: this.planner.tooltip_planner, placement: 'bottom', container: 'body', delay: {'show': 700}});
this.dialog.on("planner_progress_changed", this, function(percent) {
self.update_parent_progress_bar(percent);
});
this.dialog.appendTo(document.body);
},
update_parent_progress_bar: function(percent) {
this.$(".progress-bar").css('width', percent+"%");
},
toggle_dialog: function() {
this.dialog.$el.toggle();
this.dialog.do_toggle();
},
});
PlannerDialog.include({
prepare_planner_event: function() {
var self = this;
this._super.apply(this, arguments);
self.$el.on("click", ".o_planner a.o_planner_hide", function(ev) {
self.$('#PlannerModal').modal('hide');
});
}
});
return ajax.loadXML('/web_planner/static/src/xml/web_planner.xml', qweb).then(function() {
new planner.WebsitePlannerLauncher().prependTo($('#oe_systray'));
});
var websitePlannerLauncher = new WebsitePlannerLauncher();
websitePlannerLauncher.prependTo($('#oe_systray'));
});
});