[MERGE]merge with trunk and in testing OK.

bzr revid: vme@tinyerp.com-20120622090614-t0q7djkz62dn1yiq
This commit is contained in:
Vidhin Mehta (OpenERP) 2012-06-22 14:36:14 +05:30
commit 790e3d6d9e
46 changed files with 3956 additions and 3808 deletions

View File

@ -21,8 +21,6 @@
"static/lib/jquery.validate/jquery.validate.js",
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
"static/lib/jquery.blockUI/jquery.blockUI.js",
"static/lib/jquery.superfish/js/hoverIntent.js",
"static/lib/jquery.superfish/js/superfish.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",
"static/lib/jquery.ui.notify/js/jquery.notify.js",
@ -30,13 +28,11 @@
"static/lib/jquery.scrollTo/jquery.scrollTo-min.js",
"static/lib/jquery.tipsy/jquery.tipsy.js",
"static/lib/jquery.textext/jquery.textext.js",
"static/lib/json/json2.js",
"static/lib/jquery.timeago/jquery.timeago.js",
"static/lib/qweb/qweb2.js",
"static/lib/underscore/underscore.js",
"static/lib/underscore/underscore.string.js",
"static/lib/backbone/backbone.js",
"static/lib/labjs/LAB.src.js",
"static/lib/py.js/lib/py.js",
"static/src/js/boot.js",
"static/src/js/corelib.js",
@ -56,12 +52,10 @@
"static/src/js/view_editor.js"
],
'css' : [
"static/lib/jquery.superfish/css/superfish.css",
"static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.8.16.custom.css",
"static/lib/jquery.ui.timepicker/css/jquery-ui-timepicker-addon.css",
"static/lib/jquery.ui.notify/css/ui.notify.css",
"static/lib/jquery.tipsy/tipsy.css",
# "static/src/css/base_old.css",
"static/src/css/base.css",
"static/src/css/data_export.css",
"static/src/css/data_import.css",

View File

@ -332,12 +332,9 @@ def httprequest(f):
# OpenERP Web werkzeug Session Managment wraped using with
#----------------------------------------------------------
STORES = {}
SESSION_TIMEOUT = 7 * 24 * 60 * 60 # FIXME make it configurable ?
SESSION_COUNTER = 0
@contextlib.contextmanager
def session_context(request, storage_path, session_cookie='sessionid'):
global SESSION_COUNTER
session_store, session_lock = STORES.get(storage_path, (None, None))
if not session_store:
session_store = werkzeug.contrib.sessions.FilesystemSessionStore(
@ -347,22 +344,10 @@ def session_context(request, storage_path, session_cookie='sessionid'):
sid = request.cookies.get(session_cookie)
with session_lock:
SESSION_COUNTER += 1
if SESSION_COUNTER % 100 == 0:
SESSION_COUNTER = 0
for s in session_store.list():
ss = session_store.get(s)
t = ss.get('timestamp')
if not t or t + SESSION_TIMEOUT < time.time():
_logger.debug('deleting http session %s', s)
session_store.delete(ss)
if sid:
request.session = session_store.get(sid)
else:
request.session = session_store.new()
request.session['timestamp'] = time.time()
try:
yield request.session
@ -379,7 +364,7 @@ def session_context(request, storage_path, session_cookie='sessionid'):
and not value.jsonp_requests
# FIXME do not use a fixed value
and value._creation_time + (60*5) < time.time()):
_logger.debug('remove OpenERP session %s', key)
_logger.debug('remove session %s', key)
removed_sessions.add(key)
del request.session[key]

View File

@ -1331,19 +1331,39 @@ class Binary(openerpweb.Controller):
@openerpweb.httprequest
def image(self, req, model, id, field, **kw):
last_update = '__last_update'
Model = req.session.model(model)
context = req.session.eval_context(req.context)
headers = [('Content-Type', 'image/png')]
etag = req.httprequest.headers.get('If-None-Match')
hashed_session = hashlib.md5(req.session_id).hexdigest()
if etag:
if not id and hashed_session == etag:
return werkzeug.wrappers.Response(status=304)
else:
date = Model.read([int(id)], [last_update], context)[0].get(last_update)
if hashlib.md5(date).hexdigest() == etag:
return werkzeug.wrappers.Response(status=304)
retag = hashed_session
try:
if not id:
res = Model.default_get([field], context).get(field)
image_data = base64.b64decode(res)
else:
res = Model.read([int(id)], [field], context)[0].get(field)
image_data = base64.b64decode(res)
res = Model.read([int(id)], [last_update, field], context)[0]
retag = hashlib.md5(res.get(last_update)).hexdigest()
image_data = base64.b64decode(res.get(field))
except (TypeError, xmlrpclib.Fault):
image_data = self.placeholder(req)
return req.make_response(image_data, [
('Content-Type', 'image/png'), ('Content-Length', len(image_data))])
headers.append(('ETag', retag))
headers.append(('Content-Length', len(image_data)))
try:
ncache = int(kw.get('cache'))
headers.append(('Cache-Control', 'no-cache' if ncache == 0 else 'max-age=%s' % (ncache)))
except:
pass
return req.make_response(image_data, headers)
def placeholder(self, req):
addons_path = openerpweb.addons_manifest['web']['addons_path']
return open(os.path.join(addons_path, 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()

1544
addons/web/i18n/ca.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +0,0 @@
Changelog for Superfish - a jQuery menu plugin
v1.2.1: altered 2nd July 07. added hide() before animate to make work for jQuery 1.1.3.
v1.2.2: altered 2nd August 07. changed over function .find('ul') to .find('>ul') for smoother animations
Also deleted the iframe removal lines - not necessary it turns out
v1.2.3: altered jquery 1.1.3.1 broke keyboard access - had to change quite a few things and set display:none on the
.superfish rule in CSS instead of top:-999em
v1.3: Pretty much a complete overhaul to make all original features work in 1.1.3.1 and above.
.superfish rule reverted back to top:-999em (which is better).
v1.3.1: altered 'li[ul]' to $('li:has(ul)') to work with jQuery 1.2
v1.3.2: added onshow callback option as requested - 'this' keyword refers to revealed ul.
fixed bug whereby multiple menus on a page shared options. Now each menu can have separate options.
fixed IE6 and IE7 bug whereby under certain circumstances => 3rd tier menus appear instantly with text missing when revisited
v1.3.3: altered event attachment selectors for performance increase on menu setup.
v1.3.4: fixed pathClass bug as current path was not being restored. Still doesn't if using keyboard nav (will work on that).
v1.4: store options objects in array $.superfish.o. Also provide public access to $.superfish.defaults
provided backward compat for jQuery versions less than 1.2 via oldJquery option - will use li[ul] or li:has(ul) as needed
added more callbacks, also added option to disable hoverIntent usage if that plugin is detected
v1.4.1: fixed current path not being restored when using keyboard to tab away from the menu completely
optimised code further - now less code
removed addself() in favour of backward compatible add(this)
also remove new mouseenter/mouseleave events on window.unload (due to paranoia)
v1.4.2: 3rd July 2008. added semi-colon at start of superfish.js file to avert script concatenation errors
added pathLevels option to limit the depth of submenus that get restored by pathClass
CSS of main example hugely simplified - other example CSS files less-so.
- top level menu items are not fixed width
- only need to set submenu widths in one place.
- various other improvements.
- class names used in all CSS files are changed to be less generic
released optional Supersubs plugin which dynamically adjusts submenu widths
attach everything to jQuery.fn.superfish to clean up jQuery namespace
removed the multi-tier-all-horizontal-example as it was never a great idea and doesn't seem to be in use
Update documentation text and remove certain caveats which were there to support users of much older versions of Superfish
Documentation now show how to apply bgIgrame 2.1 - it's much easier than before
Add all links and their focus and blur events to the onunload unbind - paranoid about memory leaks
v1.4.3 5th July 2008. documentation completely redone using Mike Alsup's templates.
CSS revised so that all types of menu use superfish.css as a base. Include additional CSS files to acheive alternate styles.
class="sf-menu sf-vertical" creates vertical menu, class="sf-menu sf-navbar" creates nav-bar style menu
v1.4.4 7th July 2008. arrows feature added. If option 'autoArrows' is true, auto-appends (spans) to anchors that have a ul submenu sibling,
and adds class 'sf-with-ul' to anchor.
CSS added to style new arrows, including an 8-bit alpha (NOT INDEXED!) transparent png of arrow - degrades to solid for IE6.
Manually add arrow mark-up to docs and disable autoArrows (via defaults option) to maintain decent performance (for docs page)
Update docs, including zip download, to suit.
Fix CSS bug that had the third tier of the navbar-style menu visible when JS not available.
v1.4.5 9 July 2008. decreased code weight
added drop shadows for capable browsers - added css and 8-bit alpha transparent png image for shadow
remove support for jQuery v<1.2
remove unload clean-up which was there to solve garbage collection problems in early jQuery versions
remove toggling 'visibility' on hide and show which as a fix for an IE bug that is no longer exhibited
removed need for getOpts, rewrote getMenu
use [].join('') instead of string concatenation for performance increase - probably very slight in this case
change selector in 'over' function from '.'+o.hoverClass to 'li.'+o.hoverClass
v1.4.6 added workaround for IE7 shadows. If animation alters opacity then shadow is hidden during the animation and appears after.
This required some JS and a line of CSS, so created shortcut references to lighten code further.
v1.4.7 added back in the visibility toggle that was removed in 1.4.5 as the bug is indeed still exhibited by IE6 & 7
tweaked the look of the shadow slightly and use nicer 32bit png as I now find they behave the same as 8bit png with regard to fades in IE7
v1.4.8 fix over-sight: using 32bit png meant that the shadow image did show in IE6. Rather than go back to 8bit, add code to exclude IE6 from getting shadow class.
use new folder structure recommended by Matt from TopicTrack, for easier updates.

View File

@ -1,93 +0,0 @@
/*** adding the class sf-navbar in addition to sf-menu creates an all-horizontal nav-bar menu ***/
.sf-navbar {
background: #BDD2FF;
height: 2.5em;
padding-bottom: 2.5em;
position: relative;
}
.sf-navbar li {
background: #AABDE6;
position: static;
}
.sf-navbar a {
border-top: none;
}
.sf-navbar li ul {
width: 44em; /*IE6 soils itself without this*/
}
.sf-navbar li li {
background: #BDD2FF;
position: relative;
}
.sf-navbar li li ul {
width: 13em;
}
.sf-navbar li li li {
width: 100%;
}
.sf-navbar ul li {
width: auto;
float: left;
}
.sf-navbar a, .sf-navbar a:visited {
border: none;
}
.sf-navbar li.current {
background: #BDD2FF;
}
.sf-navbar li:hover,
.sf-navbar li.sfHover,
.sf-navbar li li.current,
.sf-navbar a:focus, .sf-navbar a:hover, .sf-navbar a:active {
background: #BDD2FF;
}
.sf-navbar ul li:hover,
.sf-navbar ul li.sfHover,
ul.sf-navbar ul li:hover li,
ul.sf-navbar ul li.sfHover li,
.sf-navbar ul a:focus, .sf-navbar ul a:hover, .sf-navbar ul a:active {
background: #D1DFFF;
}
ul.sf-navbar li li li:hover,
ul.sf-navbar li li li.sfHover,
.sf-navbar li li.current li.current,
.sf-navbar ul li li a:focus, .sf-navbar ul li li a:hover, .sf-navbar ul li li a:active {
background: #E6EEFF;
}
ul.sf-navbar .current ul,
ul.sf-navbar ul li:hover ul,
ul.sf-navbar ul li.sfHover ul {
left: 0;
top: 2.5em; /* match top ul list item height */
}
ul.sf-navbar .current ul ul {
top: -999em;
}
.sf-navbar li li.current > a {
font-weight: bold;
}
/*** point all arrows down ***/
/* point right for anchors in subs */
.sf-navbar ul .sf-sub-indicator { background-position: -10px -100px; }
.sf-navbar ul a > .sf-sub-indicator { background-position: 0 -100px; }
/* apply hovers to modern browsers */
.sf-navbar ul a:focus > .sf-sub-indicator,
.sf-navbar ul a:hover > .sf-sub-indicator,
.sf-navbar ul a:active > .sf-sub-indicator,
.sf-navbar ul li:hover > a > .sf-sub-indicator,
.sf-navbar ul li.sfHover > a > .sf-sub-indicator {
background-position: -10px -100px; /* arrow hovers for modern browsers*/
}
/*** remove shadow on first submenu ***/
.sf-navbar > li > ul {
background: transparent;
padding: 0;
-moz-border-radius-bottomleft: 0;
-moz-border-radius-topright: 0;
-webkit-border-top-right-radius: 0;
-webkit-border-bottom-left-radius: 0;
}

View File

@ -1,23 +0,0 @@
/*** adding sf-vertical in addition to sf-menu creates a vertical menu ***/
.sf-vertical, .sf-vertical li {
width: 10em;
}
/* this lacks ul at the start of the selector, so the styles from the main CSS file override it where needed */
.sf-vertical li:hover ul,
.sf-vertical li.sfHover ul {
left: 10em; /* match ul width */
top: 0;
}
/*** alter arrow directions ***/
.sf-vertical .sf-sub-indicator { background-position: -10px 0; } /* IE6 gets solid image only */
.sf-vertical a > .sf-sub-indicator { background-position: 0 0; } /* use translucent arrow for modern browsers*/
/* hover arrow direction for modern browsers*/
.sf-vertical a:focus > .sf-sub-indicator,
.sf-vertical a:hover > .sf-sub-indicator,
.sf-vertical a:active > .sf-sub-indicator,
.sf-vertical li:hover > a > .sf-sub-indicator,
.sf-vertical li.sfHover > a > .sf-sub-indicator {
background-position: -10px 0; /* arrow hovers for modern browsers*/
}

View File

@ -1,136 +0,0 @@
/*** ESSENTIAL STYLES ***/
.sf-menu, .sf-menu * {
margin: 0;
padding: 0;
list-style: none;
}
.sf-menu {
line-height: 1.0;
}
.sf-menu ul {
position: absolute;
top: -999em;
width: 10em; /* left offset of submenus need to match (see below) */
}
.sf-menu ul li {
width: 100%;
}
.sf-menu li:hover {
visibility: inherit; /* fixes IE7 'sticky bug' */
}
.sf-menu li {
float: left;
position: relative;
}
.sf-menu a {
display: block;
position: relative;
}
.sf-menu li:hover ul,
.sf-menu li.sfHover ul {
left: 0;
top: 2.5em; /* match top ul list item height */
z-index: 99;
}
ul.sf-menu li:hover li ul,
ul.sf-menu li.sfHover li ul {
top: -999em;
}
ul.sf-menu li li:hover ul,
ul.sf-menu li li.sfHover ul {
left: 10em; /* match ul width */
top: 0;
}
ul.sf-menu li li:hover li ul,
ul.sf-menu li li.sfHover li ul {
top: -999em;
}
ul.sf-menu li li li:hover ul,
ul.sf-menu li li li.sfHover ul {
left: 10em; /* match ul width */
top: 0;
}
/*** DEMO SKIN ***/
.sf-menu {
float: left;
margin-bottom: 1em;
}
.sf-menu a {
border-left: 1px solid #fff;
border-top: 1px solid #CFDEFF;
padding: .75em 1em;
text-decoration:none;
}
.sf-menu a, .sf-menu a:visited { /* visited pseudo selector so IE6 applies text colour*/
color: #13a;
}
.sf-menu li {
background: #BDD2FF;
}
.sf-menu li li {
background: #AABDE6;
}
.sf-menu li li li {
background: #9AAEDB;
}
.sf-menu li:hover, .sf-menu li.sfHover,
.sf-menu a:focus, .sf-menu a:hover, .sf-menu a:active {
background: #CFDEFF;
outline: 0;
}
/*** arrows **/
.sf-menu a.sf-with-ul {
padding-right: 2.25em;
min-width: 1px; /* trigger IE7 hasLayout so spans position accurately */
}
.sf-sub-indicator {
position: absolute;
display: block;
right: .75em;
top: 1.05em; /* IE6 only */
width: 10px;
height: 10px;
text-indent: -999em;
overflow: hidden;
background: url('../images/arrows-ffffff.png') no-repeat -10px -100px; /* 8-bit indexed alpha png. IE6 gets solid image only */
}
a > .sf-sub-indicator { /* give all except IE6 the correct values */
top: .8em;
background-position: 0 -100px; /* use translucent arrow for modern browsers*/
}
/* apply hovers to modern browsers */
a:focus > .sf-sub-indicator,
a:hover > .sf-sub-indicator,
a:active > .sf-sub-indicator,
li:hover > a > .sf-sub-indicator,
li.sfHover > a > .sf-sub-indicator {
background-position: -10px -100px; /* arrow hovers for modern browsers*/
}
/* point right for anchors in subs */
.sf-menu ul .sf-sub-indicator { background-position: -10px 0; }
.sf-menu ul a > .sf-sub-indicator { background-position: 0 0; }
/* apply hovers to modern browsers */
.sf-menu ul a:focus > .sf-sub-indicator,
.sf-menu ul a:hover > .sf-sub-indicator,
.sf-menu ul a:active > .sf-sub-indicator,
.sf-menu ul li:hover > a > .sf-sub-indicator,
.sf-menu ul li.sfHover > a > .sf-sub-indicator {
background-position: -10px 0; /* arrow hovers for modern browsers*/
}
/*** shadows for all but IE6 ***/
.sf-shadow ul {
background: url('../images/shadow.png') no-repeat bottom right;
padding: 0 8px 9px 0;
-moz-border-radius-bottomleft: 17px;
-moz-border-radius-topright: 17px;
-webkit-border-top-right-radius: 17px;
-webkit-border-bottom-left-radius: 17px;
}
.sf-shadow ul.sf-shadow-off {
background: transparent;
}

View File

@ -1,123 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>A very basic Superfish menu example</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<link rel="stylesheet" type="text/css" href="css/superfish.css" media="screen">
<script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="js/hoverIntent.js"></script>
<script type="text/javascript" src="js/superfish.js"></script>
<script type="text/javascript">
// initialise plugins
jQuery(function(){
jQuery('ul.sf-menu').superfish();
});
</script>
</head>
<body>
<ul class="sf-menu">
<li class="current">
<a href="#a">menu item</a>
<ul>
<li>
<a href="#aa">menu item that is quite long</a>
</li>
<li class="current">
<a href="#ab">menu item</a>
<ul>
<li class="current"><a href="#">menu item</a></li>
<li><a href="#aba">menu item</a></li>
<li><a href="#abb">menu item</a></li>
<li><a href="#abc">menu item</a></li>
<li><a href="#abd">menu item</a></li>
</ul>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
</ul>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#">menu item</a>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">short</a></li>
<li><a href="#">short</a></li>
<li><a href="#">short</a></li>
<li><a href="#">short</a></li>
<li><a href="#">short</a></li>
</ul>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
</ul>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
</ul>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
</ul>
</li>
<li>
<a href="#">menu item</a>
<ul>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
<li><a href="#">menu item</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#">menu item</a>
</li>
</ul>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,84 +0,0 @@
(function($){
/* hoverIntent by Brian Cherne */
$.fn.hoverIntent = function(f,g) {
// default configuration options
var cfg = {
sensitivity: 7,
interval: 100,
timeout: 0
};
// override configuration options with user supplied object
cfg = $.extend(cfg, g ? { over: f, out: g } : f );
// instantiate variables
// cX, cY = current X and Y position of mouse, updated by mousemove event
// pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
var cX, cY, pX, pY;
// A private function for getting mouse position
var track = function(ev) {
cX = ev.pageX;
cY = ev.pageY;
};
// A private function for comparing current and previous mouse position
var compare = function(ev,ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
// compare mouse positions to see if they've crossed the threshold
if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
$(ob).unbind("mousemove",track);
// set hoverIntent state to true (so mouseOut can be called)
ob.hoverIntent_s = 1;
return cfg.over.apply(ob,[ev]);
} else {
// set previous coordinates for next time
pX = cX; pY = cY;
// use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
}
};
// A private function for delaying the mouseOut function
var delay = function(ev,ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
ob.hoverIntent_s = 0;
return cfg.out.apply(ob,[ev]);
};
// A private function for handling mouse 'hovering'
var handleHover = function(e) {
// next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
if ( p == this ) { return false; }
// copy objects to be passed into t (required for event object to be passed in IE)
var ev = jQuery.extend({},e);
var ob = this;
// cancel hoverIntent timer if it exists
if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
// else e.type == "onmouseover"
if (e.type == "mouseover") {
// set "previous" X and Y position based on initial entry point
pX = ev.pageX; pY = ev.pageY;
// update "current" X and Y position based on mousemove
$(ob).bind("mousemove",track);
// start polling interval (self-calling timeout) to compare mouse coordinates over time
if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
// else e.type == "onmouseout"
} else {
// unbind expensive mousemove event
$(ob).unbind("mousemove",track);
// if hoverIntent state is true, then call the mouseOut function after the specified delay
if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
}
};
// bind the function to the two event listeners
return this.mouseover(handleHover).mouseout(handleHover);
};
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -1,10 +0,0 @@
/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* $LastChangedDate: 2007-06-19 20:25:28 -0500 (Tue, 19 Jun 2007) $
* $Rev: 2111 $
*
* Version 2.1
*/
(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&parseInt($.browser.version)<=6){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};if(!$.browser.version)$.browser.version=navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1];})(jQuery);

View File

@ -1,121 +0,0 @@
/*
* Superfish v1.4.8 - jQuery menu widget
* Copyright (c) 2008 Joel Birch
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
*/
;(function($){
$.fn.superfish = function(op){
var sf = $.fn.superfish,
c = sf.c,
$arrow = $(['<span class="',c.arrowClass,'"> &#187;</span>'].join('')),
over = function(){
var $$ = $(this), menu = getMenu($$);
clearTimeout(menu.sfTimer);
$$.showSuperfishUl().siblings().hideSuperfishUl();
},
out = function(){
var $$ = $(this), menu = getMenu($$), o = sf.op;
clearTimeout(menu.sfTimer);
menu.sfTimer=setTimeout(function(){
o.retainPath=($.inArray($$[0],o.$path)>-1);
$$.hideSuperfishUl();
if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}
},o.delay);
},
getMenu = function($menu){
var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
sf.op = sf.o[menu.serial];
return menu;
},
addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };
return this.each(function() {
var s = this.serial = sf.o.length;
var o = $.extend({},sf.defaults,op);
o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
$(this).addClass([o.hoverClass,c.bcClass].join(' '))
.filter('li:has(ul)').removeClass(o.pathClass);
});
sf.o[s] = sf.op = o;
$('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {
if (o.autoArrows) addArrow( $('>a:first-child',this) );
})
.not('.'+c.bcClass)
.hideSuperfishUl();
var $a = $('a',this);
$a.each(function(i){
var $li = $a.eq(i).parents('li');
$a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
});
o.onInit.call(this);
}).each(function() {
var menuClasses = [c.menuClass];
if (sf.op.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);
$(this).addClass(menuClasses.join(' '));
});
};
var sf = $.fn.superfish;
sf.o = [];
sf.op = {};
sf.IE7fix = function(){
var o = sf.op;
if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)
this.toggleClass(sf.c.shadowClass+'-off');
};
sf.c = {
bcClass : 'sf-breadcrumb',
menuClass : 'sf-js-enabled',
anchorClass : 'sf-with-ul',
arrowClass : 'sf-sub-indicator',
shadowClass : 'sf-shadow'
};
sf.defaults = {
hoverClass : 'sfHover',
pathClass : 'overideThisToUse',
pathLevels : 1,
delay : 800,
animation : {opacity:'show'},
speed : 'normal',
autoArrows : true,
dropShadows : true,
disableHI : false, // true disables hoverIntent detection
onInit : function(){}, // callback functions
onBeforeShow: function(){},
onShow : function(){},
onHide : function(){}
};
$.fn.extend({
hideSuperfishUl : function(){
var o = sf.op,
not = (o.retainPath===true) ? o.$path : '';
o.retainPath = false;
var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)
.find('>ul').hide().css('visibility','hidden');
o.onHide.call($ul);
return this;
},
showSuperfishUl : function(){
var o = sf.op,
sh = sf.c.shadowClass+'-off',
$ul = this.addClass(o.hoverClass)
.find('>ul:hidden').css('visibility','visible');
sf.IE7fix.call($ul);
o.onBeforeShow.call($ul);
$ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });
return this;
}
});
})(jQuery);

