[MERGE] trunk

bzr revid: al@openerp.com-20120801104657-cinfl0svpnc8njs5
This commit is contained in:
Antony Lesuisse 2012-08-01 12:46:57 +02:00
commit 574f3891a5
33 changed files with 1402 additions and 743 deletions

View File

@ -3,8 +3,10 @@
"category": "Hidden",
"description":
"""
OpenERP Web core module.
This module provides the core of the OpenERP Web Client.
OpenERP Web core module.
========================
This module provides the core of the OpenERP Web Client.
""",
"depends" : [],
'auto_install': True,
@ -20,6 +22,7 @@
"static/lib/jquery.form/jquery.form.js",
"static/lib/jquery.validate/jquery.validate.js",
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
"static/lib/spinjs/spin.js",
"static/lib/jquery.blockUI/jquery.blockUI.js",
"static/lib/jquery.ui/js/jquery-ui-1.8.17.custom.min.js",
"static/lib/jquery.ui.timepicker/js/jquery-ui-timepicker-addon.js",

View File

@ -425,11 +425,14 @@ class DisableCacheMiddleware(object):
def start_wrapped(status, headers):
referer = environ.get('HTTP_REFERER', '')
parsed = urlparse.urlparse(referer)
debug = not urlparse.parse_qs(parsed.query).has_key('debug')
filtered_headers = [(k,v) for k,v in headers if not (k=='Last-Modified' or (debug and k=='Cache-Control'))]
debug = parsed.query.count('debug') >= 1
nh = dict(headers)
if 'Last-Modified' in nh: del nh['Last-Modified']
if debug:
filtered_headers.append(('Cache-Control', 'no-cache'))
start_response(status, filtered_headers)
if 'Expires' in nh: del nh['Expires']
if 'Etag' in nh: del nh['Etag']
nh['Cache-Control'] = 'no-cache'
start_response(status, nh.items())
return self.app(environ, start_wrapped)
class Root(object):

View File

@ -194,9 +194,12 @@ class WebClient(openerpweb.Controller):
if mods is not None:
path += '?mods=' + mods
return [path]
# old code to force cache reloading
#return ['%s?debug=%s' % (wp, os.path.getmtime(fp)) for fp, wp in self.manifest_glob(req, mods, extension)]
return [el[1] for el in self.manifest_glob(req, mods, extension)]
no_sugar = req.httprequest.environ["QUERY_STRING"].count("no_sugar") >= 1
no_sugar = no_sugar or req.httprequest.environ.get('HTTP_REFERER', '').count("no_sugar") >= 1
if not no_sugar:
return ['%s?debug=%s' % (wp, os.path.getmtime(fp)) for fp, wp in self.manifest_glob(req, mods, extension)]
else:
return [el[1] for el in self.manifest_glob(req, mods, extension)]
@openerpweb.jsonrequest
def csslist(self, req, mods=None):
@ -994,6 +997,16 @@ class DataSet(openerpweb.Controller):
elif isinstance(kwargs[k], common.nonliterals.BaseDomain):
kwargs[k] = req.session.eval_domain(kwargs[k])
# Temporary implements future display_name special field for model#read()
if method == 'read' and kwargs.get('context') and kwargs['context'].get('future_display_name'):
if 'display_name' in args[1]:
names = req.session.model(model).name_get(args[0], **kwargs)
args[1].remove('display_name')
r = getattr(req.session.model(model), method)(*args, **kwargs)
for i in range(len(r)):
r[i]['display_name'] = names[i][1] or "%s#%d" % (model, names[i][0])
return r
return getattr(req.session.model(model), method)(*args, **kwargs)
@openerpweb.jsonrequest

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-07-25 04:52+0000\n"
"X-Launchpad-Export-Date: 2012-07-26 04:50+0000\n"
"X-Generator: Launchpad (build 15679)\n"
#. openerp-web

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
//fgnass.github.com/spin.js#v1.2.5
(function(window, document, undefined) {
/**
* Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
* Licensed under the MIT license
*/
var prefixes = ['webkit', 'Moz', 'ms', 'O']; /* Vendor prefixes */
var animations = {}; /* Animation rules keyed by their name */
var useCssAnimations;
/**
* Utility function to create elements. If no tag name is given,
* a DIV is created. Optionally properties can be passed.
*/
function createEl(tag, prop) {
var el = document.createElement(tag || 'div');
var n;
for(n in prop) {
el[n] = prop[n];
}
return el;
}
/**
* Appends children and returns the parent.
*/
function ins(parent /* child1, child2, ...*/) {
for (var i=1, n=arguments.length; i<n; i++) {
parent.appendChild(arguments[i]);
}
return parent;
}
/**
* Insert a new stylesheet to hold the @keyframe or VML rules.
*/
var sheet = function() {
var el = createEl('style');
ins(document.getElementsByTagName('head')[0], el);
return el.sheet || el.styleSheet;
}();
/**
* Creates an opacity keyframe animation rule and returns its name.
* Since most mobile Webkits have timing issues with animation-delay,
* we create separate rules for each line/segment.
*/
function addAnimation(alpha, trail, i, lines) {
var name = ['opacity', trail, ~~(alpha*100), i, lines].join('-');
var start = 0.01 + i/lines*100;
var z = Math.max(1-(1-alpha)/trail*(100-start) , alpha);
var prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase();
var pre = prefix && '-'+prefix+'-' || '';
if (!animations[name]) {
sheet.insertRule(
'@' + pre + 'keyframes ' + name + '{' +
'0%{opacity:'+z+'}' +
start + '%{opacity:'+ alpha + '}' +
(start+0.01) + '%{opacity:1}' +
(start+trail)%100 + '%{opacity:'+ alpha + '}' +
'100%{opacity:'+ z + '}' +
'}', 0);
animations[name] = 1;
}
return name;
}
/**
* Tries various vendor prefixes and returns the first supported property.
**/
function vendor(el, prop) {
var s = el.style;
var pp;
var i;
if(s[prop] !== undefined) return prop;
prop = prop.charAt(0).toUpperCase() + prop.slice(1);
for(i=0; i<prefixes.length; i++) {
pp = prefixes[i]+prop;
if(s[pp] !== undefined) return pp;
}
}
/**
* Sets multiple style properties at once.
*/
function css(el, prop) {
for (var n in prop) {
el.style[vendor(el, n)||n] = prop[n];
}
return el;
}
/**
* Fills in default values.
*/
function merge(obj) {
for (var i=1; i < arguments.length; i++) {
var def = arguments[i];
for (var n in def) {
if (obj[n] === undefined) obj[n] = def[n];
}
}
return obj;
}
/**
* Returns the absolute page-offset of the given element.
*/
function pos(el) {
var o = {x:el.offsetLeft, y:el.offsetTop};
while((el = el.offsetParent)) {
o.x+=el.offsetLeft;
o.y+=el.offsetTop;
}
return o;
}
var defaults = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 5, // The line thickness
radius: 10, // The radius of the inner circle
rotate: 0, // rotation offset
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 100, // Afterglow percentage
opacity: 1/4, // Opacity of the lines
fps: 20, // Frames per second when using setTimeout()
zIndex: 2e9, // Use a high z-index by default
className: 'spinner', // CSS class to assign to the element
top: 'auto', // center vertically
left: 'auto' // center horizontally
};
/** The constructor */
var Spinner = function Spinner(o) {
if (!this.spin) return new Spinner(o);
this.opts = merge(o || {}, Spinner.defaults, defaults);
};
Spinner.defaults = {};
merge(Spinner.prototype, {
spin: function(target) {
this.stop();
var self = this;
var o = self.opts;
var el = self.el = css(createEl(0, {className: o.className}), {position: 'relative', zIndex: o.zIndex});
var mid = o.radius+o.length+o.width;
var ep; // element position
var tp; // target position
if (target) {
target.insertBefore(el, target.firstChild||null);
tp = pos(target);
ep = pos(el);
css(el, {
left: (o.left == 'auto' ? tp.x-ep.x + (target.offsetWidth >> 1) : o.left+mid) + 'px',
top: (o.top == 'auto' ? tp.y-ep.y + (target.offsetHeight >> 1) : o.top+mid) + 'px'
});
}
el.setAttribute('aria-role', 'progressbar');
self.lines(el, self.opts);
if (!useCssAnimations) {
// No CSS animation support, use setTimeout() instead
var i = 0;
var fps = o.fps;
var f = fps/o.speed;
var ostep = (1-o.opacity)/(f*o.trail / 100);
var astep = f/o.lines;
!function anim() {
i++;
for (var s=o.lines; s; s--) {
var alpha = Math.max(1-(i+s*astep)%f * ostep, o.opacity);
self.opacity(el, o.lines-s, alpha, o);
}
self.timeout = self.el && setTimeout(anim, ~~(1000/fps));
}();
}
return self;
},
stop: function() {
var el = this.el;
if (el) {
clearTimeout(this.timeout);
if (el.parentNode) el.parentNode.removeChild(el);
this.el = undefined;
}
return this;
},
lines: function(el, o) {
var i = 0;
var seg;
function fill(color, shadow) {
return css(createEl(), {
position: 'absolute',
width: (o.length+o.width) + 'px',
height: o.width + 'px',
background: color,
boxShadow: shadow,
transformOrigin: 'left',
transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)',
borderRadius: (o.width>>1) + 'px'
});
}
for (; i < o.lines; i++) {
seg = css(createEl(), {
position: 'absolute',
top: 1+~(o.width/2) + 'px',
transform: o.hwaccel ? 'translate3d(0,0,0)' : '',
opacity: o.opacity,
animation: useCssAnimations && addAnimation(o.opacity, o.trail, i, o.lines) + ' ' + 1/o.speed + 's linear infinite'
});
if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'}));
ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)')));
}
return el;
},
opacity: function(el, i, val) {
if (i < el.childNodes.length) el.childNodes[i].style.opacity = val;
}
});
/////////////////////////////////////////////////////////////////////////
// VML rendering for IE
/////////////////////////////////////////////////////////////////////////
/**
* Check and init VML support
*/
!function() {
function vml(tag, attr) {
return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr);
}
var s = css(createEl('group'), {behavior: 'url(#default#VML)'});
if (!vendor(s, 'transform') && s.adj) {
// VML support detected. Insert CSS rule ...
sheet.addRule('.spin-vml', 'behavior:url(#default#VML)');
Spinner.prototype.lines = function(el, o) {
var r = o.length+o.width;
var s = 2*r;
function grp() {
return css(vml('group', {coordsize: s +' '+s, coordorigin: -r +' '+-r}), {width: s, height: s});
}
var margin = -(o.width+o.length)*2+'px';
var g = css(grp(), {position: 'absolute', top: margin, left: margin});
var i;
function seg(i, dx, filter) {
ins(g,
ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}),
ins(css(vml('roundrect', {arcsize: 1}), {
width: r,
height: o.width,
left: o.radius,
top: -o.width>>1,
filter: filter
}),
vml('fill', {color: o.color, opacity: o.opacity}),
vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change
)
)
);
}
if (o.shadow) {
for (i = 1; i <= o.lines; i++) {
seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)');
}
}
for (i = 1; i <= o.lines; i++) seg(i);
return ins(el, g);
};
Spinner.prototype.opacity = function(el, i, val, o) {
var c = el.firstChild;
o = o.shadow && o.lines || 0;
if (c && i+o < c.childNodes.length) {
c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild;
if (c) c.opacity = val;
}
};
}
else {
useCssAnimations = vendor(s, 'animation');
}
}();
window.Spinner = Spinner;
})(window, document);

