Browse Source

[IMP] help_popup module

pull/417/head
David Beal 9 years ago
parent
commit
a6a99ffeac
  1. 20
      help_popup/README.rst
  2. 24
      help_popup/__openerp__.py
  3. 43
      help_popup/demo/help.xml
  4. 142
      help_popup/model.py
  5. 46
      help_popup/report/all.xml
  6. 40
      help_popup/report/help.xml
  7. 9
      help_popup/report/report.xml
  8. 26
      help_popup/static/src/js/popup_help.js
  9. 5
      help_popup/static/src/xml/popup_help.xml
  10. 80
      help_popup/views/action_view.xml

20
help_popup/README.rst

@ -6,24 +6,20 @@ Help Popup
=========== ===========
This module adds an html help popup on each model action. This module adds an html help popup on each model action.
Two help fields are added to actions: enduser_help (html widget)
and advanced_help.
Installation
============
It was tested on Odoo 8.0 branch.
It brings to end users inline documentation.
Some parts of the documentation can be modified by anyone (with proper rights).
Configuration Configuration
============= =============
Go to the action of your choice to add some help content
or put data in some modules.
* Go to any view and click on the `?` near the title view.
* Edit the html field to add content
To display the button which open the popup, enduser_help or advanced_help field
should be set to any value.
* You can provide documentation with this module by appending data
in the field advanced_help (relative to action) or advanced_help_model
if your help must be associated to model instead of action
Usage Usage

24
help_popup/__openerp__.py