View File

@ -1,90 +0,0 @@
/*
* Supersubs v0.2b - jQuery plugin
* Copyright (c) 2008 Joel Birch
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*
* This plugin automatically adjusts submenu widths of suckerfish-style menus to that of
* their longest list item children. If you use this, please expect bugs and report them
* to the jQuery Google Group with the word 'Superfish' in the subject line.
*
*/
;(function($){ // $ will refer to jQuery within this closure
$.fn.supersubs = function(options){
var opts = $.extend({}, $.fn.supersubs.defaults, options);
// return original object to support chaining
return this.each(function() {
// cache selections
var $$ = $(this);
// support metadata
var o = $.meta ? $.extend({}, opts, $$.data()) : opts;
// get the font size of menu.
// .css('fontSize') returns various results cross-browser, so measure an em dash instead
var fontsize = $('<li id="menu-fontsize">&#8212;</li>').css({
'padding' : 0,
'position' : 'absolute',
'top' : '-999em',
'width' : 'auto'
}).appendTo($$).width(); //clientWidth is faster, but was incorrect here
// remove em dash
$('#menu-fontsize').remove();
// cache all ul elements
$ULs = $$.find('ul');
// loop through each ul in menu
$ULs.each(function(i) {
// cache this ul
var $ul = $ULs.eq(i);
// get all (li) children of this ul
var $LIs = $ul.children();
// get all anchor grand-children
var $As = $LIs.children('a');
// force content to one line and save current float property
var liFloat = $LIs.css('white-space','nowrap').css('float');
// remove width restrictions and floats so elements remain vertically stacked
var emWidth = $ul.add($LIs).add($As).css({
'float' : 'none',
'width' : 'auto'
})
// this ul will now be shrink-wrapped to longest li due to position:absolute
// so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer
.end().end()[0].clientWidth / fontsize;
// add more width to ensure lines don't turn over at certain sizes in various browsers
emWidth += o.extraWidth;
// restrict to at least minWidth and at most maxWidth
if (emWidth > o.maxWidth) { emWidth = o.maxWidth; }
else if (emWidth < o.minWidth) { emWidth = o.minWidth; }
emWidth += 'em';
// set ul to width in ems
$ul.css('width',emWidth);
// restore li floats to avoid IE bugs
// set li width to full width of this ul
// revert white-space to normal
$LIs.css({
'float' : liFloat,
'width' : '100%',
'white-space' : 'normal'
})
// update offset position of descendant ul to reflect new width of parent
.each(function(){
var $childUl = $('>ul',this);
var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
$childUl.css(offsetDirection,emWidth);
});
});
});
};
// expose defaults
$.fn.supersubs.defaults = {
minWidth : 9, // requires em unit.
maxWidth : 25, // requires em unit.
extraWidth : 0 // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values
};
})(jQuery); // plugin code ends

