flectra/addons/web_planner/static/src/js/web_planner_common.js

402 lines
15 KiB
JavaScript

flectra.define('web.planner.common', function (require) {
"use strict";
var core = require('web.core');
var Dialog = require('web.Dialog');
var dom = require('web.dom');
var rpc = require('web.rpc');
var session = require('web.session');
var utils = require('web.utils');
var weContext = require('web_editor.context');
var Widget = require('web.Widget');
var QWeb = core.qweb;
var _t = core._t;
var MIN_PROGRESS = 7;
var Page = core.Class.extend({
init: function (dom, page_index) {
this.$dom = $(dom);
this.hide_from_menu = this.$dom.attr('hide-from-menu');
this.hide_mark_as_done = this.$dom.attr('hide-mark-as-done');
this.done = false;
this.menu_item = null;
this.title = this.$dom.find('[data-menutitle]').data('menutitle');
this.set_page_id(this.title.replace(/\s/g, '') + page_index);
},
set_page_id: function (id) {
this.id = id;
this.$dom.attr('id', id);
},
get_category_name: function (category_selector) {
return this.$dom.parents(category_selector).attr('menu-category-id');
},
});
var PlannerDialog = Dialog.extend({
template: "PlannerDialog",
category_selector: "div[menu-category-id]",
events: {
"click li a[href^=\"#\"]:not([data-toggle=\"collapse\"])": function (e) {
e.preventDefault();
this._display_page($(e.currentTarget).attr("href").replace("#", ""));
},
},
init: function (parent, options, planner) {
this._super.apply(this, arguments);
this.planner = planner;
this.cookie_name = this.planner.planner_application + '_last_page';
this.pages = [];
this.menu_items = [];
this.currently_shown_page = null;
this.currently_active_menu_item = null,
this.on("change:progress", this, function () {
this.trigger('planner_progress_changed', this.get('progress'));
});
this.set("progress", this.planner.progress || MIN_PROGRESS);
},
/**
* Fetch the planner's rendered template
*/
willStart: function() {
// fallback context for frontend
var context = session.is_frontend ? weContext.get() : session.user_context;
var def = rpc.query({
model: 'web.planner',
method: 'render',
args: [this.planner.view_id[0], this.planner.planner_application],
context: context,
})
.then((function (template) {
this.$template = $(template);
}).bind(this));
return $.when(this._super.apply(this, arguments), def);
},
start: function() {
this.$modal.addClass("o_planner_dialog");
this.$template.find(".o_planner_page").addBack(".o_planner_page").each((function (index, dom_page) {
this.pages.push(new Page(dom_page, index));
}).bind(this));
this.$menu = this.$('> .o_planner_menu');
this.$menu.html(this._render_menu());
this.menu_items = this.$menu.find("li");
_.each(this.pages, (function (page) {
page.menu_item = this._find_menu_item_by_page_id(page.id);
}).bind(this));
this.$el.append(this.$template);
// update the planner_data with the new inputs of the view
var actual_vals = this._get_values();
this.planner.data = _.defaults(this.planner.data, actual_vals);
// set the default value
this._set_values(this.planner.data);
// show last opened page
this._show_last_open_page();
this.on("planner_progress_changed", this, this._update_title);
this._update_title();
this.prepare_planner_event();
return this._super.apply(this, arguments);
},
prepare_planner_event: function () {}, // overriden by modules
toggle_current_page_status: function () {
this.currently_shown_page.done = !this.currently_shown_page.done;
this._render_page_status(this.currently_shown_page, true);
this._update_buttons();
this._update_planner();
},
change_to_next_page: function (ev) {
ev.preventDefault();
this._display_page(this._get_next_page_id());
},
_update_title: function () {
this.set_title(core.qweb.render("PlannerDialog.Title", {
title: this.currently_shown_page.title,
percent: this.get("progress")
}));
},
_update_buttons: function () {
var page = this.currently_shown_page;
var buttons = [];
if (!page.hide_mark_as_done) {
buttons.push({
text: _t("Mark As Done"),
icon: page.done ? "fa-check-square-o" : "fa-square-o",
classes: "o_mark_as_done btn-" + (page.done ? "default" : "primary"),
click: this.toggle_current_page_status
});
}
if (this._get_next_page_id()) {
buttons.push({
text: _t("Next Step"),
icon: "fa-angle-right pull-right mt4",
classes: "o_next_step btn-" + ((page.done || page.hide_mark_as_done) ? "primary" : "default"),
click: this.change_to_next_page
});
}
this.set_buttons(buttons);
},
_render_page_status: function (page, withAnim) {
$(page.menu_item).find('span').toggleClass('fa-check', !!page.done);
if (withAnim && page.done) { // page checked animation
page.$dom.addClass('marked');
_.delay(function () {
page.$dom.removeClass('marked');
}, 1000);
}
},
_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._find_page_by_id(last_open_page)) {
this._display_page(last_open_page);
} else {
this._display_page(this.pages[0].id);
}
},
_render_menu: function() {
var orphan_pages = [];
var menu_categories = [];
var menu_item_page_map = {};
// pages with no category
_.each(this.pages, (function (page) {
if (!page.hide_from_menu && !page.get_category_name(this.category_selector)) {
_create_menu_item(page, orphan_pages, menu_item_page_map);
}
}).bind(this));
// pages with a category
this.$template.filter(this.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: [],
};
_.each(this.pages, (function (page) {
if (!page.hide_from_menu && page.get_category_name(this.category_selector) === menu_category_item.name) {
_create_menu_item(page, menu_category_item.menu_items, menu_item_page_map);
}
}).bind(this));
menu_categories.push(menu_category_item);
// remove the branding used to separate the pages
this.$template = this.$template.not($menu_category);
this.$template = this.$template.add($menu_category.contents());
}).bind(this));
return QWeb.render('PlannerMenu', {
'orphan_pages': orphan_pages,
'menu_categories': menu_categories,
'menu_item_page_map': menu_item_page_map
});
function _create_menu_item(page, menu_items, menu_item_page_map) {
var $menu_item_element = page.$dom.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;
}
},
_get_next_page_id: function () {
var currentID = this.currently_shown_page.id;
var currentIndex = _.findIndex(this.pages, function (page) {
return page.id === currentID;
});
var nextPage = this.pages[currentIndex + 1];
return nextPage ? nextPage.id : null;
},
_find_page_by_id: function (id) {
return _.find(this.pages, function (page) {
return page.id === id;
});
},
_find_menu_item_by_page_id: function (page_id) {
return _.find(this.menu_items, function (menu_item) {
var $menu_item = $(menu_item);
return $($menu_item.find('a')).attr('href') === '#' + page_id;
});
},
_display_page: function (page_id) {
if (!page_id) return;
var self = this;
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;
this._update_title();
this._render_page_status(this.currently_shown_page);
this._update_buttons();
this.planner.data.last_open_page = page_id;
utils.set_cookie(this.cookie_name, page_id, 8*60*60); // create cookie for 8h
this.$el.scrollTop("0");
this.$('textarea').each(function () {
dom.autoresize($(this), {parent: self});
});
},
// planner data functions
_get_values: function (page) {
// if no page_id, take the complete planner
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
var inputs = base_elem.find("textarea[id^='input_element'], input[id^='input_element'], select[id^='input_element'], button[id^='mark_button']");
_.each(inputs, function(elem){
var $elem = $(elem);
var tid = $elem.attr('id');
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'){
var ttype = $elem.attr('type');
if (ttype === 'checkbox' || ttype === 'radio'){
values[tid] = '';
if ($elem.is(':checked')){
values[tid] = 'checked';
}
}else{
values[tid] = $elem.val();
}
}
});
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="'+id+'"]');
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'){
var ttype = $elem.attr("type");
if (ttype === 'checkbox' || ttype === 'radio'){
if (val === 'checked') {
$elem.attr('checked', 'checked');
}
}else{
$elem.val(val);
}
}
});
_.each(this.pages, function (page) {
page.done = values[page.id];
self._render_page_status(page);
});
},
_update_planner: function () {
// update the planner.data with the inputs
var vals = this._get_values(this.currently_shown_page);
this.planner.data = _.extend(this.planner.data, vals);
// re compute the progress percentage
var total_pages = 0;
var done_pages = 0;
_.each(this.pages, function (page) {
if (! page.hide_mark_as_done) {
total_pages++;
}
if (page.done) {
done_pages++;
}
});
var percent = MIN_PROGRESS + parseInt(done_pages / total_pages * (100 - MIN_PROGRESS), 10);
this.set('progress', percent);
this.planner.progress = percent;
// save data and progress in database
this._save_planner_data();
},
_save_planner_data: function() {
return rpc.query({
model: 'web.planner',
method: 'write',
args: [this.planner.id, {'data': JSON.stringify(this.planner.data), 'progress': this.planner.progress}],
});
},
});
var PlannerLauncher = Widget.extend({
template: "PlannerLauncher",
sequence: 100, // force it to be the left-most item in the systray to prevent flickering as it is not displayed in all apps
events: {
"click": "show_dialog"
},
start: function () {
this.$progress = this.$(".progress");
this.$progressBar = this.$progress.find(".progress-bar");
this.$progress.tooltip({html: true, placement: 'bottom', delay: {'show': 500}});
this._loadPlannerDef = this._fetch_planner_data();
return this._super.apply(this, arguments);
},
_fetch_planner_data: function () {},
show_dialog: function () {
return this._loadPlannerDef.then((function () {
this.dialog = new PlannerDialog(this, undefined, this.planner);
this.dialog.on("planner_progress_changed", this, this._update_parent_progress_bar);
this.dialog.open();
}).bind(this));
},
_setup_for_planner: function (planner) {
this.planner = planner;
this.$progress.attr('data-original-title', this.planner.tooltip_planner);
this._update_parent_progress_bar(this.planner.progress || MIN_PROGRESS);
},
_update_parent_progress_bar: function (percent) {
this.$progress.toggleClass("o_hidden", percent >= 100);
this.$progressBar.css('width', percent + "%");
},
});
return {
PlannerDialog: PlannerDialog,
PlannerLauncher: PlannerLauncher
};
});