Merge pull request #95 from yelizariev/8.0-web_last_viewed_records

8.0 web_last_viewed_records
pull/102/head
Pedro M. Baeza 2015-03-20 01:31:56 +01:00
commit 02d82a468f
7 changed files with 320 additions and 0 deletions

View File

@ -0,0 +1,46 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License
Last viewed records
===================
The module shows links to last viewed records and pages.
The module doesn't affect on server performance, because it uses
browser's localStorage to save history. But dissadvantage is that
history is not synced accross browsers.
Usage
=====
There are no any settings to configure. Just install module and continue to use odoo in a usual way. You will see links to last visited pages.
For further information, please visit:
* https://yelizariev.github.io/odoo/module/2015/02/18/last-viewed-records.html
Known issues / Roadmap
======================
* FIXME: doesn't work in a res.config view
Credits
=======
Contributors
------------
* Ivan Yelizariev <yelizariev@it-projects.info>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

View File

@ -0,0 +1,15 @@
{
'name': 'Last viewed records',
'version': '1.0.0',
'author': 'Ivan Yelizariev, Odoo Community Association (OCA)',
'category': 'Base',
'website': 'https://yelizariev.github.io',
'depends': ['web', 'mail'],
'data': [
'views.xml',
],
'qweb': [
"static/src/xml/main.xml",
],
'installable': True
}

View File

@ -0,0 +1,44 @@
.oe_last_viewed_item.selected{
font-weight:bold;
}
.openerp .oe_last_viewed_item .oe_e {
font-size: 22px;
font-weight: 300 !important;
}
.openerp .oe_last_viewed_item .list:after, .openerp .oe_last_viewed_item .tree:after {
padding: 2px;
content: "i";
}
.openerp .oe_last_viewed_item .form:after {
content: "m";
}
.openerp .oe_last_viewed_item .graph:after {
font-family: "mnmliconsRegular" !important;
font-size: 21px;
font-weight: 300 !important;
content: "}";
top: -2px;
position: relative;
}
.openerp .oe_last_viewed_item .gantt:after {
font-family: "mnmliconsRegular" !important;
font-size: 21px;
font-weight: 300 !important;
content: "y";
top: -2px;
position: relative;
}
.openerp .oe_last_viewed_item .calendar:after {
content: "P";
}
.openerp .oe_last_viewed_item .kanban:after {
content: "k";
}
.openerp .oe_last_viewed_item .diagram:after {
content: "f";
}
.oe_last_viewed_icon.fa{
display: inline;
}

View File