View File

@ -20,6 +20,50 @@
font-style: normal;
}
@-moz-keyframes bounce {
0% {
-moz-transform: scale(0);
opacity: 0;
}
50% {
-moz-transform: scale(1.3);
opacity: 0.4;
}
75% {
-moz-transform: scale(0.9);
opacity: 0.7;
}
100% {
-moz-transform: scale(1);
opacity: 1;
}
}
@-webkit-keyframes bounce {
0% {
-webkit-transform: scale(0);
opacity: 0;
}
50% {
-webkit-transform: scale(1.3);
opacity: 0.4;
}
75% {
-webkit-transform: scale(0.9);
opacity: 0.7;
}
100% {
-webkit-transform: scale(1);
opacity: 1;
}
}
.openerp.openerp_webclient_container {
height: 100%;
position: relative;
@ -186,6 +230,11 @@
.openerp .ui-menu .ui-menu-item a.ui-state-active {
background: #f0f0fa;
}
.openerp div.ui-widget-overlay {
background: black;
filter: alpha(opacity=30);
opacity: 0.3;
}
.openerp.ui-dialog {
display: none;
padding: 6px;
@ -497,6 +546,10 @@
.openerp .oe_webclient .oe_star_on {
color: gold;
}
.openerp .oe_bounce {
-moz-animation: bounce 0.4s linear;
-webkit-animation: bounce 0.4s linear;
}
.openerp .oe_tag {
border-radius: 2px;
-webkit-box-sizing: border-box;
@ -1269,6 +1322,9 @@
.openerp .oe_view_manager .oe_view_manager_pager {
line-height: 26px;
}
.openerp .oe_view_manager .oe_view_manager_pager .oe_list_pager_single_page .oe_pager_group {
display: none;
}
.openerp .oe_view_manager .oe_pager_value {
float: left;
margin-right: 8px;
@ -2363,6 +2419,58 @@
.openerp .oe_list_content .numeric input {
text-align: right;
}
.openerp .tree_header {
background-color: #f0f0f0;
border-bottom: 1px solid #cacaca;
color: #4c4c4c;
padding: 5px;
height: 25px;
}
.openerp .tree_header button {
float: right;
height: 27px;
margin-right: 5px;
}
.openerp .oe-treeview-table {
width: 100%;
background-color: white;
border-spacing: 0;
}
.openerp .oe-treeview-table th {
padding: 10px;
color: #4c4c4c;
font-weight: bold;
background-color: #f0f0f0;
border-bottom: 2px solid #cacaca;
}
.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td {
cursor: pointer;
border-right: 1px dotted #afafb6;
vertical-align: top;
text-align: left;
border-bottom: 1px solid #cfcccc;
}
.openerp .oe-treeview-table tr:hover {
background-color: #e0e0f8;
}
.openerp .oe-treeview-table .oe-number {
text-align: right !important;
}
.openerp .oe-treeview-table span {
font-size: 90%;
font-weight: normal;
white-space: nowrap;
display: block;
}
.openerp .oe-treeview-table .treeview-tr.oe-treeview-first {
background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat;
}
.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first {
background-image: url(/web/static/src/img/collapse.gif);
}
.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span {
margin-left: 16px;
}
.openerp .oe_trad_field.touched {
border: 1px solid green !important;
}
@ -2428,59 +2536,6 @@
color: #333333;
}
.openerp .tree_header {
background-color: #f0f0f0;
border-bottom: 1px solid #cacaca;
color: #4c4c4c;
padding: 5px;
height: 25px;
}
.openerp .tree_header button {
float: right;
height: 27px;
margin-right: 5px;
}
.openerp .oe-treeview-table {
width: 100%;
background-color: white;
border-spacing: 0;
}
.openerp .oe-treeview-table th {
padding: 10px;
color: #4c4c4c;
font-weight: bold;
background-color: #f0f0f0;
border-bottom: 2px solid #cacaca;
}
.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td {
cursor: pointer;
border-right: 1px dotted #afafb6;
vertical-align: top;
text-align: left;
border-bottom: 1px solid #cfcccc;
}
.openerp .oe-treeview-table tr:hover {
background-color: #e0e0f8;
}
.openerp .oe-treeview-table .oe-number {
text-align: right !important;
}
.openerp .oe-treeview-table span {
font-size: 90%;
font-weight: normal;
white-space: nowrap;
display: block;
}
.openerp .oe-treeview-table .treeview-tr.oe-treeview-first {
background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat;
}
.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first {
background-image: url(/web/static/src/img/collapse.gif);
}
.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span {
margin-left: 16px;
}
.kitten-mode-activated {
background-image: url(http://placekitten.com/g/1365/769);
background-size: cover;
@ -2489,9 +2544,3 @@
.kitten-mode-activated > * {
opacity: 0.7;
}
div.ui-widget-overlay {
background: black;
filter: alpha(opacity=30);
opacity: 0.3;
}

View File

@ -97,6 +97,35 @@ $sheet-max-width: 860px
color: $color
// }}}
// CSS animation bounces {{{
@-moz-keyframes bounce
0%
-moz-transform: scale(0)
opacity: 0
50%
-moz-transform: scale(1.3)
opacity: 0.4
75%
-moz-transform: scale(0.9)
opacity: 0.7
100%
-moz-transform: scale(1)
opacity: 1
@-webkit-keyframes bounce
0%
-webkit-transform: scale(0)
opacity: 0
50%
-webkit-transform: scale(1.3)
opacity: 0.4
75%
-webkit-transform: scale(0.9)
opacity: 0.7
100%
-webkit-transform: scale(1)
opacity: 1
// }}}
.openerp.openerp_webclient_container
height: 100%
@ -200,7 +229,9 @@ $sheet-max-width: 860px
width: auto
a.ui-state-active
background: #f0f0fa
div.ui-widget-overlay
background: black
@include opacity(0.3)
// Modal box
&.ui-dialog
display: none
@ -390,6 +421,9 @@ $sheet-max-width: 860px
text-decoration: none
.oe_star_on
color: gold
.oe_bounce
-moz-animation: bounce .40s linear
-webkit-animation: bounce .40s linear
// }}}
// Tags (for many2many tags, among others) {{{
.oe_tag
@ -982,6 +1016,8 @@ $sheet-max-width: 860px
// ViewManager.pager {{{
.oe_view_manager_pager
line-height: 26px
.oe_list_pager_single_page .oe_pager_group
display: none
.oe_pager_value
float: left
margin-right: 8px
@ -1846,6 +1882,49 @@ $sheet-max-width: 860px
input
text-align: right
// }}}
// Tree view {{{
.tree_header
background-color: #f0f0f0
border-bottom: 1px solid #cacaca
color: #4c4c4c
padding: 5px
height: 25px
button
float: right
height: 27px
margin-right: 5px
.oe-treeview-table
width: 100%
background-color: white
border-spacing: 0
th
padding: 10px
color: #4c4c4c
font-weight: bold
background-color: #f0f0f0
border-bottom: 2px solid #cacaca
.treeview-tr, .treeview-td
cursor: pointer
border-right: 1px dotted #afafb6
vertical-align: top
text-align: left
border-bottom: 1px solid #cfcccc
tr:hover
background-color: #e0e0f8
.oe-number
text-align: right !important
span
font-size: 90%
font-weight: normal
white-space: nowrap
display: block
.treeview-tr.oe-treeview-first
background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat
.oe_open .treeview-tr.oe-treeview-first
background-image: url(/web/static/src/img/collapse.gif)
.treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span
margin-left: 16px
// }}}
// Translation {{{
.oe_trad_field.touched
border: 1px solid green !important
@ -1903,49 +1982,6 @@ $sheet-max-width: 860px
float: right
color: #333
// }}}
//Tree view
.openerp
.tree_header
background-color: #f0f0f0
border-bottom: 1px solid #cacaca
color: #4c4c4c
padding: 5px
height: 25px
button
float: right
height: 27px
margin-right: 5px
.oe-treeview-table
width: 100%
background-color: white
border-spacing: 0
th
padding: 10px
color: #4c4c4c
font-weight: bold
background-color: #f0f0f0
border-bottom: 2px solid #cacaca
.treeview-tr, .treeview-td
cursor: pointer
border-right: 1px dotted #afafb6
vertical-align: top
text-align: left
border-bottom: 1px solid #cfcccc
tr:hover
background-color: #e0e0f8
.oe-number
text-align: right !important
span
font-size: 90%
font-weight: normal
white-space: nowrap
display: block
.treeview-tr.oe-treeview-first
background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat
.oe_open .treeview-tr.oe-treeview-first
background-image: url(/web/static/src/img/collapse.gif)
.treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span
margin-left: 16px
// Kitten Mode {{{
.kitten-mode-activated
background-image: url(http://placekitten.com/g/1365/769)
@ -1956,8 +1992,6 @@ $sheet-max-width: 860px
// }}}
div.ui-widget-overlay
background: black
@include opacity(0.3)
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 673 B

View File

@ -385,8 +385,16 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
var fields = $(form).serializeArray();
self.rpc("/web/database/create", {'fields': fields}, function(result) {
var form_obj = self.to_object(fields);
self.getParent().do_login( form_obj['db_name'], 'admin', form_obj['create_admin_pwd']);
self.destroy();
var client_action = {
type: 'ir.actions.client',
tag: 'login',
params: {
'db': form_obj['db_name'],
'login': 'admin',
'password': form_obj['create_admin_pwd'],
},
};
self.do_action(client_action);
});
},
@ -471,19 +479,22 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
});
},
do_exit: function () {
this.do_action("login");
}
});
instance.web.client_actions.add("database_manager", "instance.web.DatabaseManager");
instance.web.Login = instance.web.Widget.extend({
template: "Login",
remember_credentials: true,
_db_list: null,
init: function(parent) {
init: function(parent, params) {
this._super(parent);
this.has_local_storage = typeof(localStorage) != 'undefined';
this.selected_db = null;
this.selected_login = null;
this.params = params;
if (this.has_local_storage && this.remember_credentials) {
this.selected_db = localStorage.getItem('last_db_login_success');
@ -493,26 +504,17 @@ instance.web.Login = instance.web.Widget.extend({
}
}
},
open_db_manager: function(){
var self = this;
self.$element.find('.oe_login_bottom').hide();
self.$element.find('.oe_login_pane').hide();
self.databasemanager = new instance.web.DatabaseManager(self);
self.databasemanager.appendTo(self.$element);
self.databasemanager.do_exit.add_last(function() {
self.databasemanager.destroy();
self.$element.find('.oe_login_bottom').show();
self.$element.find('.oe_login_pane').show();
self.load_db_list(true).then(self.on_db_list_loaded);
});
},
start: function() {
var self = this;
self.$element.find("form").submit(self.on_submit);
self.$element.find('.oe_login_manage_db').click(function() {
self.open_db_manager();
self.do_action("database_manager");
});
return self.load_db_list().then(self.on_db_list_loaded).then(function() {
if(self.params) {
self.do_login(self.params.db, self.params.login, self.params.password);
}
});
return self.load_db_list().then(self.on_db_list_loaded);
},
load_db_list: function (force) {
var d = $.when(), self = this;
@ -533,7 +535,7 @@ instance.web.Login = instance.web.Widget.extend({
var dbdiv = this.$element.find('div.oe_login_dbpane');
this.$element.find("[name=db]").replaceWith(instance.web.qweb.render('Login.dblist', { db_list: list, selected_db: this.selected_db}));
if(list.length === 0) {
self.open_db_manager();
this.do_action("database_manager");
} else if(list && list.length === 1) {
dbdiv.hide();
} else {
@ -580,7 +582,7 @@ instance.web.Login = instance.web.Widget.extend({
localStorage.setItem('last_password_login_success', '');
}
}
self.trigger("login");
self.trigger('login_successful');
},function () {
self.$(".oe_login_pane").fadeIn("fast");
self.$element.addClass("oe_login_invalid");
@ -593,6 +595,7 @@ instance.web.Login = instance.web.Widget.extend({
this.$element.hide();
}
});
instance.web.client_actions.add("login", "instance.web.Login");
instance.web.Menu = instance.web.Widget.extend({
template: 'Menu',
@ -896,7 +899,8 @@ instance.web.Client = instance.web.Widget.extend({
this.$element.on('click', '.oe_dropdown_toggle', function(ev) {
ev.preventDefault();
var $toggle = $(this);
var $menu = $toggle.find('.oe_dropdown_menu');
var $menu = $toggle.siblings('.oe_dropdown_menu');
$menu = $menu.size() >= 1 ? $menu : $toggle.find('.oe_dropdown_menu');
var state = $menu.is('.oe_opened');
setTimeout(function() {
// Do not alter propagation
@ -967,22 +971,15 @@ instance.web.WebClient = instance.web.Client.extend({
data: {debug: file + ':' + line}
});
};
// TODO: deprecate and use login client action
self.login = new instance.web.Login(self);
self.login.on("login",self,self.show_application);
return self.login.appendTo(self.$element).then(function () {
self.login.hide();
});
},
show_login: function() {
var self = this;
self.$('.oe_topbar').hide();
self.login.show();
this.$('.oe_topbar').hide();
this.action_manager.do_action("login");
this.action_manager.inner_widget.on('login_successful', this, this.show_application);
},
show_application: function() {
var self = this;
self.$('.oe_topbar').show();
self.login.hide();
self.menu = new instance.web.Menu(self);
self.menu.replace(this.$element.find('.oe_menu_placeholder'));
self.menu.on('menu_click', this, this.on_menu_action);
@ -1063,6 +1060,7 @@ instance.web.WebClient = instance.web.Client.extend({
},
do_push_state: function(state) {
this.set_title(state.title);
delete state.title;
var url = '#' + $.param(state);
this._current_state = _.clone(state);
$.bbq.pushState(url);
@ -1089,10 +1087,13 @@ instance.web.WebClient = instance.web.Client.extend({
}
},
set_content_full_screen: function(fullscreen) {
if (fullscreen)
if (fullscreen) {
$(".oe_webclient", this.$element).addClass("oe_content_full_screen");
else
$("body").css({'overflow-y':'hidden'});
} else {
$(".oe_webclient", this.$element).removeClass("oe_content_full_screen");
$("body").css({'overflow-y':'scroll'});
}
}
});

View File

@ -378,7 +378,8 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
instance.web.EventDispatcherMixin.init.call(this);
this.__getterSetterInternalMap = {};
},
set: function(map) {
set: function(map, options) {
options = options || {};
var self = this;
var changed = false;
_.each(map, function(val, key) {
@ -387,10 +388,11 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
return;
changed = true;
self.__getterSetterInternalMap[key] = val;
self.trigger("change:" + key, self, {
oldValue: tmp,
newValue: val
});
if (! options.silent)
self.trigger("change:" + key, self, {
oldValue: tmp,
newValue: val
});
});
if (changed)
self.trigger("change", self);

View File

@ -549,14 +549,38 @@ $.async_when = function() {
/** Setup blockui */
if ($.blockUI) {
$.blockUI.defaults.baseZ = 1100;
$.blockUI.defaults.message = '<img src="/web/static/src/img/throbber.gif">';
$.blockUI.defaults.message = '<div class="oe_blockui_spin" style="height: 50px">';
$.blockUI.defaults.css.border = '0';
$.blockUI.defaults.css["background-color"] = '';
$.blockUI.spinners = [];
}
instance.web.blockUI = function() {
$.blockUI.apply($, arguments);
var tmp = $.blockUI.apply($, arguments);
var target = $(".oe_blockui_spin")[0];
var opts = {
lines: 13, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
rotate: 0, // The rotation offset
color: '#FFF', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false, // Whether to use hardware acceleration
className: 'spinner', // The CSS class to assign to the spinner
zIndex: 2e9, // The z-index (defaults to 2000000000)
top: 'auto', // Top position relative to parent in px
left: 'auto' // Left position relative to parent in px
};
var spinner = new Spinner(opts).spin(target);
$.blockUI.spinners.push(spinner);
return tmp;
}
instance.web.unblockUI = function() {
_.each($.blockUI.spinners, function(el) {
el.stop();
});
return $.unblockUI.apply($, arguments);
}

View File

@ -516,7 +516,16 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
this.$element.addClass('oe_focused');
},
childBlurred: function () {
this.$element.removeClass('oe_focused');
var val = this.$element.val();
this.$element.val('');
var complete = this.$element.data('autocomplete');
if ((val && complete.term === undefined) || complete.previous !== undefined) {
throw new Error("new jquery.ui version altering implementation" +
" details relied on");
}
delete complete.term;
this.$element.removeClass('oe_focused')
.trigger('blur');
},
/**
*

View File

@ -33,6 +33,11 @@ instance.web.form.FieldManagerMixin = {
};
instance.web.views.add('form', 'instance.web.FormView');
/**
* Properties:
* - actual_mode: always "view", "edit" or "create". Read-only property. Determines
* the mode used by the view.
*/
instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerMixin, {
/**
* Indicates that this view is not searchable, and thus that no search
@ -55,6 +60,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
* @property {instance.web.Registry} registry=instance.web.form.widgets widgets registry for this form view instance
*/
init: function(parent, dataset, view_id, options) {
var self = this;
this._super(parent);
this.set_default_options(options);
this.dataset = dataset;
@ -82,6 +88,13 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.__blur_timeout = null;
this.rendering_engine = new instance.web.form.FormRenderingEngine(this);
this.qweb = null; // A QWeb instance will be created if the view is a QWeb template
self.set({actual_mode: self.options.initial_mode});
this.has_been_loaded.then(function() {
self.on("change:actual_mode", self, self.check_actual_mode);
self.check_actual_mode();
self.on("change:actual_mode", self, self.init_pager);
self.init_pager();
});
},
destroy: function() {
_.each(this.get_widgets(), function(w) {
@ -127,17 +140,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.$buttons.on('click','.oe_form_button_save',this.on_button_save);
this.$buttons.on('click','.oe_form_button_cancel',this.on_button_cancel);
this.$pager = $(QWeb.render("FormView.pager", {'widget':self}));
if (this.options.$pager) {
this.$pager.appendTo(this.options.$pager);
} else {
this.$element.find('.oe_form_pager').replaceWith(this.$pager);
}
this.$pager.on('click','a[data-pager-action]',function() {
var action = $(this).data('pager-action');
self.on_pager_action(action);
});
this.$sidebar = this.options.$sidebar || this.$element.find('.oe_form_sidebar');
if (!this.sidebar && this.options.$sidebar) {
this.sidebar = new instance.web.Sidebar(this);
@ -151,8 +153,15 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
{ label: _t('Set Default'), callback: function (item) { self.open_defaults_dialog(); } },
]);
}
this.on("change:mode", this, this.switch_mode);
this.set({mode: this.options.initial_mode});
// Add bounce effect on button 'Edit' when click on readonly page view.
this.$element.find(".oe_form_field, .oe_form_group_cell").on('click', function (e) {
if(self.get("actual_mode") == "view") {
var $button = self.options.$buttons.find(".oe_form_button_edit");
$button.wrap('<div>').css('margin-right','4px').addClass('oe_left oe_bounce');
}
});
this.has_been_loaded.resolve();
return $.when();
},
@ -260,7 +269,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
if (this.$pager) {
this.$pager.show();
}
this.$element.show().css('visibility', 'hidden');
this.$element.add(this.$buttons).removeClass('oe_form_dirty');
var shown = this.has_been_loaded;
@ -270,16 +278,17 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
// null index means we should start a new record
return self.on_button_new();
}
return self.dataset.read_index(_.keys(self.fields_view.fields), {
context: { 'bin_size': true }
var fields = _.keys(self.fields_view.fields);
fields.push('display_name');
return self.dataset.read_index(fields, {
context: { 'bin_size': true, 'future_display_name' : true }
}).pipe(self.on_record_loaded);
});
}
return shown.pipe(function() {
if (options.editable) {
self.set({mode: "edit"});
self.to_edit_mode();
}
self.$element.css('visibility', 'visible');
});
},
do_hide: function () {
@ -302,7 +311,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return $.Deferred().reject();
}
this.datarecord = record;
this.set({ 'title' : record.id ? record.name : "New record" });
this._actualize_mode();
this.set({ 'title' : record.id ? record.display_name : "New record" });
if (this.qweb) {
this.kill_current_form();
@ -379,6 +389,24 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.reload();
}
},
init_pager: function() {
var self = this;
if (this.$pager)
this.$pager.remove();
if (this.get("actual_mode") === "create")
return;
this.$pager = $(QWeb.render("FormView.pager", {'widget':self}));
if (this.options.$pager) {
this.$pager.appendTo(this.options.$pager);
} else {
this.$element.find('.oe_form_pager').replaceWith(this.$pager);
}
this.$pager.on('click','a[data-pager-action]',function() {
var action = $(this).data('pager-action');
self.on_pager_action(action);
});
this.do_update_pager();
},
do_update_pager: function(hide_index) {
var index = hide_index ? '-' : this.dataset.index + 1;
this.$pager.find('button').prop('disabled', this.dataset.ids.length < 2).end()
@ -578,9 +606,32 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return $.Deferred().reject();
}
},
switch_mode: function() {
/**
* Ask the view to switch to view mode if possible. The view may not do it
* if the current record is not yet saved. It will then stay in create mode.
*/
to_view_mode: function() {
this._actualize_mode("view");
},
/**
* Ask the view to switch to edit mode if possible. The view may not do it
* if the current record is not yet saved. It will then stay in create mode.
*/
to_edit_mode: function() {
this._actualize_mode("edit");
},
/**
* Reactualize actual_mode.
*/
_actualize_mode: function(switch_to) {
var mode = switch_to || this.get("actual_mode");
if (! this.datarecord.id)
mode = "create";
this.set({actual_mode: mode});
},
check_actual_mode: function(source, options) {
var self = this;
if(this.get("mode") == "view") {
if(this.get("actual_mode") === "view") {
self.$element.removeClass('oe_form_editable').addClass('oe_form_readonly');
self.$buttons.find('.oe_form_buttons_edit').hide();
self.$buttons.find('.oe_form_buttons_view').show();
@ -598,11 +649,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
});
var fields_order = self.fields_order.slice(0);
if (self.default_focus_field) {
fields_order.unshift(self.default_focus_field);
fields_order.unshift(self.default_focus_field.name);
}
for (var i = 0; i < fields_order.length; i += 1) {
var field = self.fields[fields_order[i]];
if (!field.get('effective_invisible') && !field.get('effective_readonly') && field.focus() !== false) {
if (!field.get('effective_invisible') && !field.get('effective_readonly')) {
field.focus();
break;
}
}
@ -611,19 +663,19 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
on_button_save: function() {
var self = this;
return this.do_save().then(function(result) {
self.set({mode: "view"});
self.to_view_mode();
});
},
on_button_cancel: function(event) {
if (this.can_be_discarded()) {
this.set({mode: "view"});
this.to_view_mode();
this.on_record_loaded(this.datarecord);
}
return false;
},
on_button_new: function() {
var self = this;
this.set({mode: "edit"});
this.to_edit_mode();
return $.when(this.has_been_loaded).pipe(function() {
if (self.can_be_discarded()) {
return self.load_defaults();
@ -631,7 +683,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
});
},
on_button_edit: function() {
return this.set({mode: "edit"});
return this.to_edit_mode();
},
on_button_create: function() {
this.dataset.index = null;
@ -644,7 +696,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
return self.on_created({ result : new_id });
}).then(function() {
return self.set({mode: "edit"});
return self.to_edit_mode();
}).then(function() {
def.resolve();
});
@ -806,8 +858,10 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
if (self.dataset.index == null || self.dataset.index < 0) {
return $.when(self.on_button_new());
} else {
return self.dataset.read_index(_.keys(self.fields_view.fields), {
context : { 'bin_size' : true }
var fields = _.keys(self.fields_view.fields);
fields.push('display_name');
return self.dataset.read_index(fields, {
context : { 'bin_size' : true, 'future_display_name' : true }
}).pipe(self.on_record_loaded);
}
});
@ -937,7 +991,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
register_field: function(field, name) {
this.fields[name] = field;
this.fields_order.push(name);
if (field.node.attrs.default_focus == '1') {
if (JSON.parse(field.node.attrs.default_focus || "0")) {
this.default_focus_field = field;
}
@ -959,7 +1013,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return this.fields_view.fields[field_name];
},
is_create_mode: function() {
return !this.datarecord.id;
return this.get("actual_mode") === "create";
},
open_translate_dialog: function(field) {
return this._super(field);
@ -1643,10 +1697,13 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({
this._super(view, node);
this.force_disabled = false;
this.string = (this.node.attrs.string || '').replace(/_/g, '');
if (this.node.attrs.default_focus == '1') {
if (JSON.parse(this.node.attrs.default_focus || "0")) {
// TODO fme: provide enter key binding to widgets
this.view.default_focus_button = this;
}
if (this.node.attrs.icon && (! /\//.test(this.node.attrs.icon))) {
this.node.attrs.icon = '/web/static/src/img/icons/' + this.node.attrs.icon + '.png';
}
this.view.on('view_content_has_changed', this, this.check_disable);
},
start: function() {
@ -2009,7 +2066,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we
return this.get('value') === '' || this._super();
},
focus: function() {
this.delay_focus(this.$element.find('input:first'));
this.$element.find('input:first')[0].focus();
}
});
@ -2820,10 +2877,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
if (follow)
link += "<br />";
}
this.$element.find('a')
var $link = this.$element.find('.oe_form_uri')
.unbind('click')
.html(link)
.click(function () {
.html(link);
if (! this.get_definition_options().no_open)
$link.click(function () {
self.do_action({
type: 'ir.actions.act_window',
res_model: self.field.relation,
@ -2981,6 +3039,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
}
if(view.view_type === "list") {
_.extend(view.options, {
addable: null,
selectable: self.multi_selection,
sortable: false,
import_enabled: false,
@ -2988,7 +3047,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
});
if (self.get("effective_readonly")) {
_.extend(view.options, {
addable: null,
deletable: null,
reorderable: false,
});
@ -3412,6 +3470,34 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
this._super.apply(this, arguments);
}
});
instance.web.form.One2ManyList = instance.web.ListView.List.extend({
pad_table_to: function (count) {
this._super(count > 0 ? count - 1 : 0);
// magical invocation of wtf does that do
if (this.view.o2m.get('effective_readonly')) {
return;
}
var self = this;
var columns = _(this.columns).filter(function (column) {
return column.invisible !== '1';
}).length;
if (this.options.selectable) { columns++; }
if (this.options.deletable) { columns++; }
var $cell = $('<td>', {
colspan: columns,
'class': 'oe_form_field_one2many_list_row_add'
}).text(_t("Add a row"))
.click(function (e) {
e.preventDefault();
e.stopPropagation();
self.view.do_add_record();
});
this.$current.append(
$('<tr>').append($cell))
}
});
instance.web.form.One2ManyFormView = instance.web.FormView.extend({
form_template: 'One2Many.formview',
@ -3539,12 +3625,13 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
render_value: function() {
var self = this;
var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.view.dataset.get_context());
var values = self.get("value")
var handle_names = function(data) {
var indexed = {};
_.each(data, function(el) {
indexed[el[0]] = el;
});
data = _.map(self.get("value"), function(el) { return indexed[el]; });
data = _.map(values, function(el) { return indexed[el]; });
if (! self.get("effective_readonly")) {
self.tags.containerElement().children().remove();
$("textarea", self.$element).css("padding-left", "3px");
@ -3553,8 +3640,8 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
self.$element.html(QWeb.render("FieldMany2ManyTag", {elements: data}));
}
};
if (! self.get('values') || self.get('values').length > 0) {
this._display_orderer.add(dataset.name_get(self.get("value"))).then(handle_names);
if (! values || values.length > 0) {
this._display_orderer.add(dataset.name_get(values)).then(handle_names);
} else {
handle_names([]);
}

View File

@ -357,6 +357,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
{ label: _t('Delete'), callback: this.do_delete_selected },
]);
this.sidebar.add_toolbar(this.fields_view.toolbar);
this.sidebar.$element.hide();
}
},
/**
@ -375,6 +376,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
var total = dataset.size();
var limit = this.limit() || total;
this.$pager.toggle(total !== 0);
this.$pager.toggleClass('oe_list_pager_single_page', (total <= limit));
var spager = '-';
if (total) {
@ -493,9 +495,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
},
do_show: function () {
this._super();
if (this.sidebar) {
this.sidebar.$element.show();
}
if (this.$buttons) {
this.$buttons.show();
}
@ -934,7 +933,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
'[data-id=' + record.get('id') + ']');
var index = $row.data('index');
$row.remove();
self.refresh_zebra(index);
},
'reset': function () { return self.on_records_reset(); },
'change': function (event, record, attribute, value, old_value) {
@ -969,8 +967,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
'[data-id=' + previous_record.get('id') + ']');
$new_row.insertAfter($previous_sibling);
}
self.refresh_zebra(index, 1);
}
};
_(this.record_callbacks).each(function (callback, event) {
@ -1110,7 +1106,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
this.$current
.children('tr:not([data-id])').remove().end()
.append(new Array(count - this.records.length + 1).join(row));
this.refresh_zebra(this.records.length);
},
/**
* Gets the ids of all currently selected records, if any
@ -1184,25 +1179,6 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
render_cell: function () {
return self.render_cell.apply(self, arguments); }
});
},
/**
* Fixes fixes the even/odd classes
*
* @param {Number} [from_index] index from which to resequence
* @param {Number} [offset = 0] selection offset for DOM, in case there are rows to ignore in the table
*/
refresh_zebra: function (from_index, offset) {
offset = offset || 0;
from_index = from_index || 0;
var dom_offset = offset + from_index;
var sel = dom_offset ? ':gt(' + (dom_offset - 1) + ')' : null;
this.$current.children(sel).each(function (i, e) {
var index = from_index + i;
// reset record-index accelerators on rows and even/odd
var even = index%2 === 0;
$(e).toggleClass('even', even)
.toggleClass('odd', !even);
});
}
});
instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.web.ListView.Groups# */{
@ -1535,8 +1511,6 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
}(dataset, record.get('id'), seq));
record.set('sequence', seq);
}
list.refresh_zebra();
}
});
},

View File

@ -423,26 +423,64 @@ openerp.web.list_editable = function (instance) {
keyup_ESCAPE: function () {
return this.cancel_edition();
},
/**
* Gets the selection range (start, end) for the provided element,
* returns ``null`` if it can't get a range.
*
* @private
*/
_text_selection_range: function (el) {
if (el.selectionStart !== undefined) {
var selectionStart;
try {
selectionStart = el.selectionStart;
} catch (e) {
// radio or checkbox throw on selectionStart access
return null;
}
if (selectionStart !== undefined) {
return {
start: el.selectionStart,
start: selectionStart,
end: el.selectionEnd
};
} else if(document.body.createTextRange) {
} else if (document.body.createTextRange) {
throw new Error("Implement text range handling for MSIE");
var sel = document.body.createTextRange();
if (sel.parentElement() === el) {
}
}
// Element without selection ranges (select, div/@contenteditable)
return null;
},
_text_cursor: function (el) {
var selection = this._text_selection_range(el);
if (selection.start !== selection.end) {
if (!selection) {
return null;
}
return selection.start;
if (selection.start !== selection.end) {
return {position: null, collapsed: false};
}
return {position: selection.start, collapsed: true};
},
/**
* Checks if the cursor is at the start of the provided el
*
* @param {HTMLInputElement | HTMLTextAreaElement}
* @returns {Boolean}
* @private
*/
_at_start: function (cursor, el) {
return cursor.collapsed && (cursor.position === 0);
},
/**
* Checks if the cursor is at the end of the provided el
*
* @param {HTMLInputElement | HTMLTextAreaElement}
* @returns {Boolean}
* @private
*/
_at_end: function (cursor, el) {
return cursor.collapsed && (cursor.position === el.value.length);
},
/**
* @param DOMEvent event
@ -452,10 +490,11 @@ openerp.web.list_editable = function (instance) {
*/
_key_move_record: function (event, record_direction, is_valid_move) {
if (!this.editor.is_editing('edit')) { return $.when(); }
// FIXME: assumes editable widgets are input-type elements
var index = this._text_cursor(event.target);
// If selecting or not at the start of the input
if (!is_valid_move(event.target, index)) { return $.when(); }
var cursor = this._text_cursor(event.target);
// if text-based input (has a cursor)
// and selecting (not collapsed) or not at a field boundary
// don't move to the next record
if (cursor && !is_valid_move(event.target, cursor)) { return $.when(); }
event.preventDefault();
var source_field = $(event.target).closest('[data-fieldname]')
@ -464,13 +503,15 @@ openerp.web.list_editable = function (instance) {
},
keydown_UP: function (e) {
return this._key_move_record(e, 'pred', function (el, index) {
return index === 0;
var self = this;
return this._key_move_record(e, 'pred', function (el, cursor) {
return self._at_start(cursor, el);
});
},
keydown_DOWN: function (e) {
return this._key_move_record(e, 'succ', function (el, index) {
return index === el.value.length;
var self = this;
return this._key_move_record(e, 'succ', function (el, cursor) {
return self._at_end(cursor, el);
});
},
@ -478,8 +519,8 @@ openerp.web.list_editable = function (instance) {
// If the cursor is at the beginning of the field
var source_field = $(e.target).closest('[data-fieldname]')
.attr('data-fieldname');
var index = this._text_cursor(e.target);
if (index !== 0) { return $.when(); }
var cursor = this._text_cursor(e.target);
if (cursor && !this._at_start(cursor, e.target)) { return $.when(); }
var fields_order = this.editor.form.fields_order;
var field_index = _(fields_order).indexOf(source_field);
@ -502,8 +543,8 @@ openerp.web.list_editable = function (instance) {
// looking for new fields at the right
var source_field = $(e.target).closest('[data-fieldname]')
.attr('data-fieldname');
var index = this._text_cursor(e.target);
if (index !== e.target.value.length) { return $.when(); }
var cursor = this._text_cursor(e.target);
if (cursor && !this._at_end(cursor, e.target)) { return $.when(); }
var fields_order = this.editor.form.fields_order;
var field_index = _(fields_order).indexOf(source_field);

View File

@ -120,7 +120,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
if (this.getParent() && this.getParent().do_push_state) {
if (this.inner_action) {
state['title'] = this.inner_action.name;
state['model'] = this.inner_action.res_model;
if(this.inner_action.type == 'ir.actions.act_window') {
state['model'] = this.inner_action.res_model;
}
if (this.inner_action.id) {
state['action_id'] = this.inner_action.id;
}
@ -178,7 +180,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
},
do_action: function(action, on_close) {
if (_.isNumber(action) || _.isString(action)) {
if (_.isString(action) && instance.web.client_actions.contains(action)) {
var action_client = { type: "ir.actions.client", tag: action };
return this.do_action(action_client);
} else if (_.isNumber(action) || _.isString(action)) {
var self = this;
return self.rpc("/web/action/load", { action_id: action }, function(result) {
self.do_action(result.result, on_close);
@ -209,21 +214,30 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.dialog_stop();
this.clear_breadcrumbs();
},
ir_actions_act_window: function (action, on_close) {
var self = this;
if (_(['base.module.upgrade', 'base.setup.installer'])
.contains(action.res_model)) {
var old_close = on_close;
on_close = function () {
instance.webclient.do_reload().then(old_close);
};
do_ir_actions_common: function(action, on_close) {
var self = this, klass, widget, add_breadcrumb;
if (action.type === 'ir.actions.client') {
var ClientWidget = instance.web.client_actions.get_object(action.tag);
widget = new ClientWidget(this, action.params);
klass = 'oe_act_client';
add_breadcrumb = function() {
self.push_breadcrumb({
widget: widget,
title: action.name
});
}
} else {
widget = new instance.web.ViewManagerAction(this, action);
klass = 'oe_act_window';
add_breadcrumb = widget.proxy('add_breadcrumb');
}
if (action.target === 'new') {
if (this.dialog === null) {
// These buttons will be overwrited by <footer> if any
this.dialog = new instance.web.Dialog(this, {
buttons: { "Close": function() { $(this).dialog("close"); }},
dialogClass: 'oe_act_window'
dialogClass: klass
});
if(on_close)
this.dialog.on_close.add(on_close);
@ -231,7 +245,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.dialog_widget.destroy();
}
this.dialog.dialog_title = action.name;
this.dialog_widget = new instance.web.ViewManagerAction(this, action);
this.dialog_widget = widget;
this.dialog_widget.appendTo(this.dialog.$element);
this.dialog.open();
} else {
@ -242,11 +256,34 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
}
this.inner_action = action;
var inner_widget = this.inner_widget = new instance.web.ViewManagerAction(this, action);
inner_widget.add_breadcrumb();
this.inner_widget = widget;
add_breadcrumb();
this.inner_widget.appendTo(this.$element);
}
},
ir_actions_act_window: function (action, on_close) {
var self = this;
if (_(['base.module.upgrade', 'base.setup.installer'])
.contains(action.res_model)) {
var old_close = on_close;
on_close = function () {
instance.webclient.do_reload().then(old_close);
};
}
if (action.target !== 'new') {
if(action.menu_id) {
this.dialog_stop();
return this.getParent().do_action(action, function () {
instance.webclient.menu.open_menu(action.menu_id);
});
}
}
return this.do_ir_actions_common(action, on_close);
},
ir_actions_client: function (action, on_close) {
return this.do_ir_actions_common(action, on_close);
},
ir_actions_act_window_close: function (action, on_closed) {
if (!this.dialog && on_closed) {
on_closed();
@ -262,16 +299,6 @@ instance.web.ActionManager = instance.web.Widget.extend({
self.do_action(action, on_closed)
});
},
ir_actions_client: function (action) {
this.dialog_stop();
var ClientWidget = instance.web.client_actions.get_object(action.tag);
this.inner_widget = new ClientWidget(this, action.params);
this.push_breadcrumb({
widget: this.inner_widget,
title: action.name
});
this.inner_widget.appendTo(this.$element);
},
ir_actions_report_xml: function(action, on_closed) {
var self = this;
instance.web.blockUI();
@ -477,6 +504,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
});
this.getParent().push_breadcrumb({
widget: this,
action: this.action,
show: function(index, $e) {
var view_to_select = views[index];
self.$element.show();
@ -485,9 +513,27 @@ instance.web.ViewManager = instance.web.Widget.extend({
}
},
get_title: function() {
return _.map(views, function(v) {
return self.views[v].controller.get('title');
var id;
var currentIndex;
_.each(self.getParent().breadcrumbs, function(bc, i) {
if (bc.widget === self) {
currentIndex = i;
}
});
var next = self.getParent().breadcrumbs.slice(currentIndex + 1)[0];
var titles = _.map(views, function(v) {
var controller = self.views[v].controller;
if (v === 'form') {
id = controller.datarecord.id;
}
return controller.get('title');
});
if (next && next.action.res_id && self.active_view === 'form' && self.model === next.action.res_model && id === next.action.res_id) {
// If the current active view is a formview and the next item in the breadcrumbs
// is an action on same object (model / res_id), then we omit the current formview's title
titles.pop();
}
return titles;
}
});
},

View File

@ -518,25 +518,25 @@
<div class="oe_form_dropdown_section">
<button class="oe_dropdown_toggle oe_dropdown_arrow">
<t t-esc="section.label"/>
<ul class="oe_dropdown_menu">
<li t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname">
<a class="oe_sidebar_action_a" t-att-title="item.title" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url" target="_blank">
<t t-raw="item.label"/>
</a>
<a t-if="section.name == 'files'" class="oe_sidebar_delete_item" t-att-data-id="item.id" title="Delete this attachment">x</a>
</li>
<li t-if="section.name == 'files'" class="oe_sidebar_add_attachment">
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
<t t-set="fileupload_action">/web/binary/upload_attachment</t>
<input type="hidden" name="model" t-att-value="widget.dataset and widget.dataset.model"/>
<input type="hidden" name="id" t-att-value="widget.model_id"/>
<input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
<span>Add...</span>
</t>
</li>
</ul>
</button>
<ul class="oe_dropdown_menu">
<li t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname">
<a class="oe_sidebar_action_a" t-att-title="item.title" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url" target="_blank">
<t t-raw="item.label"/>
</a>
<a t-if="section.name == 'files'" class="oe_sidebar_delete_item" t-att-data-id="item.id" title="Delete this attachment">x</a>
</li>
<li t-if="section.name == 'files'" class="oe_sidebar_add_attachment">
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
<t t-set="fileupload_action">/web/binary/upload_attachment</t>
<input type="hidden" name="model" t-att-value="widget.dataset and widget.dataset.model"/>
<input type="hidden" name="id" t-att-value="widget.model_id"/>
<input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
<span>Add...</span>
</t>
</li>
</ul>
</div>
</t>
</div>
@ -645,17 +645,14 @@
<t t-name="ListView.rows" t-foreach="records.length" t-as="index">
<t t-call="ListView.row">
<t t-set="record" t-value="records.at(index)"/>
<t t-set="row_parity" t-value="index_parity"/>
</t>
</t>
<tr t-name="ListView.row" t-att-class="row_parity"
<tr t-name="ListView.row"
t-att-data-id="record.get('id')"
t-att-style="view.style_for(record)">
<t t-set="asData" t-value="record.toForm().data"/>
<t t-foreach="columns" t-as="column">
<td t-if="column.meta">
</td>
<td t-if="column.meta"> </td>
</t>
<th t-if="options.selectable" class="oe_list_record_selector" width="1">
<t t-set="checked" t-value="options.select_view_id == record.get('id') ? 'checked' : null"/>
@ -674,7 +671,6 @@
<button type="button" name="delete" class="oe_i">d</button>
</td>
</tr>
<t t-extend="ListView.buttons">
<t t-jquery="button.oe_list_add" t-operation="after">
<button class="oe_button oe_list_save oe_highlight"
@ -684,6 +680,15 @@
<a href="#" class="oe_bold oe_list_discard">discard</a>
</t>
</t>
<t t-extend="ListView.row">
<!-- adds back padding to row being rendered after edition, if necessary
(if not deletable add back padding), otherwise the row being added is
missing columns
-->
<t t-jquery="&gt; :last" t-operation="after">
<td t-if="edited and !options.deletable" class="oe-listview-padding"/>
</t>
</t>
<t t-name="FormView">
<div class="oe_formview">
@ -955,11 +960,13 @@
<t t-name="FieldMany2One">
<span class="oe_form_field oe_form_field_many2one oe_form_field_with_button" t-att-style="widget.node.attrs.style">
<t t-if="widget.get('effective_readonly')">
<a href="#" class="oe_form_uri"/>
<a t-if="! widget.get_definition_options().no_open" href="#" class="oe_form_uri"/>
<span t-if="widget.get_definition_options().no_open" href="#" class="oe_form_uri"/>
<span class="oe_form_m2o_follow"/>
</t>
<t t-if="!widget.get('effective_readonly')">
<a href="#" tabindex="-1" class="oe_m2o_cm_button oe_e oe_right">/</a>
<a t-if="! widget.get_definition_options().no_open" href="#" tabindex="-1"
class="oe_m2o_cm_button oe_e oe_right">/</a>
<div>
<input type="text"
t-att-id="widget.id_for_label"
@ -974,7 +981,6 @@
</t>
</span>
</t>
<!-- Collection of m2m tags -->
<t t-name="FieldMany2ManyTags">
<div class="oe_form_field oe_tags" t-att-style="widget.node.attrs.style">
<t t-if="! widget.get('effective_readonly')">
@ -983,7 +989,6 @@
</t>
</div>
</t>
<!-- Individual m2m tag element -->
<t t-name="FieldMany2ManyTag">
<t t-set="i" t-value="0"/>
<t t-foreach="elements" t-as="el">
@ -1131,7 +1136,7 @@
t-att-style="widget.node.attrs.style"
t-att-tabindex="widget.node.attrs.tabindex"
t-att-autofocus="widget.node.attrs.autofocus">
<img t-if="widget.node.attrs.icon" t-att-src="_s + '/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/>
<img t-if="widget.node.attrs.icon" t-att-src="_s + widget.node.attrs.icon" width="16" height="16"/>
<span t-if="widget.string"><t t-esc="widget.string"/></span>
</button>
</t>
@ -1189,6 +1194,41 @@
</table>
</t>
<t t-name="AbstractFormPopup.render">
<div>
<table style="width:100%">
<tr style="width:100%">
<td style="width:100%">
<div class="oe_popup_search" style="width:100%"></div>
</td>
</tr>
<tr style="width:100%">
<td style="width:100%">
<div class="oe_popup_list" style="width:100%"></div>
</td>
</tr>
</table>
<div class="oe_popup_form" style="width:100%"></div>
</div>
</t>
<t t-name="SelectCreatePopup.search.buttons">
<t t-if="! widget.options.disable_multiple_selection">
<button type="button" class="oe_button oe_selectcreatepopup-search-select" disabled="disabled">Select</button>
or
</t>
<a class="oe_button oe_selectcreatepopup-search-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a>
</t>
<t t-name="AbstractFormPopup.buttons">
<t t-if="! multi_select">
<button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save</button>
</t>
<t t-if="multi_select">
<button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save &amp; New</button>
<button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save &amp; Close</button>
</t>
or <a class="oe_button oe_abstractformpopup-form-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Discard</a>
</t>
<t t-name="One2Many.viewmanager" t-extend="ViewManager">
<t t-jquery=".oe-view-manager-header">
this.attr('t-if', 'views.length != 1');
@ -1241,7 +1281,6 @@
<span t-name="SearchView.FacetView.Value" class="oe_facet_value">
<t t-esc="widget.model.get('label')"/>
</span>
<t t-name="SearchView.managed-filters">
<option class="oe_search_filters_title" value="">Filters</option>
<optgroup label="-- Filters --">
@ -1266,7 +1305,6 @@
<p>(Any existing filter with the same name will be replaced)</p>
</div>
</t>
<t t-name="SearchView.render_lines">
<table class="oe_search_render_line" border="0" cellspacing="0" cellpadding="0"
t-foreach="lines" t-as="line">
@ -1463,49 +1501,6 @@
</t>
</select>
</t>
<t t-name="AbstractFormPopup.render">
<div>
<table style="width:100%">
<tr style="width:100%">
<td style="width:100%">
<div class="oe_popup_search" style="width:100%"></div>
</td>
</tr>
<tr style="width:100%">
<td style="width:100%">
<div class="oe_popup_list" style="width:100%"></div>
</td>
</tr>
</table>
<div class="oe_popup_form" style="width:100%"></div>
</div>
</t>
<t t-name="SelectCreatePopup.search.buttons">
<t t-if="! widget.options.disable_multiple_selection">
<button type="button" class="oe_button oe_selectcreatepopup-search-select" disabled="disabled">Select</button>
or
</t>
<a class="oe_button oe_selectcreatepopup-search-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a>
</t>
<t t-name="AbstractFormPopup.buttons">
<t t-if="! multi_select">
<button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save</button>
</t>
<t t-if="multi_select">
<button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save &amp; New</button>
<button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save &amp; Close</button>
</t>
or <a class="oe_button oe_abstractformpopup-form-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a>
</t>
<t t-extend="ListView.row">
<!-- adds back padding to row being rendered after edition, if necessary
(if not deletable add back padding), otherwise the row being added is
missing columns
-->
<t t-jquery="&gt; :last" t-operation="after">
<td t-if="edited and !options.deletable" class="oe-listview-padding"/>
</t>
</t>
<t t-name="view_editor">
<table class="oe_view_editor">
@ -1570,6 +1565,7 @@
<t t-name="vieweditor_boolean">
<input type="checkbox" t-att-id="widget.name"/>
</t>
<t t-name="ExportView">
<a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a>
</t>

View File

@ -1,10 +1,7 @@
{
"name": "Web Calendar",
"category": "Hidden",
"description":
"""
OpenERP Web Calendar view.
""",
"description":"""OpenERP Web Calendar view.""",
"version": "2.0",
"depends": ['web'],
"js": [

View File

@ -1,10 +1,7 @@
{
"name": "Web Dashboard",
"category": "Hidden",
"description":
"""
OpenERP Web Dashboard view.
""",
"description":"""OpenERP Web Dashboard view.""",
"version": "2.0",
"depends": ['web'],
"js": [

View File

@ -1,7 +1,7 @@
{
"name" : "OpenERP Web Diagram",
"category" : "Hidden",
"description":'Openerp Web Diagram view',
"description":"""Openerp Web Diagram view.""",
"version" : "2.0",
"depends" : ["web"],
"js": [

View File

@ -1,10 +1,7 @@
{
"name": "Web Gantt",
"category": "Hidden",
"description":
"""
OpenERP Web Gantt chart view.
""",
"description":"""OpenERP Web Gantt chart view.""",
"version": "2.0",
"depends": ['web'],
"js": [

View File

@ -1,14 +1,16 @@
{
"name": "Graph Views",
"category" : "Hidden",
"description":"""Graph Views for Web Client
"description":"""
Graph Views for Web Client.
===========================
* Parse a <graph> view but allows changing dynamically the presentation
* Graph Types: pie, lines, areas, bars, radar
* Stacked/Not Stacked for areas and bars
* Legends: top, inside (top/left), hidden
* Features: download as PNG or CSV, browse data grid, switch orientation
* Unlimited "Group By" levels (not stacked), two cross level analysis (stacked)
* Parse a <graph> view but allows changing dynamically the presentation
* Graph Types: pie, lines, areas, bars, radar
* Stacked/Not Stacked for areas and bars
* Legends: top, inside (top/left), hidden
* Features: download as PNG or CSV, browse data grid, switch orientation
* Unlimited "Group By" levels (not stacked), two cross level analysis (stacked)
""",
"version": "3.0",
"depends": ['web'],

View File

@ -1,10 +1,7 @@
{
"name": "Hello",
"category": "Hidden",
"description":
"""
OpenERP Web example module.
""",
"description":"""OpenERP Web example module.""",
"version": "2.0",
"depends": [],
"js": ["static/*/*.js", "static/*/js/*.js"],

View File

@ -1,10 +1,7 @@
{
"name" : "Base Kanban",
"category": "Hidden",
"description":
"""
OpenERP Web kanban view.
""",
"description":"""OpenERP Web kanban view.""",
"version" : "2.0",
"depends" : ["web"],
"js": [

View File

@ -1,3 +1,4 @@
@charset "utf-8";
.openerp .oe_kanban_view {
background: url(/web/static/src/img/form_sheetbg.png);
height: inherit;
@ -49,7 +50,7 @@
.openerp .oe_kanban_view .oe_kanban_group_title {
font-size: 16px;
font-weight: bold;
min-height: 30px;
min-height: 32px;
color: #333333;
text-shadow: 0 1px 0 white;
}
@ -525,3 +526,44 @@
padding: 0px;
background: white;
}
.openerp .oe_popup_form .oe_kanban_buttons .oe_highlight {
color: #404040;
background: none;
}
.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight {
background-color: #efefef;
background-image: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8));
background-image: -webkit-linear-gradient(top, #efefef, #d8d8d8);
background-image: -moz-linear-gradient(top, #efefef, #d8d8d8);
background-image: -ms-linear-gradient(top, #efefef, #d8d8d8);
background-image: -o-linear-gradient(top, #efefef, #d8d8d8);
background-image: linear-gradient(to bottom, #efefef, #d8d8d8);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
}
.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight:active {
background-color: #e3e3e3;
background-image: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f6f6f6));
background-image: -webkit-linear-gradient(top, #e3e3e3, #f6f6f6);
background-image: -moz-linear-gradient(top, #e3e3e3, #f6f6f6);
background-image: -ms-linear-gradient(top, #e3e3e3, #f6f6f6);
background-image: -o-linear-gradient(top, #e3e3e3, #f6f6f6);
background-image: linear-gradient(to bottom, #e3e3e3, #f6f6f6);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
}
.openerp .oe_popup_form .oe_kanban_buttons button.oe_highlight:hover {
background-color: #f6f6f6;
background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3));
background-image: -webkit-linear-gradient(top, #f6f6f6, #e3e3e3);
background-image: -moz-linear-gradient(top, #f6f6f6, #e3e3e3);
background-image: -ms-linear-gradient(top, #f6f6f6, #e3e3e3);
background-image: -o-linear-gradient(top, #f6f6f6, #e3e3e3);
background-image: linear-gradient(to bottom, #f6f6f6, #e3e3e3);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
}

View File

@ -1,6 +1,15 @@
@charset "utf-8"
// Mixins {{{
@mixin vertical-gradient($startColor: #555, $endColor: #333)
background-color: $startColor
background-image: -webkit-gradient(linear, left top, left bottom, from($startColor), to($endColor)) /* Saf4+, Chrome */
background-image: -webkit-linear-gradient(top, $startColor, $endColor) /* Chrome 10+, Saf5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, $startColor, $endColor) /* FF3.6 */
background-image: -ms-linear-gradient(top, $startColor, $endColor) /* IE10 */
background-image: -o-linear-gradient(top, $startColor, $endColor) /* Opera 11.10+ */
background-image: linear-gradient(to bottom, $startColor, $endColor)
@mixin radial-gradient($gradient)
background-position: center center
background-image: -webkit-radial-gradient(circle, $gradient)
@ -64,7 +73,7 @@
.oe_kanban_group_title
font-size: 16px
font-weight: bold
min-height: 30px
min-height: 32px
color: #333333
text-shadow: 0 1px 0 white
> span
@ -439,5 +448,22 @@
padding: 0px
background: #ffffff
.openerp
.oe_popup_form
.oe_kanban_buttons
.oe_highlight
color: #404040
background: none
button.oe_highlight
@include vertical-gradient(#efefef, #d8d8d8)
@include box-shadow((0 1px 2px rgba(0, 0, 0, .1), 0 1px 1px rgba(255, 255, 255, .8) inset))
button.oe_highlight:active
@include vertical-gradient(#e3e3e3, #f6f6f6)
@include box-shadow(none)
button.oe_highlight:hover
@include vertical-gradient(#f6f6f6, #e3e3e3)
@include box-shadow((0 1px 2px rgba(0, 0, 0, .1), 0 1px 1px rgba(255, 255, 255, .8) inset))
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:

View File

@ -295,10 +295,10 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
if (!group.state.folded) {
if (182*unfolded>=self.$element.width()) {
group.$element.css('width', "170px");
} else if (262*unfolded>self.$element.width()) {
group.$element.css('width', Math.round(100/unfolded) + '%');
} else {
} else if (262*unfolded<self.$element.width()) {
group.$element.css('width', "250px");
} else {
group.$element.css('width', Math.floor(self.$element.width()/unfolded) + 'px');
}
}
});
@ -420,6 +420,15 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
self.quick.appendTo($(".oe_kanban_group_list_header", self.$records));
self.quick.focus();
});
// Add bounce effect on image '+' of kanban header when click on empty space of kanban grouped column.
var add_btn = this.$element.find('.oe_kanban_add');
this.$records.click(function (ev) {
if (ev.target == ev.currentTarget) {
if (!self.state.folded) {
add_btn.wrap('<div>').addClass('oe_bounce');
}
}
});
this.$records.find('.oe_kanban_show_more').click(this.do_show_more);
if (this.state.folded) {
this.do_toggle_fold();

View File

@ -13,7 +13,7 @@
<div t-name="KanbanView.buttons" class="oe_kanban_buttons">
<t t-if="widget.options.action_buttons !== false">
<t t-if="widget._is_create_enabled()">
<button type="button" class="oe_button oe_kanban_button_new oe_highlight oe_form_button_hi">
<button type="button" class="oe_kanban_button_new oe_highlight">
<t t-esc="widget.options.create_text || _t('Create')"/>
</button>
</t>

View File

@ -1,10 +1,7 @@
{
"name" : "OpenERP Web Mobile",
"category": "Hidden",
"description":
"""
OpenERP Web Mobile.
""",
"description":"""OpenERP Web Mobile.""",
"version" : "2.0",
"depends" : [],
'auto_install': True,

View File

@ -1,10 +1,7 @@
{
"name" : "Process",
"version": "2.0",
"description":
"""
OpenERP Web process view.
""",
"description":"""OpenERP Web process view.""",
"depends" : ["web_diagram"],
"js": [
'static/lib/dracula/*.js',

View File

@ -1,7 +1,7 @@
{
"name" : "OpenERP Web Web",
"category" : "Hidden",
"description":'Openerp Web Web',
"description":"""Openerp Web Web.""",
"version" : "2.0",
"depends" : [],
"installable" : False,

View File

@ -1,10 +1,7 @@
{
"name": "Tests",
"category": "Hidden",
"description":
"""
OpenERP Web test suite.
""",
"description":"""OpenERP Web test suite.""",
"version": "2.0",
"depends": [],
"js": ["static/src/js/*.js"],