-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] web_tip: module for tip definition and display
Also added with this commit: crm: tip data web: hooks (events) for web_tip web_kanban: hooks (events) for web_tip
1 parent
a2adb48
commit 2bf6193
Showing
13 changed files
with
545 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<openerp> | ||
<data> | ||
<record model="web.tip" id="crm_tip_1"> | ||
<field name="title">Import from LinkedIn</field> | ||
<field name="description">Import your contacts directly from LinkedIn. It is much easier than creating them manually</field> | ||
<field name="action_id" ref="base.action_partner_form"/> | ||
<field name="model">res.partner</field> | ||
<field name="mode">kanban</field> | ||
<!-- TODO Add relevant selectors when linkedin button is implemented --> | ||
<field name="trigger_selector"></field> | ||
<field name="highlight_selector"></field> | ||
<field name="placement">bottom</field> | ||
</record> | ||
|
||
<record model="web.tip" id="crm_tip_2"> | ||
<field name="title"></field> | ||
<field name="description">Switch to the opportunities pipeline for this contact. Here you can access important related documents for this customer</field> | ||
<field name="action_id" ref="base.action_partner_form"/> | ||
<field name="model">res.partner</field> | ||
<field name="mode">form</field> | ||
<field name="trigger_selector">.oe_form_buttons_view:visible,div.oe_right.oe_button_box > button</field> | ||
<field name="highlight_selector">div.oe_right.oe_button_box:visible > button:nth-child(1)</field> | ||
<field name="placement">bottom</field> | ||
</record> | ||
|
||
<record model="web.tip" id="crm_tip_3"> | ||
<field name="title"></field> | ||
<field name="description">Switch back to the pipeline view. In one screen, view all your opportunities with the expected revenue for each stage.</field> | ||
<field name="model">crm.lead</field> | ||
<field name="type">opportunity</field> | ||
<field name="mode">form</field> | ||
<field name="trigger_selector">.oe_form_buttons_view:visible,.oe_breadcrumb_title > a.oe_breadcrumb_item</field> | ||
<field name="highlight_selector">.oe_breadcrumb_title > a.oe_breadcrumb_item:last</field> | ||
<field name="placement">bottom</field> | ||
</record> | ||
|
||
<record model="web.tip" id="crm_tip_4"> | ||
<field name="title"></field> | ||
<field name="description"><![CDATA[<b>Drag and drop</b>]]> your opportunity to the next stage. Our Sales Planner tool can help you define your pipeline stages.</field> | ||
<field name="model">crm.lead</field> | ||
<field name="mode">kanban</field> | ||
<field name="trigger_selector">.oe_kanban_record:visible</field> | ||
<field name="highlight_selector">table.oe_kanban_groups:last</field> | ||
<field name="end_selector">.oe_kanban_record</field> | ||
<field name="end_event">mouseup</field> | ||
<field name="placement">auto top</field> | ||
</record> | ||
</data> | ||
</openerp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import web_tip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
############################################################################## | ||
# | ||
# OpenERP, Open Source Management Solution | ||
# Copyright (C) 2013 OpenERP SA (<http://openerp.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/>. | ||
# | ||
############################################################################## | ||
{ | ||
'name': 'Tips', | ||
'category': 'Usability', | ||
'description': """ | ||
OpenERP Web tips. | ||
======================== | ||
""", | ||
'version': '0.1', | ||
'author': 'OpenERP SA', | ||
'depends': ['web'], | ||
'data': [ | ||
'security/ir.model.access.csv', | ||
'views/tip.xml', | ||
'web_tip_view.xml' | ||
], | ||
'auto_install': True | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_web_tip,access_web_tip,model_web_tip,,1,0,0,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
.oe_tip_overlay { | ||
top: 0; | ||
bottom: 0; | ||
left: 0; | ||
right: 0; | ||
position: absolute; | ||
opacity: 0.8; | ||
z-index: 1001; | ||
background-color: #000; | ||
background: -moz-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%); | ||
background: -webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9))); | ||
background: -webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%); | ||
background: -o-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%); | ||
background: -ms-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%); | ||
background: radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%); | ||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#66000000',endColorstr='#e6000000',GradientType=1); | ||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; | ||
filter: alpha(opacity=50); | ||
-webkit-transition: all 0.3s ease-out; | ||
-moz-transition: all 0.3s ease-out; | ||
-ms-transition: all 0.3s ease-out; | ||
-o-transition: all 0.3s ease-out; | ||
transition: all 0.3s ease-out; | ||
} | ||
|
||
.oe_tip_helper { | ||
position: absolute; | ||
z-index: 1008; | ||
background-color: #FFF; | ||
background-color: rgba(255,255,255,.9); | ||
border: 1px solid #777; | ||
border: 1px solid rgba(0,0,0,.5); | ||
border-radius: 4px; | ||
box-shadow: 0 2px 15px rgba(0,0,0,.4); | ||
-webkit-transition: all 0.3s ease-out; | ||
-moz-transition: all 0.3s ease-out; | ||
-ms-transition: all 0.3s ease-out; | ||
-o-transition: all 0.3s ease-out; | ||
transition: all 0.3s ease-out; | ||
} | ||
|
||
.oe_tip_close { | ||
padding: 5px 5px 10px 10px !important; | ||
margin-top: -15px; | ||
margin-right: -15px; | ||
} | ||
|
||
.oe_tip_fix_parent { | ||
z-index: auto !important; | ||
opacity: 1.0 !important; | ||
} | ||
|
||
.oe_tip_show_element { | ||
z-index: 1011 !important; | ||
position: relative; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
(function() { | ||
|
||
var instance = openerp; | ||
|
||
instance.web.Tip = instance.web.Class.extend({ | ||
init: function() { | ||
var self = this; | ||
self.tips = []; | ||
self.tip_mutex = new $.Mutex(); | ||
self.$overlay = null; | ||
self.$element = null; | ||
|
||
var Tips = new instance.web.Model('web.tip'); | ||
Tips.query(['title', 'description', 'action_id', 'model', 'type', 'mode', 'trigger_selector', | ||
'highlight_selector', 'end_selector', 'end_event', 'placement', 'is_consumed']) | ||
.all().then(function(tips) { | ||
self.tips = tips; | ||
}) | ||
; | ||
|
||
instance.web.bus.on('action', this, function(action) { | ||
self.on_action(action); | ||
}); | ||
|
||
instance.web.bus.on('view_shown', this, function(view) { | ||
if (_.keys(view.fields_view).length === 0) { | ||
view.on('view_loaded', this, function(fields_view) { | ||
self.on_view(view); | ||
}); | ||
} else { | ||
self.on_view(view); | ||
} | ||
|
||
view.on('switch_mode', this, function() { | ||
}); | ||
}); | ||
|
||
instance.web.bus.on('view_switch_mode', this, function(viewManager, mode) { | ||
self.on_switch(viewManager, mode); | ||
}); | ||
|
||
instance.web.bus.on('form_view_shown', this, function(formView) { | ||
self.on_form_view(formView); | ||
}); | ||
|
||
instance.web.bus.on('form_view_saved', this, function(formView) { | ||
self.on_form_view(formView); | ||
}); | ||
}, | ||
|
||
// stub | ||
on_action: function(action) { | ||
var self = this; | ||
var action_id = action.id; | ||
var model = action.res_model; | ||
}, | ||
|
||
on_view: function(view) { | ||
var self = this; | ||
var fields_view = view.fields_view; | ||
var action_id = view.ViewManager.action ? view.ViewManager.action.id : null; | ||
var model = fields_view.model; | ||
|
||
// kanban | ||
if(fields_view.type === 'kanban') { | ||
var dataset_def = $.Deferred(); | ||
var groups_def = $.Deferred(); | ||
view.on("kanban_dataset_processed", self, function() { | ||
var length = view.dataset.ids.length; | ||
dataset_def.resolve(length); | ||
}); | ||
view.on('kanban_groups_processed', self, function() { | ||
groups_def.resolve(); | ||
}); | ||
dataset_def.done(function(length) { | ||
self.eval_tip(action_id, model, fields_view.type); | ||
}); | ||
groups_def.done(function() { | ||
self.eval_tip(action_id, model, fields_view.type); | ||
}); | ||
} | ||
}, | ||
|
||
on_form_view: function(formView) { | ||
var self = this; | ||
var model = formView.model; | ||
var type = formView.datarecord.type ? formView.datarecord.type : null; | ||
var mode = 'form'; | ||
self.eval_tip(null, model, mode, type); | ||
}, | ||
|
||
// stub | ||
on_switch: function (viewManager, mode) { | ||
var self = this; | ||
var action = viewManager.action; | ||
var action_id = action.id; | ||
var model = action.res_model; | ||
}, | ||
|
||
eval_tip: function(action_id, model, mode, type) { | ||
var self = this; | ||
var filter = {}; | ||
var valid_tips = []; | ||
var tips = []; | ||
if (action_id) { | ||
valid_tips = _.filter(self.tips, function (tip) { | ||
return tip.action_id[0] === action_id; | ||
}); | ||
} | ||
|
||
filter.model = model; | ||
filter.mode = mode; | ||
tips = _.where(self.tips, filter); | ||
if (type) { | ||
tips = _.filter(tips, function(tip) { | ||
if (!tip.type) { | ||
return true; | ||
} | ||
return tip.type === type; | ||
}); | ||
} | ||
|
||
valid_tips = _.uniq(valid_tips.concat(tips)); | ||
_.each(valid_tips, function(tip) { | ||
if (!tip.is_consumed) { | ||
self.add_tip(tip); | ||
} | ||
}); | ||
}, | ||
|
||
|
||
add_tip: function(tip) { | ||
var self = this; | ||
self.tip_mutex.exec(function() { | ||
return $.when(self.do_tip(tip)); | ||
}); | ||
}, | ||
|
||
do_tip: function (tip) { | ||
var self = this; | ||
var def = $.Deferred(); | ||
var Tips = new instance.web.Model('web.tip'); | ||
var highlight_selector = tip.highlight_selector; | ||
var triggers = tip.trigger_selector ? tip.trigger_selector.split(',') : []; | ||
var trigger_tip = true; | ||
|
||
if(!$(highlight_selector).length > 0) { | ||
return def.reject(); | ||
} | ||
for (var i = 0; i < triggers.length; i++) { | ||
if(!$(triggers[i]).length > 0) { | ||
trigger_tip = false; | ||
} | ||
} | ||
|
||
if (trigger_tip) { | ||
self.$element = $(highlight_selector).first(); | ||
var _top = self.$element.offset().top -5; | ||
var _left = self.$element.offset().left -5; | ||
var _width = self.$element.outerWidth() + 10; | ||
var _height = self.$element.outerHeight() + 10; | ||
|
||
self.$helper = $("<div>", { class: 'oe_tip_helper' }); | ||
self.$element.after(self.$helper); | ||
self.$helper.offset({top: _top , left: _left}); | ||
self.$helper.width(_width); | ||
self.$helper.height(_height); | ||
|
||
self.$overlay = $("<div>", { class: 'oe_tip_overlay' }); | ||
$('body').append(self.$overlay); | ||
self.$element.addClass('oe_tip_show_element'); | ||
|
||
// fix the stacking context problem | ||
_.each(self.$element.parentsUntil('body'), function(el) { | ||
var zIndex = $(el).css('z-index'); | ||
var opacity = parseFloat($(el).css('opacity')); | ||
|
||
if (/[0-9]+/.test(zIndex) || opacity < 1) { | ||
$(el).addClass('oe_tip_fix_parent'); | ||
} | ||
}); | ||
|
||
self.$element.popover({ | ||
placement: tip.placement, | ||
title: tip.title, | ||
content: tip.description, | ||
html: true, | ||
container: 'body', | ||
}).popover("show"); | ||
|
||
var $cross = $('<button type="button" class="close">×</button>'); | ||
$cross.addClass('oe_tip_close'); | ||
|
||
if (tip.title) { | ||
$('.popover-title').prepend($cross); | ||
} else { | ||
$('.popover-content').prepend($cross); | ||
} | ||
|
||
// consume tip | ||
tip.end_selector = tip.end_selector ? tip.end_selector : tip.highlight_selector; | ||
$(tip.end_selector).one(tip.end_event, function($ev) { | ||
self.end_tip(tip); | ||
def.resolve(); | ||
}); | ||
|
||
// dismiss tip | ||
$cross.on('click', function($ev) { | ||
self.end_tip(tip); | ||
def.resolve(); | ||
}); | ||
self.$overlay.on('click', function($ev) { | ||
self.end_tip(tip); | ||
def.resolve(); | ||
}); | ||
$(document).on('keyup.web_tip', function($ev) { | ||
if ($ev.which === 27) { // esc | ||
self.end_tip(tip); | ||
def.resolve(); | ||
} | ||
}); | ||
} else { | ||
def.reject(); | ||
} | ||
return def; | ||
}, | ||
|
||
end_tip: function(tip) { | ||
var self = this; | ||
var Tips = new instance.web.Model('web.tip'); | ||
self.$element.popover('destroy'); | ||
self.$overlay.remove(); | ||
self.$helper.remove(); | ||
self.$element.removeClass('oe_tip_show_element'); | ||
_.each($('.oe_tip_fix_parent'), function(el) { | ||
$(el).removeClass('oe_tip_fix_parent'); | ||
}); | ||
$(document).off('keyup.web_tip'); | ||
Tips.call('consume', [tip.id], {}); | ||
tip.is_consumed = true; | ||
} | ||
}); | ||
|
||
instance.web.WebClient = instance.web.WebClient.extend({ | ||
show_application: function() { | ||
this._super(); | ||
this.tip_handler = new instance.web.Tip(); | ||
} | ||
}); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<openerp> | ||
<data> | ||
<template id="assets_backend" name="tip assets" inherit_id="web.assets_backend"> | ||
<xpath expr="." position="inside"> | ||
<link rel="stylesheet" href="/web_tip/static/src/css/tip.css"/> | ||
<script type="text/javascript" src="/web_tip/static/src/js/tip.js"></script> | ||
</xpath> | ||
</template> | ||
</data> | ||
</openerp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
############################################################################## | ||
# | ||
# OpenERP, Open Source Management Solution | ||
# Copyright (C) 2009-Today OpenERP SA (<http://www.openerp.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.osv import osv, fields | ||
|
||
|
||
class tip(osv.Model): | ||
_name = 'web.tip' | ||
_description = 'Tips' | ||
|
||
def _is_consumed(self, cr, uid, ids, fields, arg, context=None): | ||
results = {} | ||
records = self.read(cr, uid, ids, ['user_ids']) | ||
for rec in records: | ||
if uid in rec['user_ids']: | ||
results[rec['id']] = True | ||
else: | ||
results[rec['id']] = False | ||
return results | ||
|
||
_columns = { | ||
'title': fields.char('Tip title'), | ||
'description': fields.html('Tip Description', required=True), | ||
'action_id': fields.many2one('ir.actions.act_window', string="Action", | ||
help="The action that will trigger the tip"), | ||
'model': fields.char("Model", help="Model name on which to trigger the tip, e.g. 'res.partner'."), | ||
'type': fields.char("Type", help="Model type, e.g. lead or opportunity for crm.lead"), | ||
'mode': fields.char("Mode", help="Mode, e.g. kanban, form"), | ||
'trigger_selector': fields.char('Trigger selector', help='CSS selectors used to trigger the tip, separated by a comma (ANDed).'), | ||
'highlight_selector': fields.char('Highlight selector', help='CSS selector for the element to highlight'), | ||
'end_selector': fields.char('End selector', help='CSS selector used to end the tip'), | ||
'end_event': fields.char('End event', help='Event to end the tip'), | ||
'placement': fields.char('Placement', help='Popover placement, bottom, top, left or right'), | ||
'user_ids': fields.many2many('res.users', string='Consumed by'), | ||
'is_consumed': fields.function(_is_consumed, type='boolean', string='Tip consumed') | ||
} | ||
|
||
_defaults = { | ||
'placement': 'auto', | ||
'end_event': 'click' | ||
} | ||
|
||
def consume(self, cr, uid, ids, context=None): | ||
return self.write(cr, uid, ids, { | ||
'user_ids': [(4, uid)] | ||
}, context=context) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<openerp> | ||
<data> | ||
<record id="edit_tip_form" model="ir.ui.view"> | ||
<field name="model">web.tip</field> | ||
<field name="arch" type="xml"> | ||
<form string="Menu"> | ||
<sheet> | ||
<group> | ||
<group> | ||
<field name="title"/> | ||
<field name="description"/> | ||
<field name="action_id"/> | ||
</group> | ||
<group> | ||
<field name="model"/> | ||
<field name="type"/> | ||
<field name="mode"/> | ||
</group> | ||
</group> | ||
<group> | ||
<field name="trigger_selector"/> | ||
<field name="highlight_selector"/> | ||
<field name="end_selector"/> | ||
<field name="end_event"/> | ||
<field name="placement"/> | ||
</group> | ||
<notebook> | ||
<page string="Consumed by"> | ||
<field name="user_ids"/> | ||
</page> | ||
</notebook> | ||
</sheet> | ||
</form> | ||
</field> | ||
</record> | ||
<record id="edit_tip_list" model="ir.ui.view"> | ||
<field name="model">web.tip</field> | ||
<field eval="8" name="priority"/> | ||
<field name="arch" type="xml"> | ||
<tree string="Menu"> | ||
<field name="model"/> | ||
<field name="mode"/> | ||
</tree> | ||
</field> | ||
</record> | ||
<record id="edit_tip_search" model="ir.ui.view"> | ||
<field name="name">web.tip.search</field> | ||
<field name="model">web.tip</field> | ||
<field name="arch" type="xml"> | ||
<search string="Tip"> | ||
<field name="model"/> | ||
<field name="mode"/> | ||
</search> | ||
</field> | ||
</record> | ||
<record id="edit_tip_action" model="ir.actions.act_window"> | ||
<field name="name">Tips</field> | ||
<field name="res_model">web.tip</field> | ||
<field name="view_type">form</field> | ||
<field name="view_id" ref="edit_tip_list"/> | ||
<field name="search_view_id" ref="edit_tip_search"/> | ||
</record> | ||
<menuitem action="edit_tip_action" id="menu_tip_action" parent="base.next_id_2" sequence="5"/> | ||
</data> | ||
</openerp> |