[REF] web_planner: refactor to make less brittle and reliant on layout

This introduces a new way to define web_planners. They now take the
following form:

<template id="project_planner">
    <t t-call="web_planner.pages">
    <t t-call="web_planner.category">
        <t t-set="menu_categorytitle" t-value="'Prepare'"/>
        <t t-set="menu_categoryclasses" t-value="'fa-flag-checkered'"/>
        <t t-call="web_planner.page">
            <t t-set="page_title" t-value="'Welcome'"/>
            <t t-set="hide_mark_as_done" t-value="True"/>
            <t t-set="hide_from_menu" t-value="True"/>
            <!-- content here -->
        </t>
    </t>
</template>

The menu is not manually created anymore, it is automatically generated.

Pages do not have to be part of a category and can just be defined as
children of web_planner.pages. A page can have hide_mark_as_done and
hide_from_menu, these are optional and will both default to False when
omitted.
This commit is contained in:
Joren Van Onder
2015-07-23 13:56:07 +02:00
committed by Simon Lejeune
parent c505f00c3e
commit b2eafca067
6 changed files with 406 additions and 465 deletions
@@ -1,10 +1,12 @@
odoo.define('web.planner', function (require) {
"use strict";
var core = require('web.core');
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 PlannerDialog = planner.PlannerDialog;
@@ -52,26 +54,32 @@ var PlannerLauncher = Widget.extend({
this.setup(this.planner_apps[menu_id]);
this.need_reflow = true;
} else {
if (this.$el.is(":visible")) {
this.$el.hide();
this.need_reflow = true;
}
this.$el.hide();
this.hide_dialog();
this.need_reflow = true;
}
if (this.need_reflow) {
this.webclient.menu.reflow();
core.bus.trigger('resize');
this.need_reflow = false;
}
},
setup: function(planner){
var self = this;
var webclient = this.findAncestor(function (a) {
return a instanceof WebClient;
});
this.planner = planner;
this.dialog && this.dialog.destroy();
if (this.dialog) {
this.dialog.destroy();
}
this.dialog = new PlannerDialog(this, planner);
this.dialog.$el.remove();
this.dialog.appendTo(webclient.$el);
this.$(".o_planner_progress").tooltip({html: true, title: this.planner.tooltip_planner, placement: 'bottom', delay: {'show': 500}});
this.dialog.on("planner_progress_changed", this, function(percent){
self.update_parent_progress_bar(percent);
});
this.dialog.appendTo(document.body);
},
// event
update_parent_progress_bar: function(percent) {
@@ -83,8 +91,13 @@ var PlannerLauncher = Widget.extend({
this.$el.show();
this.$(".progress-bar").css('width', percent+"%");
},
hide_dialog: function() {
if (this.dialog) {
this.dialog.$el.hide();
}
},
toggle_dialog: function() {
this.dialog.$('#PlannerModal').modal('toggle');
this.dialog.$el.toggle();
}
});
@@ -99,4 +112,3 @@ return {
};
});
@@ -9,23 +9,51 @@ var utils = require('web.utils');
var QWeb = core.qweb;
var bus = core.bus;
var Page = core.Class.extend({
init: function (dom, page_index) {
var $dom = $(dom);
this.dom = dom;
this.hide_from_menu = $dom.attr('hide-from-menu');
this.hide_mark_as_done = $dom.attr('hide-mark-as-done');
this.done = false;
this.menu_item = null;
this.title = $dom.find('[data-menutitle]').data('menutitle');
var page_id = this.title.replace(/\s/g, '') + page_index;
this.set_page_id(page_id);
},
set_page_id: function (id) {
this.id = id;
$(this.dom).attr('id', id);
},
toggle_done: function () {
this.done = ! this.done;
},
get_category_name: function (category_selector) {
var $page = $(this.dom);
return $page.parents(category_selector).attr('menu-category-id');
},
});
/*
Widget implementing the Modal of the planner (with all form, menu items, mark buttons, pages, ...). The content (the view_id) is fetched by
calling the 'render' method (server side), then footer are appended to every pages (client side). Data are saved when a 'mark button' is clicked.
Some element of the template MUST respect naming convention :
* 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.
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: [],
menu_items: [],
currently_shown_page: null,
currently_active_menu_item: null,
category_selector: 'div[menu-category-id]',
events: {
'click .o_planner div[id^="planner_page"] a[href^="#planner_page"]': 'change_page',
'click .o_planner li a[href^="#planner_page"]': 'change_page',
'click .o_planner div[id^="planner_page"] button[data-pageid^="planner_page"]': 'mark_as_done',
'hidden.bs.modal': 'on_modal_hide',
'shown.bs.modal': 'on_modal_show',
'click li a[href^="#"]': '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);
@@ -33,11 +61,45 @@ var PlannerDialog = Widget.extend({
this.planner = planner;
this.cookie_name = this.planner['planner_application'] + '_last_page';
this.set('progress', 0);
this.pages = [];
this.menu_items = [];
},
start: function() {
var self = this;
this._super.apply(this, arguments);
this._setup_view().then(function(){
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);
self.pages.push(page);
});
var $menu = self.render_menu($res);
self.$('.o_planner_menu ul').html($menu);
self.menu_items = self.$('.o_planner_menu li');
self.pages.forEach(function(page) {
page.menu_item = self._find_menu_item_by_page_id(page.id);
});
self.$('.o_content_page').html($res);
// update the planner_data with the new inputs of the view
var actual_vals = self._get_values();
self.planner.data = _.defaults(self.planner.data, actual_vals);
// set the default value
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();
});
},
@@ -49,83 +111,185 @@ var PlannerDialog = Widget.extend({
});
this.on('planner_progress_changed', this, this.update_ui_progress_bar);
this.set('progress', this.planner.progress); // init progress to trigger ui update
$(window).on('resize', function() {
self.resize_dialog();
});
},
// ui
_setup_view: function(){
var self = this;
return (new Model('web.planner')).call('render', [self.planner.view_id[0], self.planner.planner_application]).then(function(res) {
self.$('.content_page').html(res);
// add footer to each page
self.add_pages_footer();
// update the planner_data with the new inputs of the view
var actual_vals = self._get_values();
self.planner.data = _.defaults(self.planner.data, actual_vals);
// set the default value
self._set_values(self.planner.data);
// show last opened page
var last_open_page = (utils.get_cookie(self.cookie_name)) ? utils.get_cookie(self.cookie_name) : self.planner.data['last_open_page'] || false;
if (last_open_page) {
self._switch_page(last_open_page);
}
// Call resize function at the beginning
self.resize_dialog();
self.$el.on('keyup', "textarea", function() {
if (this.scrollHeight != this.clientHeight) {
this.style.height = this.scrollHeight + "px";
}
});
});
_render_done_page: function (page) {
var mark_as_done_button = this.$('.mark_as_done');
var next_button = this.$('a.btn-next');
var active_menu = $(page.menu_item).find('span');
if (page.done) {
active_menu.addClass('fa-check');
mark_as_done_button.removeClass('fa-square-o btn-primary');
mark_as_done_button.addClass('fa-check-square-o btn-default');
next_button.removeClass('btn-default');
next_button.addClass('btn-primary');
// page checked animation
$(page.dom).addClass('marked');
setTimeout(function() {
$(page.dom).removeClass('marked');
}, 1000);
} else {
active_menu.removeClass('fa-check');
mark_as_done_button.removeClass('fa-check-square-o btn-default');
mark_as_done_button.addClass('fa-square-o btn-primary');
next_button.removeClass('btn-primary');
next_button.addClass('btn-default');
}
},
_show_last_open_page: function () {
var last_open_page = utils.get_cookie(this.cookie_name);
if (! last_open_page) {
last_open_page = this.planner.data['last_open_page'] || false;
}
if (last_open_page) {
this._display_page(last_open_page);
} else {
this._display_page(this.pages[0].id);
}
},
update_ui_progress_bar: function(percent) {
this.$(".progress-bar").css('width', percent+"%");
this.$(".o_planner_progress_col").find('.o_planner_progress_counter').text(percent+"%");
},
add_pages_footer: function() {
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();
menu_items.push(menu_title);
menu_item_page_map[menu_title] = page.id;
},
render_menu: function($res) {
var self = this;
//find all the pages and append footer to each pages
_.each(self.$('.o_planner div[id^="planner_page"]'), function(element) {
var $el = $(element);
var next_page_name = self.$(".o_planner .o_planner_sidebar li a[href='#"+$el.next().attr('id')+"']").text() || ' Finished!';
var footer_template = QWeb.render("PlannerFooter", {
'next_page_name': next_page_name,
'next_page_id': $el.next().attr('id'),
'current_page_id': $el.attr('id'),
'start': $el.prev().length ? false: true,
'end': $el.next().length ? false: true
});
$el.append(footer_template);
var orphan_pages = [];
var menu_categories = [];
var menu_item_page_map = {};
// 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);
}
});
// pages with a category
$res.find(self.category_selector).each(function(index, menu_category) {
var $menu_category = $(menu_category);
var menu_category_item = {
name: $menu_category.attr('menu-category-id'),
classes: $menu_category.attr('menu-classes'),
menu_items: [],
};
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);
}
});
menu_categories.push(menu_category_item);
});
var menu = QWeb.render('PlannerMenu', {
'orphan_pages': orphan_pages,
'menu_categories': menu_categories,
'menu_item_page_map': menu_item_page_map
});
return menu;
},
resize_dialog: function() {
var winH = $(window).height();
var $modal = this.$('.o_planner_dialog');
$modal.height(winH/1.1);
this.$('.o_planner_pages').height($modal.height() - 60);
this.$('.o_planner_sidebar').height($modal.height() - 75);
get_next_page_id: function() {
var self = this;
var current_page_found = false;
var next_page_id = null;
self.pages.every(function(page) {
if (current_page_found) {
next_page_id = page.id;
return false;
}
if (page.id === self.currently_shown_page.id) {
current_page_found = true;
}
return true;
});
return next_page_id;
},
change_to_next_page: function(ev) {
var next_page_id = this.get_next_page_id();
ev.preventDefault();
if (next_page_id) {
this._display_page(next_page_id);
}
},
// page switching
change_page: function(ev) {
ev.preventDefault();
var page_id = $(ev.currentTarget).attr('href').replace('#', '');
this._switch_page(page_id);
this._display_page(page_id);
},
_switch_page: function(page_id) {
this.$(".o_planner li a[href^='#planner_page']").parent().removeClass('active');
this.$(".o_planner li a[href=#"+page_id+"]").parent().addClass('active');
this.$(".o_planner div[id^='planner_page']").removeClass('show');
this.$(".o_planner div[id="+page_id+"]").addClass('show');
this.$(".o_planner .o_planner_pages").scrollTop("0");
_find_page_by_id: function (id) {
var result = _.find(this.pages, function (page) {
return page.id === id;
});
return result;
},
_find_menu_item_by_page_id: function (page_id) {
var result = _.find(this.menu_items, function (menu_item) {
var $menu_item = $(menu_item);
return $($menu_item.find('a')).attr('href') === '#' + page_id;
});
return result;
},
_display_page: function(page_id) {
var mark_as_done_button = this.$('button.mark_as_done');
var next_button = this.$('a.btn-next');
var page = this._find_page_by_id(page_id);
if (this.currently_active_menu_item) {
$(this.currently_active_menu_item).removeClass('active');
}
var menu_item = this._find_menu_item_by_page_id(page_id);
$(menu_item).addClass('active');
this.currently_active_menu_item = menu_item;
if (this.currently_shown_page) {
$(this.currently_shown_page.dom).removeClass('show');
}
$(page.dom).addClass('show');
this.currently_shown_page = page;
if (! this.get_next_page_id()) {
next_button.hide();
} else {
next_button.show();
}
if (page.hide_mark_as_done) {
mark_as_done_button.hide();
} else {
mark_as_done_button.show();
}
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;
utils.set_cookie(this.cookie_name, page_id, 8*60*60); // create cookie for 8h
this.$(".o_content_page").scrollTop("0");
},
// planner data functions
_get_values: function(page_id){
_get_values: function(page){
// if no page_id, take the complete planner
var base_elem = page_id ? this.$(".o_planner div[id="+page_id+"]") : this.$(".o_planner div[id^='planner_page']");
var base_elem = page ? $(page.dom) : this.$(".o_planner_page");
var values = {};
// get the selector for all the input and mark_button
// only INPUT (select, textearea, input, checkbox and radio), and BUTTON (.mark_button#) are observed
@@ -152,16 +316,20 @@ var PlannerDialog = Widget.extend({
}
}
});
this.pages.forEach(function(page) {
values[page.id] = page.done;
});
return values;
},
_set_values: function(values){
var self = this;
_.each(values, function(val, id){
var $elem = self.$('#'+id);
var $elem = self.$('[id="'+id+'"]');
if ($elem.prop("tagName") == 'BUTTON'){
if(val == 'marked'){
$elem.addClass('fa-check-square-o btn-default').removeClass('fa-square-o btn-primary');
self.$(".o_planner li a[href=#"+$elem.data('pageid')+"] span").addClass('fa-check');
self.$("li a[href=#"+$elem.data('pageid')+"] span").addClass('fa-check');
}
}
if ($elem.prop("tagName") == 'INPUT' || $elem.prop("tagName") == 'TEXTAREA'){
@@ -175,15 +343,31 @@ var PlannerDialog = Widget.extend({
}
}
});
this.pages.forEach(function(page) {
page.done = values[page.id];
self._render_done_page(page);
});
},
update_planner: function(page_id){
update_planner: function(){
// update the planner.data with the inputs
var vals = this._get_values(page_id);
var vals = this._get_values(this.currently_shown_page);
this.planner.data = _.extend(this.planner.data, vals);
// re compute the progress percentage
var mark_btn = this.$(".o_planner button[id^='mark_button']");
var marked_btn = this.$(".o_planner button[id^='mark_button'].fa-check-square-o");
var percent = parseInt((marked_btn.length+1) / (mark_btn.length+1) * 100);
var total_pages = 0;
var done_pages = 0;
this.pages.forEach(function(page) {
if (! page.hide_mark_as_done) {
total_pages++;
}
if (page.done) {
done_pages++;
}
});
var percent = parseInt((done_pages / total_pages) * 100, 10);
this.set('progress', percent);
this.planner.progress = percent;
// save data and progress in database
@@ -193,39 +377,13 @@ var PlannerDialog = Widget.extend({
return (new Model('web.planner')).call('write', [this.planner.id, {'data': JSON.stringify(this.planner.data), 'progress': this.planner.progress}]);
},
// user actions
mark_as_done: function(ev) {
var self = this;
var btn = $(ev.currentTarget);
var page_id = btn.attr('data-pageid');
var active_menu = self.$(".o_planner li a[href=#"+page_id+"] span");
var active_page = self.$(".o_planner div[id^='planner_page'].o_planner_page.show");
var next_button = self.$(".o_planner a[data-parent="+page_id+"]");
if (!btn.hasClass('fa-check-square-o')) {
active_menu.addClass('fa-check');
btn.addClass('fa-check-square-o btn-default').removeClass('fa-square-o btn-primary');
next_button.addClass('btn-primary').removeClass('btn-default');
// page checked animation
active_page.addClass('marked');
setTimeout(function() { active_page.removeClass('marked'); }, 1000);
} else {
btn.removeClass('fa-check-square-o btn-default').addClass('fa-square-o btn-primary');
next_button.addClass('btn-default').removeClass('btn-primary');
active_menu.removeClass('fa-check');
}
self.update_planner(page_id);
},
on_modal_show : function(e) {
bus.on('action', this, _.bind(this.on_webclient_action, this));
$(window).on("unload", this, _.bind(this.on_webclient_action, this)); // bind the action of quitting the window
},
on_modal_hide : function(e) {
bus.off('action', this, _.bind(this.on_webclient_action, this));
$(window).off("unload", this, _.bind(this.on_webclient_action, this)); // unbind the action of quitting the window
this.update_planner(); // explicit call to save data
click_on_done: function(ev) {
this.currently_shown_page.toggle_done();
this._render_done_page(this.currently_shown_page);
this.update_planner();
},
on_webclient_action: function(e) {
this.$('#PlannerModal').modal('hide');
this.$('#PlannerDialog').hide();
},
});
return {
@@ -233,4 +391,3 @@ return {
};
});
@@ -194,201 +194,52 @@
}
}
/**************** PLANNER MODAL ****************/
#PlannerModal {
@o_planner_width: 480px;
#PlannerDialog {
font-family: "Lato", serif;
position: absolute;
top: 35px;
right: 5px; // include box shadow
bottom: 5px;
width: @o_planner_width;
z-index: 1001; // z-index website + 1
padding-bottom: 80px;
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;
.row { // website adds negative margins
margin-left: 0px;
margin-right: 0px;
}
.o_planner_page{
display : none;
.box-shadow(@shadow) {
-webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1
box-shadow: @shadow;
}
.o_planner_dialog {
width: 85%;
max-width: 1024px;
//overflow: hidden;
margin-left: auto;
margin-right: auto;
.box-shadow(0 3px 9px #666666);
background-color: white;
// button close
button.close {
line-height: 30px;
color: rgba(51, 51, 51, 0.54);
.o_planner_header {
padding: 5px 5px 5px 5px;
}
h1 {
font-size: 3.5em;
font-weight: 100;
}
.o_content_page {
padding-left: 15px;
padding-right: 15px;
height: 100%;
overflow: auto;
.marked:after {
position: absolute;
right: 15px;
z-index:9999;
}
button.close:hover {
color:#222;
}
// modal core
.modal-content {
background: #f3f3f3;
}
.modal-body {
overflow-x: hidden;
max-height: inherit;
padding: 0;
}
.row.o_planner {
padding: 0 15px;
}
.o_planner_footer {
padding: 0;
height: auto;
overflow-y: visible;
overflow-x: initial;
display: block;
background: transparent;
position: fixed;
z-index: 99;
right: 0;
bottom: 0;
.shadow {
background: url("/web_planner/static/src/img/shadow.png") center center repeat-x;
height: 12px;
width: 100%;
display: block;
border-bottom: 1px solid #E5E5E5;
opacity: 0.3;
}
> div {
padding: 1em 15px;
background: #f7f7f7;
min-height: 60px;
}
.mark_as_done span{
font-family: Lato,serif;
}
// mark/uncheck button animation
button.fa-check-square-o {
left: 5em;
font-size: 2em;
border: none;
&:focus {outline:none}
&:hover:before{
content: "\f096";
color: #888;
position: absolute;
margin-left: 2px;
}
&:hover i:before{
content: "\f00c";
color: #CACACA;
}
span {display: none;}
}
button.fa-check-square-o:after {
color: #7C7C7C;
position: absolute;
font-size: .5em;
opacity: 0;
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
-ms-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
}
button.fa-check-square-o:hover:after {
opacity: 1;
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
-ms-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
}
.btn-next i {
margin-left: 10px;
}
.span-next {
position: absolute;
right: 9em;
top: 0.8em;
opacity: 0;
height: 1.3em;
font-size: 1em;
display: block;
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
-ms-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
.next-block:hover .span-next {
right: 9.6em;
opacity: 1;
}
}
// PROGRESS
.o_planner_progress_container {
padding: 0;
.o_planner_progress_col {
border-right: 1px solid #E5E5E5;
background: #f7f7f7;
padding: 10px 12px 0 12px;
i.fa{
font-size: 1.7em;
padding-left: 0;
margin-right: 0.2em;
margin-top: 0.1em;
color: #929292;
}
.o_planner_progress_counter {
padding: 6px 0 0 8px;
font-weight: bold;
color: #727272;
}
.progress {
background-color: #C4C4C4;
height: 30px;
padding: 3px;
}
.progress-bar {
background: #A24689;
border-radius: 4px;
height: 95%;
box-shadow: 0 1px 0 #7A3067;
}
}
}
// MARKED ANIMATION
.o_planner_page.marked:after {
position: absolute;
left: 0;
top: 0;
left: 105px;
font-size: 20em;
font-family: "FontAwesome";
content: "\f00c";
color: #21b799;
vertical-align: middle;
padding: 0.3em 0.7em;
animation: markAnim ease-in-out 1s;
animation-iteration-count: 1;
transform-origin: 50% 50%;
@@ -410,70 +261,6 @@
-ms-transform-origin: 50% 50%;
-ms-animation-fill-mode:forwards; /*IE 10+*/
}
// MENU MOBILE
.dropdown.mobile {
padding: 10px 12px 0 0px;
.dropdown-menu{
height: 250px;
overflow: auto;
}
.btn {
text-align: justify;
}
.dropdown-menu a {
color: #333;
padding: 3px;
}
.dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus {
background-color: #F3F3F3;
}
.dropdown-menu h4 {
padding: 10px 15px 0;
border-top: 1px solid #EAEAEA;
}
.fa {
color: #21b799;
margin-right: 5px;
}
}
.o_planner_sidebar {
padding: 5px 5px 20px 10px;
border-right: 1px solid #E5E5E5;
background: #f7f7f7;
overflow-x: hidden;
overflow-y: auto;
.nav-stacked h4 {
font-size: 15px;
color: #444;
text-transform: uppercase;
font-weight: bold;
margin-top: 20px;
}
.nav-stacked h4 i {
margin-right: 8px;
color: #A24689;
}
.nav-stacked li a {
padding: 3px 0 3px 38px;
margin: auto -10px;
color: #444;
font-size: 13px;
}
.nav-stacked li a:hover, .nav-stacked li a:focus {
text-decoration: none;
background-color: transparent;
color: black;
}
.nav-stacked li.active a{
background-color: #EAEAEA;
}
.fa.fa-fw.fa-check {
color: #21b799;
margin-left: -5px;
margin-right: 5px;
}
}
//NOTEBOOK
.o_planner_notebook_container {
margin: 20px 0;
@@ -581,26 +368,40 @@
}
}
}
.o_planner_pages {
color: #444;
margin-top:-60px;
overflow-x: hidden;
overflow-y: auto;
> div {
padding-top: 25px;
position: relative;
height: 100%;
> h1, > h2, > h3, > h4, > h5, > h6, > p, > strong, > i {
text-shadow:none;
}
h1 {
margin-top: 0;
font-size: 3.5em;
font-weight: 100;
margin-bottom: 0.5em;
}
}
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;
}
.o_planner_page {
display : none;
}
// PARAGRAPHS
.o_planner_paragraphs .icon {
text-align: center;
@@ -614,39 +415,4 @@
margin-top: 20px;
}
}
}
// XS size
@media screen and (max-width: 768px) {
#PlannerModal .pages {
margin-top: 0px;
}
#PlannerModal .o_planner_progress_counter {
padding: 6px 0 0 5px;
}
}
// SM size
@media screen and (min-width: 769px) {
#PlannerModal .o_planner_paragraphs {
div.col-md-10 {
margin-top:1em;
}
span {
transform: translateX(-8px);
position: relative;
display: block;
}
}
}
// MD size
@media screen and (min-width: 992px) {
#PlannerModal .o_planner_paragraphs .icon {
font-size: 4em;
margin: 0.3em auto .5em;
span{
transform: translateX(0px);
position: relative;
display: block;
}
}
}
}
@@ -13,54 +13,41 @@
</li>
</t>
<t t-name="PlannerFooter">
<div class="o_planner_footer col-sm-8 col-md-9 col-xs-12 hidden-print">
<span class="shadow" />
<div class="col-xs-6 text-left mark-block">
<t t-if="!start and !end">
<button t-attf-id='mark_button#{current_page_id}'
t-attf-data-pageid='#{current_page_id}'
class='fa fa-square-o btn btn-primary mark_as_done'><i /> <span>Mark As Done</span>
<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>
<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>
</t>
</div>
<div class="col-xs-6 next-block">
<t t-if="!end">
<a t-attf-class="pull-right btn btn-#{start and 'primary' or 'default'} btn-next"
t-attf-data-parent='#{current_page_id}'
t-attf-href='##{next_page_id}'>Next step<i class="fa fa-angle-right"></i>
</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>
<span class="help-block span-next"> <t t-esc="next_page_name"/></span>
</t>
</div>
</div>
<div class="row o_content_page"/>
</div>
</t>
<t t-name="PlannerDialog">
<div>
<div class="modal fade odoo_colors" id="PlannerModal" tabindex="-1" role="dialog" aria-labelledby="PlannerModalLabel" aria-hidden="true">
<div class="modal-dialog o_planner_dialog">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal"><i class="fa fa-times"></i></button>
<div>
<div class="col-sm-12 col-xs-7 o_planner_progress_container">
<div class="col-sm-4 col-md-3 col-xs-12 o_planner_progress_col">
<i class="fa fa-question-circle col-xs-1"></i>
<div class="progress col-xs-9">
<div class="progress-bar" t-attf-style="width:0%;"></div>
</div>
<span class="o_planner_progress_counter col-xs-1"></span>
</div>
</div>
<div class="content_page"/>
</div>
</div>
</div>
</div>
</div>
</div>
<t t-name="PlannerMenu">
<li t-foreach="orphan_pages" t-as="orphan_page">
<a t-att-href="'#' + menu_item_page_map[orphan_page]"><span class="fa fa-fw"/><t t-esc="orphan_page"/></a>
</li>
<t t-foreach="menu_categories" t-as="menu_category">
<h4><i t-att-class="'fa ' + menu_category.classes"/><t t-esc="menu_category.name"/></h4>
<li t-foreach="menu_category.menu_items" t-as="menu_item">
<a t-att-href="'#' + menu_item_page_map[menu_item]"><span class="fa fa-fw"/><t t-esc="menu_item"/></a>
</li>
</t>
</t>
</templates>
@@ -12,4 +12,23 @@
<script type="text/javascript" src="/web_planner/static/src/js/web_planner_common.js"></script>
</xpath>
</template>
<template id="pages">
<div class ="row">
<t t-raw="0"/>
</div>
</template>
<template id="category">
<div t-att-menu-category-id="menu_categorytitle" t-att-menu-classes="menu_categoryclasses">
<t t-raw="0"/>
</div>
</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">
<h1 t-esc="page_title" t-att-data-menutitle="page_menutitle or page_title"/>
<t t-raw="0"/>
</div>
</template>
</odoo>
@@ -48,7 +48,7 @@ planner.WebsitePlannerLauncher = Widget.extend({
this.$(".progress-bar").css('width', percent+"%");
},
toggle_dialog: function() {
this.dialog.$('#PlannerModal').modal('toggle');
this.dialog.$el.toggle();
},
});