@ -1,27 +1,10 @@
# coding: utf-8 # coding: utf-8
##############################################################################
#
# Odoo, Open Source Management Solution
# Copyright (C) 2015-TODAY Akretion (<http://www.akretion.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# © 2015 David BEAL @ Akretion <david.beal@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{ {
'name': 'Help Popup', 'name': 'Help Popup',
'version': '8.0.0.5.0',
'version': '8.0.2.0.0',
'author': 'Akretion, Odoo Community Association (OCA)', 'author': 'Akretion, Odoo Community Association (OCA)',
'depends': [ 'depends': [
'web', 'web',
@ -32,6 +15,7 @@
'views/action_view.xml', 'views/action_view.xml',
'report/report.xml', 'report/report.xml',
'report/help.xml', 'report/help.xml',
'report/all.xml',
], ],
'demo': [ 'demo': [
'demo/help.xml', 'demo/help.xml',

43
help_popup/demo/help.xml

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data noupdate="1">
<data>
<record id="base.action_partner_form" model="ir.actions.act_window"> <record id="base.action_partner_form" model="ir.actions.act_window">
<field name="enduser_help"><![CDATA[ <field name="enduser_help"><![CDATA[
@ -20,14 +20,17 @@ I'm displayed in a Qweb html report
Don't hesitate to customized me with your own words and syntax Don't hesitate to customized me with your own words and syntax
</p> </p>
<p>You can write any html tag. Here is an image with img tag</p>
<img src="http://www.akretion.com/sites/50443990c3c67e1bf3000004/theme/images/logo.png"/>
]]></field> ]]></field>
</record> </record>
</data>
<data noupdate="0">
<record id="base.action_partner_form" model="ir.actions.act_window"> <record id="base.action_partner_form" model="ir.actions.act_window">
<field name="advanced_help"><![CDATA[ <field name="advanced_help"><![CDATA[
<b>Hi developers,</b>
<b>Hi Odoo community,</b>
<br/> <br/>
<br/> <br/>
@ -35,18 +38,42 @@ Don't hesitate to customized me with your own words and syntax
I'm the field 'advanced_help' in the customer action also displayed in Qweb report. I'm the field 'advanced_help' in the customer action also displayed in Qweb report.
</p> </p>
<p> <p>
<b>Akretion</b> wrote these words to explain my main purpose:
I wrote these words to explain the main purpose:
<blockquote> <blockquote>
Allows to developers to write documentation on their work.
Odoo community companies can insert their documenation here with data in their modules. <br><br>
Then, any end users can see this documentation in one click.
<br>
End users can also display and print documentation about an entire menu.
</blockquote> </blockquote>
</p> </p>
<p> <p>
</p> </p>
<p>You can write any html tag. Here is an image with img tag</p>
<img src="http://www.akretion.com/sites/50443990c3c67e1bf3000004/theme/images/logo.png"/>
]]></field>
</record>
<record id="base.action_partner_category_form"
model="ir.actions.act_window">
<field name="enduser_help"><![CDATA[
Hi all,<br><br>
A supplier can have several specialities.
<br><br>
Use these multicategories to classify your partners
]]></field>
</record>
<record id="base.action_res_bank_form"
model="ir.actions.act_window">
<field name="enduser_help"><![CDATA[
Hi all,<br>
<br><br>
Who does not want to rob a bank?
<br><br>
;-)
]]></field> ]]></field>
</record> </record>

142
help_popup/model.py

@ -1,35 +1,127 @@
# coding: utf-8 # coding: utf-8
##############################################################################
#
# Odoo, Open Source Management Solution
# Copyright (C) 2015-TODAY Akretion (<http://www.akretion.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields
# © 2015 David BEAL @ Akretion <david.beal@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import _, api, models, fields
class IrActionsActwindow(models.Model):
_inherit = 'ir.actions.act_window'
class ErpHelp(models.AbstractModel):
_name = 'erp.help'
enduser_help = fields.Html( enduser_help = fields.Html(
string="End User Help", string="End User Help",
help="Use this field to add custom content for documentation purpose\n" help="Use this field to add custom content for documentation purpose\n"
"mainly by power users ") "mainly by power users ")
advanced_help = fields.Text( advanced_help = fields.Text(
string="Advanced Help",
string="Advanced Help", groups='base.group_no_one',
help="Use this field to add custom content for documentation purpose\n" help="Use this field to add custom content for documentation purpose\n"
"mainly by developers")
"mainly by developers or consultants")
class IrModel(models.Model):
_inherit = ['ir.model', 'erp.help']
_name = 'ir.model'
class IrActionsActwindow(models.Model):
_inherit = ['ir.actions.act_window', 'erp.help']
_name = 'ir.actions.act_window'
_rpt_menu = False
enduser_help_model = fields.Html(
string='Enduser Help from Model', store="True",
compute='_compute_model_help', inverse='_inverse_model_help',
help="")
advanced_help_model = fields.Text(
string='Advanced Help from model', store="True",
compute='_compute_model_help', inverse='_inverse_model_help',
help="")
action_help = fields.Boolean(string="Display Action Help")
help_has_content = fields.Boolean(
string="Content in help", compute='_compute_contains_help',
help="One of the help has content")
@api.one
@api.depends('enduser_help', 'advanced_help',
'enduser_help_model', 'advanced_help_model')
def _compute_contains_help(self):
if (self.enduser_help or self.enduser_help_model or
self.advanced_help or self.advanced_help_model):
self.help_has_content = True
else:
self.help_has_content = False
@api.multi
def _compute_model_help(self):
for rec in self:
model = rec.env['ir.model'].search([('model', '=', rec.res_model)])
rec.enduser_help_model = model.enduser_help
rec.advanced_help_model = model.advanced_help
def _inverse_model_help(self):
for rec in self:
model = rec.env['ir.model'].search([('model', '=', rec.res_model)])
model.enduser_help = rec.enduser_help_model
model.advanced_help = rec.advanced_help_model
@api.multi
def open_help_popup(self):
""" Open in a new tab instead of in popup"""
self.ensure_one()
return {
'name': _('Open help for this action'),
'type': 'ir.actions.act_url',
'url': 'report/html/help_popup.tpl_help/%s' % self.id,
'target': 'new',
}
@api.model
def get_help_actions(self):
""" called by the template"""
self._rpt_menu = self.get_main_menu()
menu_names = self.get_menu_names(self._rpt_menu)
actions = self.search([
('id', 'in', menu_names.keys()),
'|', '|', '|',
('enduser_help', '!=', False),
('enduser_help_model', '!=', False),
('advanced_help', '!=', False),
('advanced_help_model', '!=', False),
])
return actions
@api.model
def get_main_menu(self):
self._rpt_menu = False
ir_vals = self.env['ir.values'].search([
('key2', '=', 'tree_but_open'),
('key', '=', 'action'),
('res_id', '>', 0),
('value', '=', 'ir.actions.act_window,%s' % self.id),
])
if ir_vals:
# we only keep the first menu beacause we have no info on menu_id
self._rpt_menu = self.env['ir.ui.menu'].browse(ir_vals[0].res_id)
while self._rpt_menu.parent_id:
self._rpt_menu = self._rpt_menu.parent_id
return self._rpt_menu
@api.model
def get_menu_names(self, main_menu):
""" @return dict {action_id: 'menu name'} """
menus = self.env['ir.ui.menu'].search(
[('id', 'child_of', main_menu.id)])
ir_vals = self.env['ir.values'].search([
('key2', '=', 'tree_but_open'),
('key', '=', 'action'),
('res_id', 'in', menus.ids),
('value', 'like', 'ir.actions.act_window,%'),
])
map_menu = {x.id: x.name for x in menus}
return {int(x.value[22:]): map_menu[x.res_id] for x in ir_vals}
def _anchorize(self, string):
""" called by template """
for char in ["'", '"', ' ']:
string = string.replace(char, '-')
return string

46
help_popup/report/all.xml

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<template id="all_help">
<t t-call="report.html_container">
<t t-call="report.internal_layout">
<t t-foreach="docs" t-as="o">
<div class="page">
<t t-set="actions" t-value="o.get_help_actions()"/>
<h2 class="text-center" t-if="o._rpt_menu" t-raw="o._rpt_menu.name"/>
<ul>
<t t-foreach="actions" t-as="act">
<li>
<a t-attf-href="#-{{ o._anchorize(act.name) }}" t-raw='act.name'/>
</li>
</t>
</ul>
<t t-foreach="actions" t-as="act">
<h2 t-attf-id="-{{ o._anchorize(act.name) }}" t-raw='act.name'/>
<div class="bg-warning" t-if="act.enduser_help" t-raw="act.enduser_help"/>
<div class="bg-warning" t-if="act.enduser_help_model" t-raw="act.enduser_help_model"/>
<hr width="70%"/>
<div t-if="act.advanced_help" t-raw="act.advanced_help"/>
<div t-if="act.advanced_help_model" t-raw="act.advanced_help_model"/>
</t>
<hr width="70%"/>
</div>
<!--end foreach-->
</t>
</t>
</t>
</template>
</data>
</openerp>

40
help_popup/report/help.xml

@ -13,18 +13,34 @@
<div class="page"> <div class="page">
<div t-raw="o.enduser_help"/>
<hr width="70%"/>
<h3 t-if="o.advanced_help">Help from developer</h3>
<div t-raw="o.advanced_help"/>
<hr width="70%"/>
<h3 t-if="o.help">Help from Odoo</h3>
<div t-raw="o.help"/>
<div class="pull-right bg-sucess">
<t t-set="action_id" t-value="o.env.ref('help_popup.action_help_popup_form').id" />
<a t-attf-href="/report/html/help_popup.all_help/{{ o.id }}" class="btn btn-success btn-xs" title="Click to see documentation for the whole menu">
<span t-raw="o.get_main_menu().name"/> help</a>
<a t-attf-href="/web#id={{ o.id }}&amp;view_type=form&amp;model=ir.actions.act_window&amp;action={{ action_id }}" class="btn btn-danger btn-xs" title="Edit this documentation">Edit</a>
<br/>
</div>
<br/>
<div class="bg-warning" t-if="o.enduser_help_model or o.enduser_help">
<div class="oe_text_center label label-info">Internal</div>
<div t-if="o.enduser_help_model" t-raw="o.enduser_help_model"/>
<div t-if="o.enduser_help" t-raw="o.enduser_help"/>
<hr width="70%"/>
</div>
<div t-if="o.advanced_help_model or o.advanced_help">
<div class="oe_text_center label label-info" title="Odoo Community Association (OCA) maintains several modules with high quality level">Odoo Community</div>
<div t-if="o.advanced_help_model" t-raw="o.advanced_help_model"/>
<div t-if="o.advanced_help" t-raw="o.advanced_help"/>
<hr width="70%"/>
</div>
<div t-if="o.help">
<div class="oe_text_center label label-info" title="Help from Odoo editor">Odoo</div>
<div t-if="o.help" t-raw="o.help"/>
<hr width="70%"/>
</div>
<div>Use Ctrl + P to print this document</div>
</div> </div>
<!--end foreach--> <!--end foreach-->

9
help_popup/report/report.xml

@ -3,11 +3,18 @@
<openerp> <openerp>
<data> <data>
<report id="report_help_popup"
<report id="report_help_popup"
model="ir.actions.act_window" model="ir.actions.act_window"
string="Contextual Help" string="Contextual Help"
name="help_popup.tpl_help" name="help_popup.tpl_help"
report_type="qweb-html"/> report_type="qweb-html"/>
<report id="report_all_help"
model="ir.actions.act_window"
string="All Contextual Help"
name="help_popup.all_help"
report_type="qweb-html"/>
</data> </data>
</openerp> </openerp>

26
help_popup/static/src/js/popup_help.js

@ -6,24 +6,40 @@ openerp.help_popup = function(instance, local) {
do_create_view: function(view_type) { do_create_view: function(view_type) {
var self = this; var self = this;
var res = self._super(view_type); var res = self._super(view_type);
var params = 'height=650, width=900, location=no, ';
params += 'resizable=yes, menubar=yes, scrollbars=yes';
self.$el.find('span.update_help').each(function () {
var $elem = $(this);
if ($elem.data('click-init')) {
return true;
}
$elem.data('click-init', true);
console.log('me ' + self)
if (self.action.id == undefined || self.action.help_has_content == true) {
self.$el.find('span.update_help').hide()
}
$elem.on('click', function(e) {
path = self.action.id;
my_window = window.open('/web#id='+ path +'&view_type=form&model=ir.actions.act_window&action=help_popup.action_help_popup_form', 'Help', params);
// allows to back to the window if opened previoulsy
setTimeout('my_window.focus()', 1);
});
return true;
});
self.$el.find('span.view_help').each(function () { self.$el.find('span.view_help').each(function () {
var $elem = $(this); var $elem = $(this);
if ($elem.data('click-init')) { if ($elem.data('click-init')) {
return true; return true;
} }
$elem.data('click-init', true); $elem.data('click-init', true);
if (self.action.id == undefined || (self.action.advanced_help == '' && self.action.enduser_help == '')) {
if (self.action.id == undefined || self.action.help_has_content == false) {
self.$el.find('span.view_help').hide() self.$el.find('span.view_help').hide()
} }
$elem.on('click', function(e) { $elem.on('click', function(e) {
var params = 'height=650, width=800, location=no, ';
params += 'resizable=yes, menubar=yes';
path = self.action.id; path = self.action.id;
my_window = window.open('/report/html/help_popup.tpl_help/' + path, 'Help', params); my_window = window.open('/report/html/help_popup.tpl_help/' + path, 'Help', params);
// allows to back to the window if opened previoulsy
setTimeout('my_window.focus()', 1); setTimeout('my_window.focus()', 1);
}); });
return true; return true;
}); });

5
help_popup/static/src/xml/popup_help.xml

@ -2,7 +2,10 @@
<templates> <templates>
<t t-name="ViewManagerAction" t-extend="ViewManagerAction"> <t t-name="ViewManagerAction" t-extend="ViewManagerAction">
<t t-jquery="h2.oe_view_title" t-operation="before"> <t t-jquery="h2.oe_view_title" t-operation="before">
<span> &amp;nbsp; </span><span class="oe_button oe_highlight view_help">?</span>
<span> &amp;nbsp; </span>
<span class="btn btn-primary btn-sm view_help"
title="Display help content">?</span>
<span class="btn btn-link btn-xs update_help" title="Define help content">?</span>
</t> </t>
</t> </t>
</templates> </templates>

80
help_popup/views/action_view.xml

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data>
<data>
<record id="view_window_action_form" model="ir.ui.view">
<record id="view_window_action_form" model="ir.ui.view">
<field name="model">ir.actions.act_window</field> <field name="model">ir.actions.act_window</field>
<field name="inherit_id" <field name="inherit_id"
ref="base.view_window_action_form"/> ref="base.view_window_action_form"/>
@ -12,7 +12,79 @@
<field name="advanced_help"/> <field name="advanced_help"/>
</field> </field>
</field> </field>
</record>
</record>
</data>
<record id="view_window_action_help_form" model="ir.ui.view">
<field name="model">ir.actions.act_window</field>
<field name="arch" type="xml">
<form>
<sheet>
<group name="main" col="4">
<field name="name" attrs="{'readonly': True}"/>
<field name="res_model" attrs="{'readonly': True}"/>
<field name="action_help"/>
<button name="open_help_popup" type="object" string="Help"
class="oe_highlight"/><span/>
<!-- <field name="help_has_content"/> -->
<separator string="End users help" colspan="4"/>
<field name="enduser_help_model" colspan="4" nolabel="1"/>
<div attrs="{'invisible': [('action_help', '=', False)]}"
class="alert alert-warning"
colspan="4">Help field below is only used by action (i.e. action for 'customer' is different than action for 'supplier' but share the same model)</div>
<field name="enduser_help" colspan="4" nolabel="1"
attrs="{'invisible': [('action_help', '=', False)]}"/>
<separator string="Odoo community help" colspan="4"/>
<field name="advanced_help_model" attrs="{'readonly': True}"
colspan="4" nolabel="1"/>
<field name="advanced_help" attrs="{'readonly': True}"
colspan="4" nolabel="1"/>
<span colspan="4"></span>
<separator string="Standard Odoo help" colspan="4"/>
<field name="help" nolabel="1" attrs="{'readonly': True}" colspan="4"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_window_action_help_tree" model="ir.ui.view">
<field name="model">ir.actions.act_window</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="res_model"/>
<field name="enduser_help"/>
<field name="advanced_help"/>
<field name="help"/>
</tree>
</field>
</record>
<record id="action_help_popup_form" model="ir.actions.act_window">
<field name="name">Help on Action</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.actions.act_window</field>
<field name="view_mode">form</field>
<field name="target">current</field>
<!-- <field name="context">{'search_default_customer':1, 'restrict_kind': ['individu', 'incorpo'], 'default_kind':'incorpo'}</field> -->
</record>
<record model="ir.actions.act_window.view" id="act_help_popup_formr_view_form">
<field name="act_window_id" ref="action_help_popup_form"/>
<field name="view_mode">form</field>
<field name="sequence" eval="10"/>
<field name="view_id" ref="view_window_action_help_form"/>
</record>
<record model="ir.actions.act_window.view" id="act_help_popup_formr_view_tree">
<field name="act_window_id" ref="action_help_popup_form"/>
<field name="view_mode">tree</field>
<field name="sequence" eval="5"/>
<field name="view_id" ref="view_window_action_help_tree"/>
</record>
<menuitem id="action_with_help" sequence="100"
action="action_help_popup_form" name="Help"
parent="base.menu_config"/>
</data>
</openerp> </openerp>
Loading…
Cancel
Save