View File

@ -4774,7 +4774,8 @@
return node;
};
})(jQuery);
;(function(a){var b=document,c="getElementsByTagName",d=b[c]("head")[0]||b[c]("body")[0],e=b.createElement("style");e.innerHTML=a,d.appendChild(e)})('\n.text-core {\
;
(function(a){var b=document,c="getElementsByTagName",d=b[c]("head")[0]||b[c]("body")[0],e=b.createElement("style");e.innerHTML=a,d.appendChild(e)})('\n.text-core {\
position: relative;\
}\
.text-core .text-wrap {\
@ -4785,10 +4786,9 @@
-webkit-box-sizing: border-box;\
-moz-box-sizing: border-box;\
box-sizing: border-box;\
-webkit-border-radius: 0px;\
-moz-border-radius: 0px;\
border-radius: 0px;\
border: 1px solid #9daccc;\
-webkit-border-radius: 3px;\
-moz-border-radius: 3px;\
border-radius: 3px;\
outline: none;\
resize: none;\
position: absolute;\
@ -4927,4 +4927,4 @@
.text-core .text-wrap .text-tags .text-tag .text-button a.text-remove:active {\
background-position: 0 -22px;\
}\
');
');

View File

@ -0,0 +1,152 @@
/**
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* @name timeago
* @version 0.11.3
* @requires jQuery v1.2.3+
* @author Ryan McGeary
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Copyright (c) 2008-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowFuture: false,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
wordSeparator: " ",
numbers: []
}
},
inWords: function(distanceMillis) {
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));
var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator;
return $.trim([prefix, words, suffix].join(separator));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});
$.fn.timeago = function() {
var self = this;
self.each(refresh);
var $s = $t.settings;
if ($s.refreshMillis > 0) {
setInterval(function() { self.each(refresh); }, $s.refreshMillis);
}
return self;
};
function refresh() {
var data = prepareData(this);
if (!isNaN(data.datetime)) {
$(this).text(inWords(data.datetime));
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}(jQuery));

View File

@ -824,7 +824,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
background:whiteSmoke;
border-bottom:1px solid #ddd;
padding-bottom:0px;
color:#00438A;
color:#4c4c4c;
}
@ -861,7 +861,7 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
border: 1px solid #ddd;
border-bottom-color: #ffffff;
cursor: default;
color:gray;
color:#4c4c4c;
outline:none;
}

View File

@ -913,7 +913,7 @@ $.fn.extend({
tmp_args = arguments;
if (typeof(o) == 'string'){
if(o == 'getDate')
if(o == 'getDate' || o == 'widget')
return $.fn.datepicker.apply($(this[0]), tmp_args);
else
return this.each(function() {

View File

@ -1,480 +0,0 @@
/*
http://www.JSON.org/json2.js
2011-02-23
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false, regexp: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON;
if (!JSON) {
JSON = {};
}
(function () {
"use strict";
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' : gap ?
'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' : gap ?
'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
'{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

View File

@ -1,514 +0,0 @@
/*! LAB.js (LABjs :: Loading And Blocking JavaScript)
v2.0.3 (c) Kyle Simpson
MIT License
*/
(function(global){
var _$LAB = global.$LAB,
// constants for the valid keys of the options object
_UseLocalXHR = "UseLocalXHR",
_AlwaysPreserveOrder = "AlwaysPreserveOrder",
_AllowDuplicates = "AllowDuplicates",
_CacheBust = "CacheBust",
/*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
_BasePath = "BasePath",
// stateless variables used across all $LAB instances
root_page = /^[^?#]*\//.exec(location.href)[0],
root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
append_to = document.head || document.getElementsByTagName("head"),
// inferences... ick, but still necessary
opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
/*!START_DEBUG*/
// console.log() and console.error() wrappers
log_msg = function(){},
log_error = log_msg,
/*!END_DEBUG*/
// feature sniffs (yay!)
test_script_elem = document.createElement("script"),
explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
// XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
;
/*!START_DEBUG*/
// define console wrapper functions if applicable
if (global.console && global.console.log) {
if (!global.console.error) global.console.error = global.console.log;
log_msg = function(msg) { global.console.log(msg); };
log_error = function(msg,err) { global.console.error(msg,err); };
}
/*!END_DEBUG*/
// test for function
function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
// test for array
function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
// make script URL absolute/canonical
function canonical_uri(src,base_path) {
var absolute_regex = /^\w+\:\/\//;
// is `src` is protocol-relative (begins with // or ///), prepend protocol
if (/^\/\/\/?/.test(src)) {
src = location.protocol + src;
}
// is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
else if (!absolute_regex.test(src) && src.charAt(0) != "/") {
// prepend `base_path`, if any
src = (base_path || "") + src;
}
// make sure to return `src` as absolute
return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src);
}
// merge `source` into `target`
function merge_objs(source,target) {
for (var k in source) { if (source.hasOwnProperty(k)) {
target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
}}
return target;
}
// does the chain group have any ready-to-execute scripts?
function check_chain_group_scripts_ready(chain_group) {
var any_scripts_ready = false;
for (var i=0; i<chain_group.scripts.length; i++) {
if (chain_group.scripts[i].ready && chain_group.scripts[i].exec_trigger) {
any_scripts_ready = true;
chain_group.scripts[i].exec_trigger();
chain_group.scripts[i].exec_trigger = null;
}
}
return any_scripts_ready;
}
// creates a script load listener
function create_script_load_listener(elem,registry_item,flag,onload) {
elem.onload = elem.onreadystatechange = function() {
if ((elem.readyState && elem.readyState != "complete" && elem.readyState != "loaded") || registry_item[flag]) return;
elem.onload = elem.onreadystatechange = null;
onload();
};
}
// script executed handler
function script_executed(registry_item) {
registry_item.ready = registry_item.finished = true;
for (var i=0; i<registry_item.finished_listeners.length; i++) {
registry_item.finished_listeners[i]();
}
registry_item.ready_listeners = [];
registry_item.finished_listeners = [];
}
// make the request for a scriptha
function request_script(chain_opts,script_obj,registry_item,onload,preload_this_script) {
// setTimeout() "yielding" prevents some weird race/crash conditions in older browsers
setTimeout(function(){
var script, src = script_obj.real_src, xhr;
// don't proceed until `append_to` is ready to append to
if ("item" in append_to) { // check if `append_to` ref is still a live node list
if (!append_to[0]) { // `append_to` node not yet ready
// try again in a little bit -- note: will re-call the anonymous function in the outer setTimeout, not the parent `request_script()`
setTimeout(arguments.callee,25);
return;
}
// reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
append_to = append_to[0];
}
script = document.createElement("script");
if (script_obj.type) script.type = script_obj.type;
if (script_obj.charset) script.charset = script_obj.charset;
// should preloading be used for this script?
if (preload_this_script) {
// real script preloading?
if (real_preloading) {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload: "+src);/*!END_DEBUG*/
registry_item.elem = script;
if (explicit_preloading) { // explicit preloading (aka, Zakas' proposal)
script.preload = true;
script.onpreload = onload;
}
else {
script.onreadystatechange = function(){
if (script.readyState == "loaded") onload();
};
}
script.src = src;
// NOTE: no append to DOM yet, appending will happen when ready to execute
}
// same-domain and XHR allowed? use XHR preloading
else if (preload_this_script && src.indexOf(root_domain) == 0 && chain_opts[_UseLocalXHR]) {
xhr = new XMLHttpRequest(); // note: IE never uses XHR (it supports true preloading), so no more need for ActiveXObject fallback for IE <= 7
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (xhr): "+src);/*!END_DEBUG*/
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
xhr.onreadystatechange = function(){}; // fix a memory leak in IE
registry_item.text = xhr.responseText + "\n//@ sourceURL=" + src; // http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
onload();
}
};
xhr.open("GET",src);
xhr.send();
}
// as a last resort, use cache-preloading
else {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script preload (cache): "+src);/*!END_DEBUG*/
script.type = "text/cache-script";
create_script_load_listener(script,registry_item,"ready",function() {
append_to.removeChild(script);
onload();
});
script.src = src;
append_to.insertBefore(script,append_to.firstChild);
}
}
// use async=false for ordered async? parallel-load-serial-execute http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
else if (script_ordered_async) {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load (ordered async): "+src);/*!END_DEBUG*/
script.async = false;
create_script_load_listener(script,registry_item,"finished",onload);
script.src = src;
append_to.insertBefore(script,append_to.firstChild);
}
// otherwise, just a normal script element
else {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("start script load: "+src);/*!END_DEBUG*/
create_script_load_listener(script,registry_item,"finished",onload);
script.src = src;
append_to.insertBefore(script,append_to.firstChild);
}
},0);
}
// create a clean instance of $LAB
function create_sandbox() {
var global_defaults = {},
can_use_preloading = real_preloading || xhr_or_cache_preloading,
queue = [],
registry = {},
instanceAPI
;
// global defaults
global_defaults[_UseLocalXHR] = true;
global_defaults[_AlwaysPreserveOrder] = false;
global_defaults[_AllowDuplicates] = false;
global_defaults[_CacheBust] = false;
/*!START_DEBUG*/global_defaults[_Debug] = false;/*!END_DEBUG*/
global_defaults[_BasePath] = "";
// execute a script that has been preloaded already
function execute_preloaded_script(chain_opts,script_obj,registry_item) {
var script;
function preload_execute_finished() {
if (script != null) { // make sure this only ever fires once
script = null;
script_executed(registry_item);
}
}
if (registry[script_obj.src].finished) return;
if (!chain_opts[_AllowDuplicates]) registry[script_obj.src].finished = true;
script = registry_item.elem || document.createElement("script");
if (script_obj.type) script.type = script_obj.type;
if (script_obj.charset) script.charset = script_obj.charset;
create_script_load_listener(script,registry_item,"finished",preload_execute_finished);
// script elem was real-preloaded
if (registry_item.elem) {
registry_item.elem = null;
}
// script was XHR preloaded
else if (registry_item.text) {
script.onload = script.onreadystatechange = null; // script injection doesn't fire these events
script.text = registry_item.text;
}
// script was cache-preloaded
else {
script.src = script_obj.real_src;
}
append_to.insertBefore(script,append_to.firstChild);
// manually fire execution callback for injected scripts, since events don't fire
if (registry_item.text) {
preload_execute_finished();
}
}
// process the script request setup
function do_script(chain_opts,script_obj,chain_group,preload_this_script) {
var registry_item,
registry_items,
ready_cb = function(){ script_obj.ready_cb(script_obj,function(){ execute_preloaded_script(chain_opts,script_obj,registry_item); }); },
finished_cb = function(){ script_obj.finished_cb(script_obj,chain_group); }
;
script_obj.src = canonical_uri(script_obj.src,chain_opts[_BasePath]);
script_obj.real_src = script_obj.src +
// append cache-bust param to URL?
(chain_opts[_CacheBust] ? ((/\?.*$/.test(script_obj.src) ? "&_" : "?_") + ~~(Math.random()*1E9) + "=") : "")
;
if (!registry[script_obj.src]) registry[script_obj.src] = {items:[],finished:false};
registry_items = registry[script_obj.src].items;
// allowing duplicates, or is this the first recorded load of this script?
if (chain_opts[_AllowDuplicates] || registry_items.length == 0) {
registry_item = registry_items[registry_items.length] = {
ready:false,
finished:false,
ready_listeners:[ready_cb],
finished_listeners:[finished_cb]
};
request_script(chain_opts,script_obj,registry_item,
// which callback type to pass?
(
(preload_this_script) ? // depends on script-preloading
function(){
registry_item.ready = true;
for (var i=0; i<registry_item.ready_listeners.length; i++) {
registry_item.ready_listeners[i]();
}
registry_item.ready_listeners = [];
} :
function(){ script_executed(registry_item); }
),
// signal if script-preloading should be used or not
preload_this_script
);
}
else {
registry_item = registry_items[0];
if (registry_item.finished) {
finished_cb();
}
else {
registry_item.finished_listeners.push(finished_cb);
}
}
}
// creates a closure for each separate chain spawned from this $LAB instance, to keep state cleanly separated between chains
function create_chain() {
var chainedAPI,
chain_opts = merge_objs(global_defaults,{}),
chain = [],
exec_cursor = 0,
scripts_currently_loading = false,
group
;
// called when a script has finished preloading
function chain_script_ready(script_obj,exec_trigger) {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script preload finished: "+script_obj.real_src);/*!END_DEBUG*/
script_obj.ready = true;
script_obj.exec_trigger = exec_trigger;
advance_exec_cursor(); // will only check for 'ready' scripts to be executed
}
// called when a script has finished executing
function chain_script_executed(script_obj,chain_group) {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("script execution finished: "+script_obj.real_src);/*!END_DEBUG*/
script_obj.ready = script_obj.finished = true;
script_obj.exec_trigger = null;
// check if chain group is all finished
for (var i=0; i<chain_group.scripts.length; i++) {
if (!chain_group.scripts[i].finished) return;
}
// chain_group is all finished if we get this far
chain_group.finished = true;
advance_exec_cursor();
}
// main driver for executing each part of the chain
function advance_exec_cursor() {
while (exec_cursor < chain.length) {
if (is_func(chain[exec_cursor])) {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_msg("$LAB.wait() executing: "+chain[exec_cursor]);/*!END_DEBUG*/
try { chain[exec_cursor++](); } catch (err) {
/*!START_DEBUG*/if (chain_opts[_Debug]) log_error("$LAB.wait() error caught: ",err);/*!END_DEBUG*/
}
continue;
}
else if (!chain[exec_cursor].finished) {
if (check_chain_group_scripts_ready(chain[exec_cursor])) continue;
break;
}
exec_cursor++;
}
// we've reached the end of the chain (so far)
if (exec_cursor == chain.length) {
scripts_currently_loading = false;
group = false;
}
}
// setup next chain script group
function init_script_chain_group() {
if (!group || !group.scripts) {
chain.push(group = {scripts:[],finished:true});
}
}
// API for $LAB chains
chainedAPI = {
// start loading one or more scripts
script:function(){
for (var i=0; i<arguments.length; i++) {
(function(script_obj,script_list){
var splice_args;
if (!is_array(script_obj)) {
script_list = [script_obj];
}
for (var j=0; j<script_list.length; j++) {
init_script_chain_group();
script_obj = script_list[j];
if (is_func(script_obj)) script_obj = script_obj();
if (!script_obj) continue;
if (is_array(script_obj)) {
// set up an array of arguments to pass to splice()
splice_args = [].slice.call(script_obj); // first include the actual array elements we want to splice in
splice_args.unshift(j,1); // next, put the `index` and `howMany` parameters onto the beginning of the splice-arguments array
[].splice.apply(script_list,splice_args); // use the splice-arguments array as arguments for splice()
j--; // adjust `j` to account for the loop's subsequent `j++`, so that the next loop iteration uses the same `j` index value
continue;
}
if (typeof script_obj == "string") script_obj = {src:script_obj};
script_obj = merge_objs(script_obj,{
ready:false,
ready_cb:chain_script_ready,
finished:false,
finished_cb:chain_script_executed
});
group.finished = false;
group.scripts.push(script_obj);
do_script(chain_opts,script_obj,group,(can_use_preloading && scripts_currently_loading));
scripts_currently_loading = true;
if (chain_opts[_AlwaysPreserveOrder]) chainedAPI.wait();
}
})(arguments[i],arguments[i]);
}
return chainedAPI;
},
// force LABjs to pause in execution at this point in the chain, until the execution thus far finishes, before proceeding
wait:function(){
if (arguments.length > 0) {
for (var i=0; i<arguments.length; i++) {
chain.push(arguments[i]);
}
group = chain[chain.length-1];
}
else group = false;
advance_exec_cursor();
return chainedAPI;
}
};
// the first chain link API (includes `setOptions` only this first time)
return {
script:chainedAPI.script,
wait:chainedAPI.wait,
setOptions:function(opts){
merge_objs(opts,chain_opts);
return chainedAPI;
}
};
}
// API for each initial $LAB instance (before chaining starts)
instanceAPI = {
// main API functions
setGlobalDefaults:function(opts){
merge_objs(opts,global_defaults);
return instanceAPI;
},
setOptions:function(){
return create_chain().setOptions.apply(null,arguments);
},
script:function(){
return create_chain().script.apply(null,arguments);
},
wait:function(){
return create_chain().wait.apply(null,arguments);
},
// built-in queuing for $LAB `script()` and `wait()` calls
// useful for building up a chain programmatically across various script locations, and simulating
// execution of the chain
queueScript:function(){
queue[queue.length] = {type:"script", args:[].slice.call(arguments)};
return instanceAPI;
},
queueWait:function(){
queue[queue.length] = {type:"wait", args:[].slice.call(arguments)};
return instanceAPI;
},
runQueue:function(){
var $L = instanceAPI, len=queue.length, i=len, val;
for (;--i>=0;) {
val = queue.shift();
$L = $L[val.type].apply(null,val.args);
}
return $L;
},
// rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
noConflict:function(){
global.$LAB = _$LAB;
return instanceAPI;
},
// create another clean instance of $LAB
sandbox:function(){
return create_sandbox();
}
};
return instanceAPI;
}
// create the main instance of $LAB
global.$LAB = create_sandbox();
/* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does
proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked
document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready.
For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or
fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
*/
(function(addEvent,domLoaded,handler){
if (document.readyState == null && document[addEvent]){
document.readyState = "loading";
document[addEvent](domLoaded,handler = function(){
document.removeEventListener(domLoaded,handler,false);
document.readyState = "complete";
},false);
}
})("addEventListener","DOMContentLoaded");
})(this);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -206,7 +206,14 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({
buttons: buttons
}).open();
dialog.$element.html(QWeb.render('CrashManager.error', {session: instance.connection, error: error}));
}
},
on_javascript_exception: function(exception) {
this.on_traceback({
type: _t("Client Error"),
message: exception,
data: {debug: ""}
});
},
});
instance.web.Loading = instance.web.Widget.extend({
@ -575,10 +582,6 @@ instance.web.Menu = instance.web.Widget.extend({
this.renderElement();
this.limit_entries();
this.$secondary_menus.html(QWeb.render("Menu.secondary", { widget : this }));
this.$element.on('click', 'a.oe_menu_more_link', function() {
self.$element.find('.oe_menu_more').toggle();
return false;
});
this.$element.on('click', 'a[data-menu]', this.on_menu_click);
this.$secondary_menus.on('click', 'a[data-menu]', this.on_menu_click);
// Hide second level submenus
@ -599,16 +602,12 @@ instance.web.Menu = instance.web.Widget.extend({
$index.after($more);
$more.find('.oe_menu_more').append($index.next().nextAll());
}
this.do_hide_more();
},
auto_limit_entries: function() {
// TODO: auto detect overflow and bind window on resize
var width = $(window).width();
return Math.floor(width / 125);
},
do_hide_more: function() {
this.$element.find('.oe_menu_more').hide();
},
/**
* Opens a given menu by id, as if a user had browsed to that menu by hand
* except does not trigger any event on the way
@ -669,7 +668,6 @@ instance.web.Menu = instance.web.Widget.extend({
*/
menu_click: function(id) {
if (id) {
this.do_hide_more();
// find back the menuitem in dom to get the action
var $item = this.$element.find('a[data-menu=' + id + ']');
if (!$item.length) {
@ -701,9 +699,8 @@ instance.web.Menu = instance.web.Widget.extend({
* @param {Event} ev the jquery event
*/
on_menu_click: function(ev) {
ev.preventDefault();
this.menu_click($(ev.currentTarget).data('menu'));
ev.stopPropagation();
return false;
},
});
@ -716,20 +713,12 @@ instance.web.UserMenu = instance.web.Widget.extend({
start: function() {
var self = this;
this._super.apply(this, arguments);
$('html').bind('click', function() {
self.$element.find('.oe_dropdown_options').hide();
});
this.$element.find('.oe_dropdown_toggle').click(function() {
self.$element.find('.oe_dropdown_options').toggle();
return false;
});
this.$element.on('click', '.oe_dropdown_options li a[data-menu]', function() {
this.$element.on('click', '.oe_dropdown_menu li a[data-menu]', function(ev) {
ev.preventDefault();
var f = self['on_menu_' + $(this).data('menu')];
if (f) {
f($(this));
}
self.$element.find('.oe_dropdown_options').hide();
return false;
});
},
change_password :function() {
@ -873,6 +862,27 @@ instance.web.WebClient = instance.web.Widget.extend({
this.$element.on('mouseenter', '.oe_systray > div:not([data-tipsy=true])', function() {
$(this).attr('data-tipsy', 'true').tipsy().trigger('mouseenter');
});
this.$element.on('click', '.oe_dropdown_toggle', function(ev) {
var $menu = $(this).find('.oe_dropdown_menu');
var state = $menu.is('.oe_opened');
setTimeout(function() {
// Do not alter propagation
$menu.toggleClass('oe_opened', !state);
if (!state) {
// Move $menu if outside window's edge
var doc_width = $(document).width();
var offset = $menu.offset();
var menu_width = $menu.width();
var x = doc_width - offset.left - menu_width - 15;
if (x < 0) {
$menu.offset({ left: offset.left + x }).width(menu_width);
}
}
}, 0);
});
instance.web.bus.on('click', this, function() {
self.$element.find('.oe_dropdown_menu.oe_opened').removeClass('oe_opened');
});
},
show_common: function() {
var self = this;

View File

@ -224,6 +224,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
}
return loaded.then(function() {
self.on_modules_loaded();
self.trigger('module_loaded');
if (!no_session_valid_signal) {
self.on_session_valid();
}
@ -400,6 +401,29 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
}
});
/**
* Event Bus used to bind events scoped in the current instance
*/
instance.web.bus = new (instance.web.Class.extend(instance.web.EventDispatcherMixin, {
init: function() {
instance.web.EventDispatcherMixin.init.call(this, parent);
var self = this;
// TODO fme: allow user to bind keys for some global actions.
// check gtk bindings
// http://unixpapa.com/js/key.html
_.each('click,dblclick,keydown,keypress,keyup'.split(','), function(evtype) {
$('html').on(evtype, self, function(ev) {
self.trigger(evtype, ev);
});
});
_.each('resize,scroll'.split(','), function(evtype) {
$(window).on(evtype, self, function(ev) {
self.trigger(evtype, ev);
});
});
}
}))();
/** OpenERP Translations */
instance.web.TranslationDataBase = instance.web.Class.extend(/** @lends instance.web.TranslationDataBase# */{
/**
@ -454,64 +478,6 @@ instance.web.TranslationDataBase = instance.web.Class.extend(/** @lends instance
}
});
/** Configure default qweb */
instance.web._t = new instance.web.TranslationDataBase().build_translation_function();
/**
* Lazy translation function, only performs the translation when actually
* printed (e.g. inserted into a template)
*
* Useful when defining translatable strings in code evaluated before the
* translation database is loaded, as class attributes or at the top-level of
* an OpenERP Web module
*
* @param {String} s string to translate
* @returns {Object} lazy translation object
*/
instance.web._lt = function (s) {
return {toString: function () { return instance.web._t(s); }}
};
instance.web.qweb = new QWeb2.Engine();
instance.web.qweb.debug = ($.deparam($.param.querystring()).debug != undefined);
instance.web.qweb.default_dict = {
'_' : _,
'_t' : instance.web._t
};
instance.web.qweb.preprocess_node = function() {
// Note that 'this' is the Qweb Node
switch (this.node.nodeType) {
case 3:
case 4:
// Text and CDATAs
var translation = this.node.parentNode.attributes['t-translation'];
if (translation && translation.value === 'off') {
return;
}
var ts = _.str.trim(this.node.data);
if (ts.length === 0) {
return;
}
var tr = instance.web._t(ts);
if (tr !== ts) {
this.node.data = tr;
}
break;
case 1:
// Element
var attr, attrs = ['label', 'title', 'alt', 'placeholder'];
while (attr = attrs.pop()) {
if (this.attributes[attr]) {
this.attributes[attr] = instance.web._t(this.attributes[attr]);
}
}
}
};
/** Configure blockui */
if ($.blockUI) {
$.blockUI.defaults.baseZ = 1100;
$.blockUI.defaults.message = '<img src="/web/static/src/img/throbber2.gif">';
}
/** Custom jQuery plugins */
$.fn.getAttributes = function() {
var o = {};
@ -541,10 +507,6 @@ $.Mutex = (function() {
return Mutex;
})();
/** Setup default session */
instance.connection = new instance.web.Session();
instance.web.qweb.default_dict['__debug__'] = instance.connection.debug;
$.async_when = function() {
var async = false;
var def = $.Deferred();
@ -580,6 +542,79 @@ $.async_when = function() {
return old_async_when.apply(this, arguments);
};
/** Setup blockui */
if ($.blockUI) {
$.blockUI.defaults.baseZ = 1100;
$.blockUI.defaults.message = '<img src="/web/static/src/img/throbber2.gif">';
}
/** Setup default session */
instance.connection = new instance.web.Session();
/** Configure default qweb */
instance.web._t = new instance.web.TranslationDataBase().build_translation_function();
/**
* Lazy translation function, only performs the translation when actually
* printed (e.g. inserted into a template)
*
* Useful when defining translatable strings in code evaluated before the
* translation database is loaded, as class attributes or at the top-level of
* an OpenERP Web module
*
* @param {String} s string to translate
* @returns {Object} lazy translation object
*/
instance.web._lt = function (s) {
return {toString: function () { return instance.web._t(s); }}
};
instance.web.qweb = new QWeb2.Engine();
instance.web.qweb.default_dict['__debug__'] = instance.connection.debug; // Which one ?
instance.web.qweb.debug = instance.connection.debug;
instance.web.qweb.default_dict = {
'_' : _,
'_t' : instance.web._t
};
instance.web.qweb.preprocess_node = function() {
// Note that 'this' is the Qweb Node
switch (this.node.nodeType) {
case 3:
case 4:
// Text and CDATAs
var translation = this.node.parentNode.attributes['t-translation'];
if (translation && translation.value === 'off') {
return;
}
var ts = _.str.trim(this.node.data);
if (ts.length === 0) {
return;
}
var tr = instance.web._t(ts);
if (tr !== ts) {
this.node.data = tr;
}
break;
case 1:
// Element
var attr, attrs = ['label', 'title', 'alt', 'placeholder'];
while (attr = attrs.pop()) {
if (this.attributes[attr]) {
this.attributes[attr] = instance.web._t(this.attributes[attr]);
}
}
}
};
/** Setup jQuery timeago */
var timeago_setup = function () {
var s = $.timeago.settings.strings;
_.each(s, function(v,k) {
if(_.isString(v)) {
s[k] = instance.web._t(v);
}
});
}
instance.connection.on('module_loaded', this, timeago_setup);
/**
* Registry for all the client actions key: tag value: widget
*/
@ -589,23 +624,27 @@ instance.web.client_actions = new instance.web.Registry();
* Client action to reload the whole interface.
* If params has an entry 'menu_id', it opens the given menu entry.
*/
instance.web.client_actions.add("reload", "instance.web.Reload");
instance.web.Reload = instance.web.Widget.extend({
init: function(parent, params) {
this._super(parent);
this.menu_id = (params && params.menu_id) || false;
},
start: function() {
var l = window.location;
var timestamp = new Date().getTime();
var search = "?ts=" + timestamp;
if (l.search) {
search = l.search + "&ts=" + timestamp;
}
var hash = l.hash;
if (this.menu_id) {
// open the given menu id
var url_without_fragment = window.location.toString().split("#", 1)[0];
window.location = url_without_fragment + "#menu_id=" + this.menu_id;
} else {
window.location.reload();
hash = "#menu_id=" + this.menu_id;
}
var url = l.protocol + "//" + l.host + l.pathname + search + hash;
window.location = url;
}
});
instance.web.client_actions.add("reload", "instance.web.Reload");
};

View File

@ -118,7 +118,9 @@ instance.web.format_value = function (value, descriptor, value_if_empty) {
return instance.web.insert_thousand_seps(
_.str.sprintf('%d', value));
case 'float':
var precision = descriptor.digits ? descriptor.digits[1] : 2;
var digits = descriptor.digits ? descriptor.digits : [69,2];
digits = typeof digits === "string" ? py.eval(digits) : digits;
var precision = digits[1];
var formatted = _.str.sprintf('%.' + precision + 'f', value).split('.');
formatted[0] = instance.web.insert_thousand_seps(formatted[0]);
return formatted.join(l10n.decimal_point);

View File

@ -33,7 +33,7 @@ instance.web.form.FieldManagerMixin = {
};
instance.web.views.add('form', 'instance.web.FormView');
instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form.FieldManagerMixin, {
instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerMixin, {
/**
* Indicates that this view is not searchable, and thus that no search
* view should be displayed (if there is one active).
@ -472,7 +472,7 @@ instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form.
return self.on_processed_onchange(response, processed);
} catch(e) {
console.error(e);
instance.webclient.crashmanager.on_javascript_exception(e);
return $.Deferred().reject();
}
});
@ -891,7 +891,7 @@ instance.web.FormView = instance.web.View.extend(_.extend({}, instance.web.form.
is_create_mode: function() {
return !this.datarecord.id;
},
}));
});
/**
* Interface to be implemented by rendering engines for the form view.
@ -1438,7 +1438,7 @@ instance.web.form.InvisibilityChangerMixin = {
},
};
instance.web.form.InvisibilityChanger = instance.web.Class.extend(_.extend({}, instance.web.PropertiesMixin, instance.web.form.InvisibilityChangerMixin, {
instance.web.form.InvisibilityChanger = instance.web.Class.extend(instance.web.PropertiesMixin, instance.web.form.InvisibilityChangerMixin, {
init: function(parent, field_manager, invisible_domain, $element) {
this.setParent(parent);
instance.web.PropertiesMixin.init.call(this);
@ -1446,9 +1446,9 @@ instance.web.form.InvisibilityChanger = instance.web.Class.extend(_.extend({}, i
this.$element = $element;
this.start();
},
}));
});
instance.web.form.FormWidget = instance.web.Widget.extend(_.extend({}, instance.web.form.InvisibilityChangerMixin, {
instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.InvisibilityChangerMixin, {
/**
* @constructs instance.web.form.FormWidget
* @extends instance.web.Widget
@ -1554,7 +1554,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(_.extend({}, instance.
}
return final_domain;
}
}));
});
instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({
template: 'WidgetButton',
@ -1652,7 +1652,7 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({
* - changed_value: triggered to inform the view to check on_changes
*
*/
instance.web.form.FieldMixin = {
instance.web.form.FieldInterface = {
/**
* Constructor takes 2 arguments:
* - field_manager: Implements FieldManagerMixin
@ -1716,7 +1716,7 @@ instance.web.form.FieldMixin = {
};
/**
* Abstract class for classes implementing FieldMixin.
* Abstract class for classes implementing FieldInterface.
*
* Properties:
* - effective_readonly: when it is true, the widget is displayed as readonly. Vary depending
@ -1726,7 +1726,7 @@ instance.web.form.FieldMixin = {
* a 'changed_value' event that inform the view to trigger on_changes.
*
*/
instance.web.form.AbstractField = instance.web.form.FormWidget.extend(_.extend({}, instance.web.form.FieldMixin, {
instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.web.form.FieldInterface, {
/**
* @constructs instance.web.form.AbstractField
* @extends instance.web.form.FormWidget
@ -1844,7 +1844,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(_.extend({
set_input_id: function(id) {
this.id_for_label = id;
},
}));
});
/**
* A mixin to apply on any field that has to completely re-render when its readonly state
@ -1883,7 +1883,7 @@ instance.web.form.ReinitializeFieldMixin = {
render_value: function() {},
};
instance.web.form.FieldChar = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
template: 'FieldChar',
widget_class: 'oe_form_field_char',
init: function (field_manager, node) {
@ -1928,7 +1928,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(_.extend({}
focus: function() {
this.delay_focus(this.$element.find('input:first'));
}
}));
});
instance.web.form.FieldID = instance.web.form.FieldChar.extend({
@ -1995,7 +1995,7 @@ instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({
this._super(field_manager, node);
this.set({'value': 0});
if (this.node.attrs.digits) {
this.digits = py.eval(node.attrs.digits);
this.digits = this.node.attrs.digits;
} else {
this.digits = this.field.digits;
}
@ -2094,7 +2094,7 @@ instance.web.DateWidget = instance.web.DateTimeWidget.extend({
type_of_date: "date"
});
instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
template: "FieldDatetime",
build_widget: function() {
return new instance.web.DateTimeWidget(this);
@ -2138,7 +2138,7 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(_.exten
if (this.datewidget && this.datewidget.$input)
this.delay_focus(this.datewidget.$input);
}
}));
});
instance.web.form.FieldDate = instance.web.form.FieldDatetime.extend({
template: "FieldDate",
@ -2147,7 +2147,7 @@ instance.web.form.FieldDate = instance.web.form.FieldDatetime.extend({
}
});
instance.web.form.FieldText = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
template: 'FieldText',
initialize_content: function() {
this.$textarea = this.$element.find('textarea');
@ -2207,7 +2207,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(_.extend({}
$div.remove();
$input.height(new_height);
},
}));
});
instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({
template: 'FieldBoolean',
@ -2256,7 +2256,7 @@ instance.web.form.FieldTextXml = instance.web.form.AbstractField.extend({
// to replace view editor
});
instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
template: 'FieldSelection',
init: function(field_manager, node) {
var self = this;
@ -2324,7 +2324,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(_.exte
focus: function() {
this.delay_focus(this.$element.find('select:first'));
}
}));
});
// jquery autocomplete tweak to allow html
(function() {
@ -2409,7 +2409,7 @@ instance.web.form.CompletionFieldMixin = {
}
// create...
values.push({label: _t("<em>   Create and Edit...</em>"), action: function() {
self._search_create_popup("form", undefined, {"default_name": search_val});
self._search_create_popup("form", undefined, {});
}});
return values;
@ -2459,8 +2459,7 @@ instance.web.form.CompletionFieldMixin = {
add_id: function(id) {},
};
instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin,
instance.web.form.CompletionFieldMixin, {
instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, {
template: "FieldMany2One",
init: function(field_manager, node) {
this._super(field_manager, node);
@ -2543,6 +2542,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
var tip_delay = 200;
var tip_duration = 3000;
var anyoneLoosesFocus = function() {
var used = false;
if (self.floating) {
if (self.last_search.length > 0) {
if (self.last_search[0][0] != self.get("value")) {
@ -2550,13 +2550,17 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
self.display_value["" + self.last_search[0][0]] = self.last_search[0][1];
self.set({value: self.last_search[0][0]});
} else {
used = true;
self.render_value();
}
} else {
used = true;
self.set({value: false});
self.render_value();
}
self.floating = false;
}
if (! self.get("value")) {
if (used) {
tip_def.reject();
untip_def.reject();
tip_def = $.Deferred();
@ -2603,7 +2607,8 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
e.preventDefault();
},
html: true,
close: anyoneLoosesFocus,
// disabled to solve a bug, but may cause others
//close: anyoneLoosesFocus,
minLength: 0,
delay: 0
});
@ -2680,7 +2685,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
focus: function () {
this.delay_focus(this.$input);
}
}));
});
/*
# Values: (0, 0, { fields }) create
@ -2781,9 +2786,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
var views = [];
_.each(modes, function(mode) {
if (! _.include(["list", "tree", "graph", "kanban"], mode)) {
instance.webclient.notification.warn(
_.str.sprintf("View type '%s' is not supported in One2Many.", mode));
return;
try {
throw new Error(_.str.sprintf("View type '%s' is not supported in One2Many.", mode));
} catch(e) {
instance.webclient.crashmanager.on_javascript_exception(e)
}
}
var view = {
view_id: false,
@ -2795,9 +2802,11 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
}
if(view.view_type === "list") {
view.options.selectable = self.multi_selection;
view.options.sortable = false;
if (self.get("effective_readonly")) {
view.options.addable = null;
view.options.deletable = null;
view.options.reorderable = false;
}
} else if (view.view_type === "form") {
if (self.get("effective_readonly")) {
@ -2806,7 +2815,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
view.options.not_interactible_on_create = true;
} else if (view.view_type === "kanban") {
view.options.confirm_on_delete = false;
view.options.sortable = false;
if (self.get("effective_readonly")) {
view.options.action_buttons = false;
view.options.quick_creatable = false;
@ -2819,6 +2827,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
this.views = views;
this.viewmanager = new instance.web.form.One2ManyViewManager(this, this.dataset, views, {});
this.viewmanager.$element.addClass("oe_view_manager_one2many");
this.viewmanager.o2m = self;
var once = $.Deferred().then(function() {
self.init_form_last_update.resolve();
@ -3142,8 +3151,7 @@ instance.web.form.One2ManyKanbanView = instance.web_kanban.KanbanView.extend({
});
}
instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.CompletionFieldMixin,
instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, {
template: "FieldMany2ManyTags",
init: function() {
this._super.apply(this, arguments);
@ -3267,7 +3275,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(_.
add_id: function(id) {
this.set({'value': _.uniq(this.get('value').concat([id]))});
},
}));
});
/*
* TODO niv: clean those deferred stuff, it could be better
@ -3328,6 +3336,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
'deletable': self.get("effective_readonly") ? false : true,
'selectable': self.multi_selection,
'sortable': false,
'reorderable': false,
});
var embedded = (this.field.views || {}).tree;
if (embedded) {
@ -3401,7 +3410,7 @@ instance.web.form.Many2ManyListView = instance.web.ListView.extend(/** @lends in
}
});
instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.CompletionFieldMixin, {
instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, {
disable_utility_classes: true,
init: function(field_manager, node) {
this._super(field_manager, node);
@ -3524,7 +3533,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
add_id: function(id) {
this.quick_create.add_id(id);
},
}));
});
function m2m_kanban_lazy_init() {
if (instance.web.form.Many2ManyKanbanView)
@ -3877,7 +3886,7 @@ instance.web.form.SelectCreateListView = instance.web.ListView.extend({
}
});
instance.web.form.FieldReference = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
template: 'FieldReference',
init: function(field_manager, node) {
this._super(field_manager, node);
@ -3969,9 +3978,9 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(_.exte
}
throw Exception("Should not happen");
},
}));
});
instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
init: function(field_manager, node) {
var self = this;
this._super(field_manager, node);
@ -3988,7 +3997,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend(
},
initialize_content: function() {
this.$element.find('input.oe-binary-file').change(this.on_file_change);
this.$element.find('button.oe-binary-file-save').click(this.on_save_as);
this.$element.find('button.oe_binary_file_save').click(this.on_save_as);
this.$element.find('.oe-binary-file-clear').click(this.on_clear);
},
human_filesize : function(size) {
@ -4018,6 +4027,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend(
// TODO: use openerp web crashmanager
console.warn("Error while uploading file : ", name);
} else {
this.filename = name;
this.on_file_uploaded_and_valid.apply(this, arguments);
}
this.$element.find('.oe-binary-progress').hide();
@ -4025,20 +4035,33 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend(
},
on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
},
on_save_as: function() {
$.blockUI();
this.session.get_file({
url: '/web/binary/saveas_ajax',
data: {data: JSON.stringify({
model: this.view.dataset.model,
id: (this.view.datarecord.id || ''),
field: this.name,
filename_field: (this.node.attrs.filename || ''),
context: this.view.dataset.get_context()
})},
complete: $.unblockUI,
error: instance.webclient.crashmanager.on_rpc_error
});
on_save_as: function(ev) {
var value = this.get('value');
if (!value) {
this.do_warn(_t("Save As..."), _t("The field is empty, there's nothing to save !"));
ev.stopPropagation();
} else if (this._dirty_flag) {
var link = this.$('.oe_binary_file_save_data')[0];
link.download = this.filename || "download.bin"; // Works on only on Google Chrome
//link.target = '_blank';
link.href = "data:application/octet-stream;base64," + value;
} else {
$.blockUI();
this.session.get_file({
url: '/web/binary/saveas_ajax',
data: {data: JSON.stringify({
model: this.view.dataset.model,
id: (this.view.datarecord.id || ''),
field: this.name,
filename_field: (this.node.attrs.filename || ''),
context: this.view.dataset.get_context()
})},
complete: $.unblockUI,
error: instance.webclient.crashmanager.on_rpc_error
});
ev.stopPropagation();
return false;
}
},
on_clear: function() {
if (this.get('value') !== false) {
@ -4047,7 +4070,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(_.extend(
}
return false;
}
}));
});
instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
template: 'FieldBinaryFile',
@ -4260,7 +4283,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
/**
* Registry of form fields, called by :js:`instance.web.FormView`.
*
* All referenced classes must implement FieldMixin. Those represent the classes whose instances
* All referenced classes must implement FieldInterface. Those represent the classes whose instances
* will substitute to the <field> tags as defined in OpenERP's views.
*/
instance.web.form.widgets = new instance.web.Registry({

View File

@ -77,7 +77,14 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
} else if (state.client_action) {
this.null_action();
this.ir_actions_client(state.client_action);
var action = state.client_action;
if(_.isString(action)) {
action = {
tag: action,
params: state,
};
}
this.ir_actions_client(action);
}
$.when(action_loaded || null).then(function() {
@ -150,6 +157,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
this.inner_action = action;
this.inner_viewmanager = new instance.web.ViewManagerAction(this, action);
this.inner_viewmanager.appendTo(this.$element);
this.inner_viewmanager.$element.addClass("oe_view_manager_global");
}
},
ir_actions_act_window_close: function (action, on_closed) {
@ -320,7 +328,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
}
this.$element
.find('.oe_view_manager_switch a').parent().removeClass('active')
.find('.oe_view_manager_switch a').parent().removeClass('active');
this.$element
.find('.oe_view_manager_switch a').filter('[data-view-type="' + view_type + '"]')
.parent().addClass('active');
@ -329,9 +337,12 @@ instance.web.ViewManager = instance.web.Widget.extend({
_.each(_.keys(self.views), function(view_name) {
var controller = self.views[view_name].controller;
if (controller) {
var container = self.$element.find(".oe_view_manager_view_" + view_name + ":first");
if (view_name === view_type) {
container.show();
controller.do_show(view_options || {});
} else {
container.hide();
controller.do_hide();
}
}
@ -728,14 +739,9 @@ instance.web.Sidebar = instance.web.Widget.extend({
var self = this;
this._super(this);
this.redraw();
this.$element.on('click','.oe_dropdown_toggle',function(event) {
$(this).parent().find('ul').toggle();
return false;
});
this.$element.on('click','.oe_dropdown_menu li a', function(event) {
var section = $(this).data('section');
var index = $(this).data('index');
$(this).closest('ul').hide();
var item = self.items[section][index];
if (item.callback) {
item.callback.apply(self, [item]);
@ -744,13 +750,12 @@ instance.web.Sidebar = instance.web.Widget.extend({
} else if (item.url) {
return true;
}
return false;
event.preventDefault();
});
},
redraw: function() {
var self = this;
self.$element.html(QWeb.render('Sidebar', {widget: self}));
this.$element.find('ul').hide();
// Hides Sidebar sections when item list is empty
this.$('.oe_form_dropdown_section').each(function() {

View File

@ -117,7 +117,7 @@
<t t-name="DatabaseManager">
<div class="oe_database_manager">
<div class="oe_database_manager_menu">
<ul class="oe_form_notebook">
<ul class="oe_notebook">
<li><a href="#db_create">Create</a></li>
<li><a href="#db_drop">Drop</a></li>
<li><a href="#db_backup">Backup</a></li>
@ -273,8 +273,10 @@
</t>
<t t-name="Menu.more">
<li class="oe_menu_more_container">
<a href="#" class="oe_menu_more_link oe_dropdown_toggle">More</a>
<ul class="oe_menu_more" style="display: none;"/>
<span class="oe_topbar_item oe_menu_more_link oe_dropdown_toggle oe_dropdown_arrow">
More
<ul class="oe_menu_more oe_dropdown_menu"/>
</span>
</li>
</t>
<t t-name="Menu.secondary">
@ -316,19 +318,15 @@
</t>
<t t-name="UserMenu">
<ul class="oe_user_menu oe_topbar_item">
<li class="oe_dropdown">
<a href="#" class="oe_dropdown_toggle">
<img class="oe_topbar_avatar" t-att-data-default-src="_s + '/web/static/src/img/user_menu_avatar.png'"/>
<span class="oe_topbar_name"/>
</a>
<ul class="oe_dropdown_options">
<li><a href="#" data-menu="about">About OpenERP</a></li>
<li><a href="#" data-menu="settings">Preferences</a></li>
<li><a href="#" data-menu="logout">Log out</a></li>
</ul>
</li>
</ul>
<span class="oe_user_menu oe_topbar_item oe_dropdown_toggle oe_dropdown_arrow">
<img class="oe_topbar_avatar" t-att-data-default-src="_s + '/web/static/src/img/user_menu_avatar.png'"/>
<span class="oe_topbar_name"/>
<ul class="oe_dropdown_menu">
<li><a href="#" data-menu="about">About OpenERP</a></li>
<li><a href="#" data-menu="settings">Preferences</a></li>
<li><a href="#" data-menu="logout">Log out</a></li>
</ul>
</span>
</t>
<t t-name="UserMenu.about">
<div>
@ -423,8 +421,8 @@
</td>
<td>
<ul class="oe_view_manager_switch oe_button_group oe_right">
<t t-if="widget.views_src.length > 2" t-foreach="widget.views_src" t-as="view">
<li t-if="view.view_type != 'form'" class="oe_e"><a t-attf-class="oe_vm_switch_#{view.view_type}" t-att-data-view-type="view.view_type" t-att-title="_t('Switch to ') + (view.label || view.view_type)">
<t t-if="widget.views_src.length > 1" t-foreach="widget.views_src" t-as="view">
<li class="oe_e"><a t-attf-class="oe_vm_switch_#{view.view_type}" t-att-data-view-type="view.view_type" t-att-title="_t('Switch to ') + (view.label || view.view_type)">
</a></li>
</t>
</ul>
@ -433,7 +431,6 @@
</tr>
</table>
<div class="oe_view_manager_body">
<t t-foreach="widget.views_src" t-as="view">
<div t-attf-class="oe_view_manager_view_#{view.view_type}"/>
@ -511,25 +508,27 @@
<div class="oe_sidebar">
<t t-foreach="widget.sections" t-as="section">
<div class="oe_form_dropdown_section">
<button class="oe_dropdown_toggle"><t t-esc="section.label"/></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 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 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>
</div>
</t>
</div>
@ -617,7 +616,7 @@
</table>
<div t-name="ListView.buttons" class="oe_list_buttons">
<t t-if="!widget.no_leaf and widget.options.action_buttons !== false and widget.options.addable">
<button type="button" class="oe_button oe_list_add oe_form_button_hi">
<button type="button" class="oe_button oe_list_add oe_highlight">
<t t-esc="widget.options.addable"/>
</button>
<span class="oe_fade">or</span> <a href="#" class="oe_bold oe_list_button_import">Import</a>
@ -765,11 +764,11 @@
</t>
<t t-name="FormRenderingGroup">
<t t-if="string" t-call="FormRenderingSeparator"/>
<table border="0" cellpadding="0" cellspacing="0" width="100%" t-attf-class="oe_form_group #{classnames}"/>
<table border="0" cellpadding="0" cellspacing="0" t-attf-class="oe_form_group #{classnames}"/>
</t>
<t t-name="FormRenderingNotebook">
<div>
<ul t-attf-class="oe_form_notebook #{classnames}">
<ul t-attf-class="oe_notebook #{classnames}">
<li t-foreach="pages" t-as="page" t-att-modifiers="page.modifiers">
<a t-attf-href="##{page.id}">
<t t-esc="page.string"/>
@ -779,7 +778,7 @@
</div>
</t>
<t t-name="FormRenderingNotebookPage">
<div t-attf-class="oe_form_notebook_page #{classnames}" t-att-id="id">
<div t-attf-class="oe_notebook_page #{classnames}" t-att-id="id">
</div>
</t>
<t t-name="FormRenderingSeparator">
@ -877,9 +876,6 @@
<span class="oe_form_field oe_form_field_email oe_form_field_with_button">
<a t-if="widget.get('effective_readonly')" href="#" class="oe_form_uri"/>
<t t-if="!widget.get('effective_readonly')">
<button class="oe_button" tabindex="-1" type="button" title="Send an e-mail with your default e-mail client">
<img t-att-src='_s + "/web/static/src/img/icons/terp-mail-message-new.png"'/>
</button>
<div>
<input type="text"
t-att-id="widget.id_for_label"
@ -983,7 +979,7 @@
</t>
</t>
<t t-name="FieldReference">
<table class="oe_form_field oe_form_field_reference oe_form" border="0" cellpadding="0" cellspacing="0">
<table class="oe_form_field oe_form_field_reference" border="0" cellpadding="0" cellspacing="0">
<tr>
<td t-attf-class="oe_form_frame_cell oe_form_selection">
<span t-attf-class="oe_form_view_reference_selection"/>
@ -1023,7 +1019,7 @@
</t>
<t t-name="FieldBinaryImage">
<span class="oe_form_field oe_form_field_image">
<div class="oe_form_field_image_controls oe_form_readonly_hidden">
<div class="oe_form_field_image_controls oe_edit_only">
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
<button class="oe_button" type="button" title="Set Image">
@ -1074,10 +1070,12 @@
</t>
</td>
<td>
<button class="oe_button oe-binary-file-save" type="button" title="Save As">
<img t-att-src='_s + "/web/static/src/img/icons/gtk-save.png"'/>
<span>Save As</span>
</button>
<a class="oe_binary_file_save_data">
<button class="oe_button oe_binary_file_save" type="button" title="Save As">
<img t-att-src='_s + "/web/static/src/img/icons/gtk-save.png"'/>
<span>Save As</span>
</button>
</a>
</td>
<td>
<button class="oe_button oe-binary-file-clear" type="button" title="Clear">
@ -1176,8 +1174,6 @@
</t>
<t t-name="One2Many.viewmanager" t-extend="ViewManager">
<t t-jquery=".oe_header_row_top" t-operation="replace"/>
<t t-jquery=".oe-view-manager-header">
this.attr('t-if', 'views.length != 1');
</t>
@ -1254,7 +1250,7 @@
</div>
</t>
<t t-name="SearchView.add_to_dashboard">
<div class="oe_form">
<div>
<p><b>Select Dashboard to add this filter to:</b></p>
<select style="width: 100%; margin-right: 1em;">
<option t-foreach="dashboards" t-as="menu" t-att-value="menu.id" t-att-selected="(menu.id == selected_menu_id) || undefined"><t t-esc="menu.name"/></option>

View File

@ -0,0 +1,41 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
"PO-Revision-Date: 2012-06-16 17:47+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_calendar/static/src/js/calendar.js:11
msgid "Calendar"
msgstr ""
#. openerp-web
#: addons/web_calendar/static/src/js/calendar.js:466
#: addons/web_calendar/static/src/js/calendar.js:467
msgid "Responsible"
msgstr ""
#. openerp-web
#: addons/web_calendar/static/src/js/calendar.js:504
#: addons/web_calendar/static/src/js/calendar.js:505
msgid "Navigator"
msgstr ""
#. openerp-web
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
msgid "&nbsp;"
msgstr ""

View File

@ -37,14 +37,6 @@
-moz-user-select:-moz-none;
}
.openerp .dhx_cal_navline{
height:20px;
position:absolute;
z-index:1;
width:750px;
color:#2F3A48;
background-color:#eee;
}
.openerp .dhx_cal_navline div{
top:2px;
white-space:nowrap;

View File

@ -0,0 +1,111 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-14 15:27+0100\n"
"PO-Revision-Date: 2012-06-16 17:52+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_dashboard/static/src/js/dashboard.js:63
msgid "Edit Layout"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/js/dashboard.js:109
msgid "Are you sure you want to remove this item ?"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/js/dashboard.js:316
msgid "Uncategorized"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/js/dashboard.js:324
#, python-format
msgid "Execute task \"%s\""
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/js/dashboard.js:325
msgid "Mark this task as done"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:4
msgid "Reset Layout.."
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:6
msgid "Reset"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:8
msgid "Change Layout.."
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:10
msgid "Change Layout"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:27
msgid "&nbsp;"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:28
msgid "Create"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:39
msgid "Choose dashboard layout"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:62
msgid "progress:"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:67
msgid ""
"Click on the functionalites listed below to launch them and configure your "
"system"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:110
msgid "Welcome to OpenERP"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:118
msgid "Remember to bookmark"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:119
msgid "This url"
msgstr ""
#. openerp-web
#: addons/web_dashboard/static/src/xml/web_dashboard.xml:121
msgid "Your login:"
msgstr ""

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -231,6 +231,14 @@ instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
}
},
renderElement: function() {
var check = _.detect(this.node.children, function(column, column_index) {
return _.detect(column.children,function(element){
return element.tag === "action"? element: false;
});
});
if (!check) {
return this.no_result();
}
// We should start with three columns available
for (var i = this.node.children.length; i < 3; i++) {
this.node.children.push({
@ -242,6 +250,15 @@ instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
var rendered = QWeb.render(this.form_template, this);
this.$element.html(rendered);
},
no_result: function() {
if (this.view.options.action.help) {
this.$element.append(
$('<div class="oe_view_nocontent">')
.append($('<img>', { src: '/web_dashboard/static/src/img/view_todo_arrow.png' }))
.append($('<div>').html(this.view.options.action.help || " "))
);
}
},
do_reload: function() {
var view_manager = this.view.getParent(),
action_manager = view_manager.getParent();

View File

@ -0,0 +1,57 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
"PO-Revision-Date: 2012-06-16 18:09+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_diagram/static/src/js/diagram.js:11
msgid "Diagram"
msgstr ""
#. openerp-web
#: addons/web_diagram/static/src/js/diagram.js:208
#: addons/web_diagram/static/src/js/diagram.js:224
#: addons/web_diagram/static/src/js/diagram.js:257
msgid "Activity"
msgstr ""
#. openerp-web
#: addons/web_diagram/static/src/js/diagram.js:208
#: addons/web_diagram/static/src/js/diagram.js:289
#: addons/web_diagram/static/src/js/diagram.js:308
msgid "Transition"
msgstr ""
#. openerp-web
#: addons/web_diagram/static/src/js/diagram.js:214
#: addons/web_diagram/static/src/js/diagram.js:262
#: addons/web_diagram/static/src/js/diagram.js:314
msgid "Create:"
msgstr ""
#. openerp-web
#: addons/web_diagram/static/src/js/diagram.js:231
#: addons/web_diagram/static/src/js/diagram.js:232
#: addons/web_diagram/static/src/js/diagram.js:296
msgid "Open: "
msgstr ""
#. openerp-web
#: addons/web_diagram/static/src/xml/base_diagram.xml:5
#: addons/web_diagram/static/src/xml/base_diagram.xml:6
msgid "New Node"
msgstr ""

View File

@ -0,0 +1,28 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
"PO-Revision-Date: 2012-06-16 18:10+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_gantt/static/src/js/gantt.js:11
msgid "Gantt"
msgstr ""
#. openerp-web
#: addons/web_gantt/static/src/xml/web_gantt.xml:10
msgid "Create"
msgstr ""

View File

@ -0,0 +1,23 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
"PO-Revision-Date: 2012-06-16 18:10+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_graph/static/src/js/graph.js:19
msgid "Graph"
msgstr ""

View File

@ -1,9 +1,12 @@
.dropdown-menu-icon {
z-index: 5000;
.openerp a.dropdown-menu-icon {
z-index: 10;
position: absolute;
right: 0px;
color: #4c4c4c;
right: 8px;
}
.openerp a.dropdown-menu-icon:hover {
text-decoration: none;
}
.editor-render {
position: relative;
}
@ -12,24 +15,62 @@
width: 650px;
height: 350px;
}
.graph-dropdown {
padding: 5px;
width: 200px;
border: 1px #333 solid;
.openerp .graph-dropdown {
display: none;
position: absolute;
right: 0px;
background: #fafaf5;
z-index: 100;
top: 40px;
right: 8px;
padding: 8px;
border: 1px solid #afafb6;
background: white;
z-index: 900;
min-width: 160px;
overflow-x: hidden;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.open .graph-dropdown {
.openerp .graph-dropdown h3 {
margin: 8px 4px 4px 0;
color: #8786b7;
font-size: 13px;
}
.openerp .graph-menu > li > a {
position: relative;
display: block;
padding: 2px 4px 2px 20px;
line-height: 14px;
color: #4c4c4c;
text-decoration: none;
}
.openerp .graph-menu > li > a:hover {
text-decoration: none;
background: #f0f0fa;
background: -moz-linear-gradient(#f0f0fa, #eeeef6);
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6));
background: -webkit-linear-gradient(#f0f0fa, #eeeef6);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
}
.openerp .open .graph-dropdown {
display: block;
}
.graph-menu {
padding: 3px;
}
.graph-menu .active {
background: #aaaaff;
.graph-menu .active:before {
content: "W";
font-family: "entypoRegular" !important;
font-size: 24px;
font-weight: 300 !important;
color: #a3a3a3;
position: absolute;
left: 4px;
top: -2px;
}
li {
padding: 2px;

View File

@ -4,45 +4,30 @@
</div>
<a href="#" class="oe_i dropdown-menu-icon" data-toggle="dropdown" title="Graph Options">B</a>
<div class="graph-dropdown">
<div class="menu-section">
Graph Mode:
</div>
<h3 class="menu-section">
Graph Mode
</h3>
<ul class="graph-menu oe_graph_options">
<li><a href="#" data-mode="pie">Pie</a></li>
<li>
<a href="#" data-mode="bar" data-legend="top"
data-stacked="true">Bars</a>
<div class="oe_i graph-menu-options">
<a href="#" data-mode="bar" data-legend="top"
data-stacked="true" title="Stacked Bars">w</a>
<a href="#" data-mode="bar" data-legend="top"
data-stacked="false" title="Multiple Bars">O</a>
</div>
<li><a href="#" data-mode="bar" data-legend="top" data-stacked="true">Bars</a>
</li>
<li><a href="#" data-mode="line">Lines</a></li>
<li><a href="#" data-mode="area" data-legend="top"
data-stacked="true">Areas</a>
<div class="oe_i graph-menu-options">
<a href="#" data-mode="area" data-legend="top"
data-stacked="true" title="Stacked Areas">w</a>
<a href="#" data-mode="area" data-legend="top"
data-stacked="false" title="Multiple Areas">O</a>
</div>
<li><a href="#" data-mode="area" data-legend="top" data-stacked="true">Areas</a>
</li>
<li><a href="#" data-mode="radar" data-legend="inside"
data-orientation="0">Radar</a></li>
</ul>
<div class="menu-section">
Legend:
</div>
<h3 class="menu-section">
Legend
</h3>
<ul class="graph-menu oe_graph_options">
<li><a href="#" data-legend="no">Hide</a></li>
<li><a href="#" data-legend="no">Hidden</a></li>
<li><a href="#" data-legend="inside">Inside</a></li>
<li><a href="#" data-legend="top">Top</a></li>
</ul>
<div class="menu-section">
Actions:
</div>
<h3 class="menu-section">
Actions
</h3>
<ul class="graph-menu">
<li><a href="#" id="graph_switch">Switch Axis</a></li>
<li><a href="#" id="graph_show_data">Show Data</a></li>

View File

@ -0,0 +1,55 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-14 15:27+0100\n"
"PO-Revision-Date: 2012-06-16 18:12+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_kanban/static/src/js/kanban.js:10
msgid "Kanban"
msgstr ""
#. openerp-web
#: addons/web_kanban/static/src/js/kanban.js:294
#: addons/web_kanban/static/src/js/kanban.js:295
msgid "Undefined"
msgstr ""
#. openerp-web
#: addons/web_kanban/static/src/js/kanban.js:469
#: addons/web_kanban/static/src/js/kanban.js:470
msgid "Are you sure you want to delete this record ?"
msgstr ""
#. openerp-web
#: addons/web_kanban/static/src/xml/web_kanban.xml:5
msgid "Create"
msgstr ""
#. openerp-web
#: addons/web_kanban/static/src/xml/web_kanban.xml:41
msgid "Show more... ("
msgstr ""
#. openerp-web
#: addons/web_kanban/static/src/xml/web_kanban.xml:41
msgid "remaining)"
msgstr ""
#. openerp-web
#: addons/web_kanban/static/src/xml/web_kanban.xml:59
msgid "</tr><tr>"
msgstr ""

View File

@ -1,9 +1,6 @@
@charset "utf-8";
.openerp .oe_kanban_view {
position: absolute;
top: 118px;
bottom: 0;
left: 221px;
right: 0;
height: inherit;
}
.openerp .oe_kanban_view .ui-sortable-placeholder {
border: 1px dotted black;
@ -19,8 +16,11 @@
.openerp .oe_kanban_view .oe_kanban_clear {
clear: both;
}
.openerp .oe_kanban_view .oe_kanban_content div:first-child {
margin-right: 12px;
}
.openerp .oe_kanban_view .oe_kanban_groups {
height: 100%;
height: inherit;
width: 100%;
}
.openerp .oe_kanban_view .oe_kanban_group_title {
@ -34,10 +34,21 @@
.openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_group_header {
vertical-align: top;
padding: 6px 7px 6px 6px;
}
.openerp .oe_kanban_view .oe_kanban_column.oe_kanban_grouped, .openerp .oe_kanban_view .oe_kanban_group_header {
background: #f0eeee;
}
.openerp .oe_kanban_view .oe_kanban_group_header.oe_kanban_no_group {
display: none;
}
.openerp .oe_kanban_view .oe_kanban_column.oe_kanban_grouped, .openerp .oe_kanban_view .oe_kanban_group_header {
border-left: 1px solid #f0f8f8;
border-right: 1px solid #b9b9b9;
}
.openerp .oe_kanban_view .oe_form .oe_kanban_column {
padding: 0px;
background: white;
}
.openerp .oe_kanban_view .oe_kanban_column {
height: 100%;
}
@ -106,8 +117,8 @@
box-sizing: border-box;
width: 100%;
}
.openerp .oe_kanban_view .oe_kanban_quick_create .oe_kanban_quick_create_buttons {
margin-bottom: 10px;
.openerp .oe_kanban_view .oe_kanban_quick_create button {
float: right;
}
.openerp .oe_kanban_view .oe_kanban_vignette {
padding: 8px;
@ -314,7 +325,7 @@
-webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
-box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
}
.openerp .oe_kanban_view .oe_kanban_card:hover .oe_kanban_menuaction {
.openerp .oe_kanban_view .oe_kanban_card:hover .oe_dropdown_kanban {
display: block;
}
.openerp .oe_kanban_view .oe_kanban_card h3 {
@ -375,56 +386,24 @@
text-overflow: ellipsis;
white-space: nowrap;
}
.openerp .oe_kanban_view a.oe_kanban_menuaction {
.openerp .oe_kanban_view .oe_dropdown_kanban {
position: absolute;
top: 0px;
top: -8px;
right: 3px;
display: none;
color: #4c4c4c;
cursor: pointer;
}
.openerp .oe_kanban_view a.oe_kanban_menuaction:hover {
.openerp .oe_kanban_view .oe_dropdown_kanban:hover {
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_menu {
display: none;
position: absolute;
top: 30px;
.openerp .oe_kanban_view .oe_dropdown_kanban .oe_dropdown_menu {
right: -140px;
padding: 4px;
border: 1px solid #afafb6;
min-width: 160px;
overflow-x: hidden;
z-index: 900;
background: white;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.openerp .oe_kanban_view .oe_kanban_menu p {
margin-left: 12px;
}
.openerp .oe_kanban_view .oe_kanban_menu > li > a {
display: block;
padding: 3px 6px;
line-height: 14px;
color: #4c4c4c;
text-decoration: none;
}
.openerp .oe_kanban_view .oe_kanban_menu > li > a:hover {
background: #f0f0fa;
background: -moz-linear-gradient(#f0f0fa, #eeeef6);
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6));
background: -webkit-linear-gradient(#f0f0fa, #eeeef6);
-moz-box-shadow: none;
-webkit-box-shadow: none;
-box-shadow: none;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker {
padding: 3px 6px;
white-space: nowrap;
}
.openerp .oe_kanban_view .oe_kanban_colorpicker li {
float: left;
@ -477,3 +456,8 @@
.openerp .oe_kanban_view .oe_kanban_color_9 {
background-color: #ffc7f1;
}
.openerp .oe_form .oe_kanban_view .oe_kanban_column, .openerp .oe_form .oe_kanban_view .oe_kanban_group_header {
padding: 0px;
background: white;
}

View File

@ -21,11 +21,7 @@
.openerp .oe_kanban_view
// KanbanView {{{
position: absolute
top: 118px
bottom: 0
left: 221px
right: 0
height: inherit
.ui-sortable-placeholder
border: 1px dotted black
visibility: visible !important
@ -36,10 +32,13 @@
float: right
.oe_kanban_clear
clear: both
.oe_kanban_content
div:first-child
margin-right: 12px
// }}}
// KanbanGroups {{{
.oe_kanban_groups
height: 100%
height: inherit
width: 100%
.oe_kanban_group_title
margin: 1px 1px 4px
@ -48,12 +47,26 @@
font-weight: bold
color: #333333
text-shadow: 0 1px 0 white
.oe_kanban_column, .oe_kanban_group_header
vertical-align: top
padding: 6px 7px 6px 6px
.oe_kanban_column.oe_kanban_grouped, .oe_kanban_group_header
background: #f0eeee
.oe_kanban_group_header.oe_kanban_no_group
display: none
.oe_kanban_column.oe_kanban_grouped, .oe_kanban_group_header
border-left: 1px solid #f0f8f8
border-right: 1px solid #b9b9b9
.oe_form
.oe_kanban_column
padding: 0px
background: #ffffff
.oe_kanban_column
height: 100%
.oe_kanban_aggregates
@ -267,7 +280,7 @@
margin-bottom: 0
&:hover
@include box-shadow(0 0 3px rgba(0,0,0,0.6))
.oe_kanban_menuaction
.oe_dropdown_kanban
display: block
h3
margin: 0 16px 0 0
@ -306,46 +319,23 @@
white-space: nowrap
// }}}
// KanbanDropDown {{{
a.oe_kanban_menuaction
.oe_dropdown_kanban
position: absolute
top: 0px
top: -8px
right: 3px
display: none
color: #4c4c4c
cursor: pointer
&:hover
text-decoration: none
.oe_kanban_menu
display: none
position: absolute
top: 30px
right: -140px
padding: 4px
border: 1px solid #afafb6
min-width: 160px
overflow-x: hidden
z-index: 900
background: white
@include radius(3px)
@include box-shadow(0 1px 4px rgba(0,0,0,0.3))
p
margin-left: 12px
> li > a
display: block
padding: 3px 6px
line-height: 14px
color: #4c4c4c
text-decoration: none
> li > a:hover
background: #f0f0fa
background: -moz-linear-gradient(#f0f0fa, #eeeef6)
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6))
background: -webkit-linear-gradient(#f0f0fa, #eeeef6)
@include box-shadow(none)
.oe_dropdown_menu
right: -140px
min-width: 160px
// }}}
// KanbanColorPicker {{{
.oe_kanban_colorpicker
padding: 3px 6px
white-space: nowrap
.oe_kanban_colorpicker li
float: left
a
@ -394,5 +384,10 @@
.oe_kanban_color_9
background-color: #FFC7F1
.openerp .oe_form .oe_kanban_view
.oe_kanban_column, .oe_kanban_group_header
padding: 0px
background: #ffffff
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:

View File

@ -42,18 +42,6 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.limit = options.limit || 80;
this.add_group_mutex = new $.Mutex();
},
start: function() {
var self = this;
var def = this._super.apply(this, arguments);
// Bind kanban cards dropdown menus
$('html').on('click.kanban', function() {
self.trigger('hide_menus');
});
this.on('hide_menus', this, function() {
self.$element.find('.oe_kanban_menu').hide();
});
return def;
},
destroy: function() {
this._super.apply(this, arguments);
$('html').off('click.kanban');
@ -608,7 +596,6 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
}
this.$element.find('.oe_kanban_action').click(function() {
self.view.trigger('hide_menus');
var $action = $(this),
type = $action.data('type') || 'button',
method = 'do_action_' + (type === 'action' ? 'object' : type);
@ -619,32 +606,17 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
} else {
self.do_warn("Kanban: no action for type : " + type);
}
return false;
});
this.$element.on('click', '.oe_kanban_menuaction', function() {
var $menu = $(this).next('.oe_kanban_menu');
var show = !$menu.is(':visible');
self.view.trigger('hide_menus');
var doc_width = $(document).width();
$menu.toggle(show);
if (show) {
var offset = $menu.offset();
var menu_width = $menu.width();
var x = doc_width - offset.left - menu_width - 15;
if (x < 0) {
$menu.offset({ left: offset.left + x }).width(menu_width);
}
}
return false;
});
if (this.$element.find('.oe_kanban_global_click').length) {
this.$element.on('click', this.on_card_clicked);
this.$element.on('click', function(ev) {
if (!ev.isTrigger && !$(ev.target).data('events')) {
//self.on_card_clicked(ev);
}
});
}
},
on_card_clicked: function() {
this.view.trigger('hide_menus');
on_card_clicked: function(ev) {
this.view.open_record(this.id);
},
setup_color_picker: function() {
@ -654,8 +626,8 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
$el.html(QWeb.render('KanbanColorPicker', {
widget: this
}));
$el.on('click', 'a', function() {
self.view.trigger('hide_menus');
$el.on('click', 'a', function(ev) {
ev.preventDefault();
var color_field = $(this).parents('.oe_kanban_colorpicker').first().data('field') || 'color';
var data = {};
data[color_field] = $(this).data('color');
@ -663,7 +635,6 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
self.record[color_field] = $(this).data('color');
self.do_reload();
});
return false;
});
}
},
@ -740,12 +711,12 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
var email_md5 = $.md5(email);
return 'http://www.gravatar.com/avatar/' + email_md5 + '.png?s=' + size + '&d=' + default_;
},
kanban_image: function(model, field, id) {
kanban_image: function(model, field, id, cache) {
id = id || '';
var url = instance.connection.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id;
if (this.record.__last_update && this.record.__last_update.raw_value) {
var time = instance.web.str_to_datetime(this.record.__last_update.raw_value).getTime();
url += '&t=' + time;
if (cache !== undefined) {
// Set the cache duration in seconds.
url += '&cache=' + parseInt(cache, 10);
}
return url;
},

View File

@ -0,0 +1,106 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-07 10:13+0100\n"
"PO-Revision-Date: 2012-06-16 18:14+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:17
msgid "OpenERP"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:22
msgid "Database:"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:30
msgid "Login:"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:32
msgid "Password:"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:34
msgid "Login"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:36
msgid "Bad username or password"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:42
msgid "Powered by openerp.com"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:49
msgid "Home"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:57
msgid "Favourite"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:58
msgid "Preference"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:123
msgid "Logout"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:132
msgid "There are no records to show."
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:183
msgid "Open this resource"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:223
#: addons/web_mobile/static/src/xml/web_mobile.xml:226
msgid "Percent of tasks closed according to total of tasks to do..."
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:264
#: addons/web_mobile/static/src/xml/web_mobile.xml:268
msgid "On"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:265
#: addons/web_mobile/static/src/xml/web_mobile.xml:269
msgid "Off"
msgstr ""
#. openerp-web
#: addons/web_mobile/static/src/xml/web_mobile.xml:294
msgid "Form View"
msgstr ""

View File

@ -0,0 +1,118 @@
# Catalan translation for openerp-web
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-07 19:19+0100\n"
"PO-Revision-Date: 2012-06-16 18:19+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Catalan <ca@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-06-17 04:44+0000\n"
"X-Generator: Launchpad (build 15419)\n"
#. openerp-web
#: addons/web_process/static/src/js/process.js:261
msgid "Cancel"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/js/process.js:262
msgid "Save"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:6
msgid "Process View"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:19
msgid "Documentation"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:19
msgid "Read Documentation Online"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:25
msgid "Forum"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:25
msgid "Community Discussion"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:31
msgid "Books"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:31
msgid "Get the books"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:37
msgid "OpenERP Enterprise"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:37
msgid "Purchase OpenERP Enterprise"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:52
msgid "Process"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:56
msgid "Notes:"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:59
msgid "Last modified by:"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:59
msgid "N/A"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:62
msgid "Subflows:"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:75
msgid "Related:"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:88
msgid "Select Process"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:98
msgid "Select"
msgstr ""
#. openerp-web
#: addons/web_process/static/src/xml/web_process.xml:109
msgid "Edit Process"
msgstr ""