@ -0,0 +1,180 @@
openerp.web_last_viewed_records = function(instance){
var localStorage = {};
if (typeof window.localStorage !== "undefined"){
localStorage = window.localStorage;
}
instance.web.ActionManager.include({
last_viewed_history_var: 'odoo_last_viewed',
last_viewed_history_size: 8,
init:function(){
this._super.apply(this, arguments);
this.last_viewed = [];
var last_viewed = this.load_last_viewed_history().last_viewed || [];
for (var i=last_viewed.length-1; i>=0; i--){
this.unshift_last_viewed(last_viewed[i]);
}
},
add_last_viewed: function(item){
if (_.any(this.last_viewed, function(x){
if (x['title'] != item['title'] ||
x['view_type'] != item['view_type'] ||
x['url']['model'] != item['url']['model'])
return false;
if (x['view_type'] == 'form' && x['id'] != item['id'])
return false;
return true;
}))
return;
//save json data to localStorage
var data = this.load_last_viewed_history();
data.last_viewed = data.last_viewed || []
data.last_viewed.unshift(item);
data.last_viewed.splice(this.last_viewed_history_size);
this.save_last_viewed_history(data);
this.unshift_last_viewed(item);
},
unshift_last_viewed: function(item){
var self = this;
this.last_viewed.unshift(item);
this.last_viewed.splice(this.last_viewed_history_size);
},
load_last_viewed_history: function(){
var data = localStorage[this.last_viewed_history_var] || '{}';
return JSON.parse(data);
},
save_last_viewed_history: function(data){
localStorage[this.last_viewed_history_var] = JSON.stringify(data);
},
// icon map: http://fortawesome.github.io/Font-Awesome/icons/
_model2icon: {
'account.analytic.account':'fa-book',
'account.invoice':'fa-pencil-square-o',
'calendar.event':'fa-calendar',
'crm.lead':'fa-star',
'crm.phonecall':'fa-phone',
'hr.employee':'fa-male',
'hr.payslip':'fa-money',
'hr_timesheet_sheet.sheet': 'fa-clock-o',
'ir.attachment': 'fa-file-o',
'ir.module.module':'fa-plus-circle',
'product.product': 'fa-sitemap',
'project.issue':'fa-bug',
'project.project':'fa-folder',
'project.task':'fa-tasks',
'purchase.order':'fa-shopping-cart',
'purchase.order.line':'fa-shopping-cart',
'res.company': 'fa-building-o',
'res.groups': 'fa-users',
'res.partner':'fa-user',
'res.user': 'fa-user-plus',
'sale.order':'fa-strikethrough',
},
get_last_viewed_title: function(){
var titles = [];
for (var i = 0; i < this.last_viewed.length; i += 1) {
var item = this.last_viewed[i];
var label = item.title;
var selected = false;//item.action.id == this.inner_action.id && item.action.res_id == this.inner_action.res_id;
var view_type = item.view_type;
var url = $.param(item.url);
var model = item.url.model;
var title = model;
var icon = this._model2icon[model];
if (!icon && /\.settings/.test(model))
icon = 'c';
if (icon)
icon = _.str.sprintf('<span class="oe_last_viewed_icon fa %s"></span>', icon);
titles.push(_.str.sprintf('<a title="%s" href="#%s" class="oe_last_viewed_item %s">%s&nbsp;%s&nbsp;<span class="oe_e %s"/></a>',
title,
url,
selected && 'selected' || '',
icon || '',
label,
view_type != 'form' && view_type || ''
));
}
return titles.join(' <span class="oe_fade">|</span>&nbsp;');
},
})
instance.web.ViewManagerAction.include({
try_add_last_viewed: function(view_type){
var view = this.views[view_type];
var act = view.options.action;
if (!act.type)
return false;
if (act.target == 'new')
//skip widgets and popup forms
return false;
var url = {
'view_type': view_type,
'model': act.res_model,
'menu_id': act.menu_id,
'action': act.id
}
var title = act.display_name;
var dr = view.controller.datarecord;
if (dr){
title = dr.display_name || title;
if (view_type=='form'){
url['id'] = dr.id;
}
}
if (view_type=='form' && !url['id'])
return false;
var last_viewed_item = {
'title': title,
'url': url,
'view_type': view_type,
}
this.ActionManager.add_last_viewed(last_viewed_item);
return true;
},
do_create_view: function(view_type) {
var self = this;
var res = this._super.apply(this, arguments);
var view = this.views[view_type];
var exec = function(){
if (self.active_view == view_type && self.try_add_last_viewed(view_type)){
self.update_last_viewed_title()
}
}
exec();
view.controller.on('change:title', this, function(){
exec()
})
return res;
},
update_last_viewed_title: function(){
this.$el.find('.oe_view_manager_last_viewed').html(this.get_action_manager().get_last_viewed_title());
},
set_title: function(){
this._super.apply(this, arguments);
if (this.action.target!='new')
this.update_last_viewed_title();
}
})
instance.mail.Wall.include({
start: function() {
this._super();
this.update_last_viewed_title();
},
update_last_viewed_title: function(){
this.$el.find('.oe_view_manager_last_viewed').html(this.ActionManager.get_last_viewed_title());
},
});
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<templates>
<t t-name="web_last_viewed_records.header">
<tr class="oe_header_row">
<td t-att-colspan="colspan or '3'">
<div class="oe_view_manager_last_viewed"/>
</td>
<td></td>
</tr>
</t>
<t t-extend="ViewManagerAction">
<t t-jquery="tr.oe_header_row_top" t-operation="after">
<t t-call="web_last_viewed_records.header"/>
</t>
</t>
<t t-extend="mail.wall">
<t t-jquery="tr.oe_header_row_top" t-operation="after">
<t t-call="web_last_viewed_records.header">
<t t-set="colspan" t-value="2"/>
</t>
</t>
</t>
</templates>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend" name="custom bar assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/web_last_viewed_records/static/src/css/main.css"/>
<script type="text/javascript" src="/web_last_viewed_records/static/src/js/main.js"></script>
</xpath>
</template>
</data>
</openerp>