diff options
| author | Vo Minh Thu <vmt@openerp.com> | 2012-01-18 11:12:52 +0100 |
|---|---|---|
| committer | Vo Minh Thu <vmt@openerp.com> | 2012-01-18 11:12:52 +0100 |
| commit | 75b3fc0907ee873c6e16d1fa8e8bfe58d4f520c1 (patch) | |
| tree | 3e7f7bbe9110eeae766b46bb9c16a867579b6452 /addons/web | |
| parent | 3203d264aecd751a8c261cea4f72fa323a3098be (diff) | |
| parent | 152f92916bc36d00c0e59fbc49fb655a4fd85908 (diff) | |
[MERGE] merged trunk.
bzr revid: vmt@openerp.com-20120118101252-e81nlyzym2nkebf4
Diffstat (limited to 'addons/web')
23 files changed, 520 insertions, 580 deletions
diff --git a/addons/web/__init__.py b/addons/web/__init__.py index b09c8c213bc..36dead8ab74 100644 --- a/addons/web/__init__.py +++ b/addons/web/__init__.py @@ -1,7 +1,6 @@ import common import controllers import logging -import optparse _logger = logging.getLogger(__name__) diff --git a/addons/web/common/http.py b/addons/web/common/http.py index 17ccfb63d8a..434edf5e3a7 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -328,6 +328,7 @@ def session_context(request, storage_path, session_cookie='sessionid'): # Remove all OpenERPSession instances with no uid, they're generated # either by login process or by HTTP requests without an OpenERP # session id, and are generally noise + removed_sessions = [] for key, value in request.session.items(): if (isinstance(value, session.OpenERPSession) and not value._uid @@ -335,6 +336,7 @@ def session_context(request, storage_path, session_cookie='sessionid'): and value._creation_time + (60*5) < time.time() # FIXME do not use a fixed value ): _logger.debug('remove session %s', key) + removed_sessions.append(key) del request.session[key] with session_lock: @@ -364,7 +366,7 @@ def session_context(request, storage_path, session_cookie='sessionid'): # add missing keys for k, v in in_store.iteritems(): - if k not in request.session: + if k not in request.session and k not in removed_sessions: request.session[k] = v session_store.save(request.session) diff --git a/addons/web/common/nonliterals.py b/addons/web/common/nonliterals.py index f6e81894a4c..0f5248edf33 100644 --- a/addons/web/common/nonliterals.py +++ b/addons/web/common/nonliterals.py @@ -8,7 +8,7 @@ import binascii import hashlib import simplejson.encoder -__all__ = ['Domain', 'Context', 'NonLiteralEncoder, non_literal_decoder', 'CompoundDomain', 'CompoundContext'] +__all__ = ['Domain', 'Context', 'NonLiteralEncoder', 'non_literal_decoder', 'CompoundDomain', 'CompoundContext'] #: 48 bits should be sufficient to have almost no chance of collision #: with a million hashes, according to hg@67081329d49a diff --git a/addons/web/common/xml2json.py b/addons/web/common/xml2json.py index 1f2e74691b9..df3aad67fa5 100644 --- a/addons/web/common/xml2json.py +++ b/addons/web/common/xml2json.py @@ -4,35 +4,23 @@ # # URL: http://code.google.com/p/xml2json-direct/ -class Xml2Json(object): - @staticmethod - def convert_to_json(s): - return simplejson.dumps( - Xml2Json.convert_to_structure(s), sort_keys=True, indent=4) - - @staticmethod - def convert_to_structure(s): - root = ElementTree.fromstring(s) - return Xml2Json.convert_element(root) - - @staticmethod - def convert_element(el, preserve_whitespaces=False): - res = {} - if el.tag[0] == "{": - ns, name = el.tag.rsplit("}", 1) - res["tag"] = name - res["namespace"] = ns[1:] - else: - res["tag"] = el.tag - res["attrs"] = {} - for k, v in el.items(): - res["attrs"][k] = v - kids = [] - if el.text and (preserve_whitespaces or el.text.strip() != ''): - kids.append(el.text) - for kid in el: - kids.append(Xml2Json.convert_element(kid, preserve_whitespaces)) - if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''): - kids.append(kid.tail) - res["children"] = kids - return res +def from_elementtree(el, preserve_whitespaces=False): + res = {} + if el.tag[0] == "{": + ns, name = el.tag.rsplit("}", 1) + res["tag"] = name + res["namespace"] = ns[1:] + else: + res["tag"] = el.tag + res["attrs"] = {} + for k, v in el.items(): + res["attrs"][k] = v + kids = [] + if el.text and (preserve_whitespaces or el.text.strip() != ''): + kids.append(el.text) + for kid in el: + kids.append(from_elementtree(kid, preserve_whitespaces)) + if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''): + kids.append(kid.tail) + res["children"] = kids + return res diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 3a23556794a..a514cafb6c8 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -99,7 +99,7 @@ html_template = """<!DOCTYPE html> }); </script> </head> - <body></body> + <body class="openerp" id="oe"></body> </html> """ @@ -207,7 +207,7 @@ class WebClient(openerpweb.Controller): 'js': js, 'css': css, 'modules': simplejson.dumps(self.server_wide_modules(req)), - 'init': 'new s.web.WebClient().replace($("body"));', + 'init': 'new s.web.WebClient().start();', } return r @@ -933,7 +933,7 @@ class View(openerpweb.Controller): xml = self.transform_view(arch, session, evaluation_context) else: xml = ElementTree.fromstring(arch) - fvg['arch'] = common.xml2json.Xml2Json.convert_element(xml, preserve_whitespaces) + fvg['arch'] = common.xml2json.from_elementtree(xml, preserve_whitespaces) for field in fvg['fields'].itervalues(): if field.get('views'): diff --git a/addons/web/po/pt_BR.po b/addons/web/po/pt_BR.po index 4be0c66826c..eb3e427a769 100644 --- a/addons/web/po/pt_BR.po +++ b/addons/web/po/pt_BR.po @@ -8,15 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "POT-Creation-Date: 2011-12-20 18:48+0100\n" -"PO-Revision-Date: 2012-01-15 02:47+0000\n" -"Last-Translator: Renato Lima - http://www.akretion.com " -"<renatonlima@gmail.com>\n" +"PO-Revision-Date: 2012-01-16 13:38+0000\n" +"Last-Translator: Rafael Sales <Unknown>\n" "Language-Team: Brazilian Portuguese <pt_BR@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-01-16 05:27+0000\n" -"X-Generator: Launchpad (build 14664)\n" +"X-Launchpad-Export-Date: 2012-01-17 05:08+0000\n" +"X-Generator: Launchpad (build 14676)\n" #: addons/web/static/src/js/chrome.js:162 #: addons/web/static/src/js/chrome.js:175 @@ -626,7 +625,7 @@ msgstr "Visão de Depuração#" #: addons/web/static/src/xml/base.xml:0 msgid "- Fields View Get" -msgstr "" +msgstr "- Fields View Get" #: addons/web/static/src/xml/base.xml:0 msgid "- Edit" @@ -786,7 +785,7 @@ msgstr "Botão" #: addons/web/static/src/xml/base.xml:0 msgid "(no string)" -msgstr "" +msgstr "(sem string)" #: addons/web/static/src/xml/base.xml:0 msgid "Special:" @@ -875,6 +874,10 @@ msgid "" " You can export all data or only the fields that can be " "reimported after modification." msgstr "" +"Este assistente irá exportar todos os dados que corresponda aos critérios de " +"pesquisa atual em um arquivo CSV.\n" +" Você pode exportar todos os dados ou apenas os campos que podem " +"ser reimportados após a modificação." #: addons/web/static/src/xml/base.xml:0 msgid "Export Type:" @@ -945,6 +948,10 @@ msgid "" "Select a .CSV file to import. If you need a sample of file to import,\n" " you should use the export tool with the \"Import Compatible\" option." msgstr "" +"Selecionar um arquivo .CSV para importar. Se você precisar de uma amostra do " +"arquivo para importação,\n" +" você deve usar a ferramenta de exportação com a opção \"Importação " +"Compatível\"." #: addons/web/static/src/xml/base.xml:0 msgid "CSV File:" @@ -1039,6 +1046,13 @@ msgid "" "supply chain,\n" " project management, production, services, CRM, etc..." msgstr "" +"é um sistema de software livre de escala empresarial que é projetado para " +"aumentar\n" +" produtividade e lucro através da integração de dados. Ele se " +"conecta, melhora e\n" +" gerencia os processos de negócio em áreas como vendas, " +"finanças, supply chain,\n" +" gerenciamento de projetos, produção, serviços, CRM, etc .." #: addons/web/static/src/xml/base.xml:0 msgid "" @@ -1051,6 +1065,14 @@ msgid "" " production system and migration to a new version to be " "straightforward." msgstr "" +"É um sistema independente de plataforma, onde pode ser instalado em " +"ambientes Windows, Mac OS X,\n" +" e várias distribuições Linux ou baseadas em Unix. Sua " +"arquitetura permite que\n" +" novas funcionalidades sejam criadas rapidamente, e modificações " +"possam ser realizadas em um\n" +" sistema de produção e sua migração para uma nova versão de " +"forma simples." #: addons/web/static/src/xml/base.xml:0 msgid "" diff --git a/addons/web/static/lib/jquery.tipTip/jquery.tipTip.fme.patch b/addons/web/static/lib/jquery.tipTip/jquery.tipTip.fme.patch deleted file mode 100644 index 1a62870a6b0..00000000000 --- a/addons/web/static/lib/jquery.tipTip/jquery.tipTip.fme.patch +++ /dev/null @@ -1,58 +0,0 @@ ---- jquery.tipTip_old.js 2011-12-01 14:15:35.000000000 +0100 -+++ jquery.tipTip.js 2011-12-07 12:32:32.000000000 +0100 -@@ -20,6 +20,9 @@ - */ - - (function($){ -+ $.tipTipClear = function() { -+ $("#tiptip_holder").remove(); -+ } - $.fn.tipTip = function(options) { - var defaults = { - activation: "hover", -@@ -31,7 +34,7 @@ - fadeIn: 200, - fadeOut: 200, - attribute: "title", -- content: false, // HTML or String to fill TipTIp with -+ content: false, // HTML String or function to fill TipTIp with - enter: function(){}, - exit: function(){} - }; -@@ -51,12 +54,7 @@ - - return this.each(function(){ - var org_elem = $(this); -- if(opts.content){ -- var org_title = opts.content; -- } else { -- var org_title = org_elem.attr(opts.attribute); -- } -- if(org_title != ""){ -+ if(opts.content || org_elem.attr(opts.attribute)){ - if(!opts.content){ - org_elem.removeAttr(opts.attribute); //remove original Attribute - } -@@ -99,6 +97,8 @@ - - function active_tiptip(){ - opts.enter.call(this); -+ var org_title = typeof opts.content === 'function' ? opts.content.call(org_elem, opts) : opts.content; -+ org_title = org_title || org_elem.attr(opts.attribute); - tiptip_content.html(org_title); - tiptip_holder.hide().removeAttr("class").css("margin","0"); - tiptip_arrow.removeAttr("style"); -@@ -177,7 +177,12 @@ - tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class); - - if (timeout){ clearTimeout(timeout); } -- timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay); -+ timeout = setTimeout(function() { -+ tiptip_holder.stop(true,true); -+ if ($.contains(document.documentElement, org_elem[0])) { -+ tiptip_holder.fadeIn(opts.fadeIn); -+ } -+ }, opts.delay); - } - - function deactive_tiptip(){ diff --git a/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js b/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js index 522df828003..ff8cc1b0ba6 100644 --- a/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js +++ b/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js @@ -1,196 +1,325 @@ - /* - * TipTip - * Copyright 2010 Drew Wilson - * www.drewwilson.com - * code.drewwilson.com/entry/tiptip-jquery-plugin - * - * Version 1.3 - Updated: Mar. 23, 2010 - * - * This Plug-In will create a custom tooltip to replace the default - * browser tooltip. It is extremely lightweight and very smart in - * that it detects the edges of the browser window and will make sure - * the tooltip stays within the current window size. As a result the - * tooltip will adjust itself to be displayed above, below, to the left - * or to the right depending on what is necessary to stay within the - * browser window. It is completely customizable as well via CSS. - * - * This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - */ - -(function($){ - $.tipTipClear = function() { - $("#tiptip_holder").remove(); +/* +* TipTip +* Copyright 2010 Drew Wilson +* www.drewwilson.com +* code.drewwilson.com/entry/tiptip-jquery-plugin +* +* Version 1.3 - Updated: Mar. 23, 2010 +* +* This Plug-In will create a custom tooltip to replace the default +* browser tooltip. It is extremely lightweight and very smart in +* that it detects the edges of the browser window and will make sure +* the tooltip stays within the current window size. As a result the +* tooltip will adjust itself to be displayed above, below, to the left +* or to the right depending on what is necessary to stay within the +* browser window. It is completely customizable as well via CSS. +* +* This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses: +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl.html +*/ + +(function ($) { + $.fn.tipTip = function (options) { + + var defaults = { + activation: 'hover', // How to show (and hide) the tooltip. Can be: hover, focus, click and manual. + keepAlive: false, // When true the tooltip won't disapper when the mouse moves away from the element. Instead it will be hidden when it leaves the tooltip. + maxWidth: '200px', // The max-width to set on the tooltip. You may also use the option cssClass to set this. + edgeOffset: 0, // The offset between the tooltip arrow edge and the element that has the tooltip. + defaultPosition: 'bottom', // The position of the tooltip. Can be: top, right, bottom and left. + delay: 400, // The delay in msec to show a tooltip. + fadeIn: 200, // The length in msec of the fade in. + fadeOut: 200, // The length in msec of the fade out. + attribute: 'title', // The attribute to fetch the tooltip text if the option content is false. + content: false, // HTML or String or Function (that returns HTML or String) to fill TipTIp with + enter: function () { }, // Callback function before a tooltip is shown. + afterEnter: function () { }, // Callback function after a tooltip is shown. + exit: function () { }, // Callback function before a tooltip is hidden. + afterExit: function () { }, // Callback function after a tooltip is hidden. + cssClass: '', // CSS class that will be applied on the tooltip before showing only for this instance of tooltip. + detectTextDir: true // When false auto-detection for right-to-left text will be disable (When true affects a bit the performance). + }; + + // Setup tip tip elements and render them to the DOM + if ($('#tiptip_holder').length <= 0) { + var tiptip_inner_arrow = $('<div>', { id: 'tiptip_arrow_inner' }), + tiptip_arrow = $('<div>', { id: 'tiptip_arrow' }).append(tiptip_inner_arrow), + tiptip_content = $('<div>', { id: 'tiptip_content' }), + tiptip_holder = $('<div>', { id: 'tiptip_holder' }).append(tiptip_arrow).append(tiptip_content); + $('body').append(tiptip_holder); + } else { + var tiptip_holder = $('#tiptip_holder'), + tiptip_content = $('#tiptip_content'), + tiptip_arrow = $('#tiptip_arrow'); + } + + return this.each(function () { + var org_elem = $(this), + data = org_elem.data('tipTip'), + opts = data && data.options || $.extend({}, defaults, options), + callback_data = { + holder: tiptip_holder, + content: tiptip_content, + arrow: tiptip_arrow, + options: opts + }; + + if (data) { + switch (options) { + case 'show': + activate(); + break; + case 'hide': + deactivate(); + break; + case 'destroy': + org_elem.unbind('.tipTip').removeData('tipTip'); + break; + case 'position': + position_tiptip(); + } + } else { + var timeout = false; + + org_elem.data('tipTip', { options: opts }); + + if (opts.activation == 'hover') { + org_elem.bind('mouseenter.tipTip', function () { + activate(); + }).bind('mouseleave.tipTip', function () { + if (!opts.keepAlive) { + deactivate(); + } else { + tiptip_holder.one('mouseleave.tipTip', function () { + deactivate(); + }); + } + }); + } else if (opts.activation == 'focus') { + org_elem.bind('focus.tipTip', function () { + activate(); + }).bind('blur.tipTip', function () { + deactivate(); + }); + } else if (opts.activation == 'click') { + org_elem.bind('click.tipTip', function (e) { + e.preventDefault(); + activate(); + return false; + }).bind('mouseleave.tipTip', function () { + if (!opts.keepAlive) { + deactivate(); + } else { + tiptip_holder.one('mouseleave.tipTip', function () { + deactivate(); + }); + } + }); + } else if (opts.activation == 'manual') { + // Nothing to register actually. We decide when to show or hide. + } + } + + function activate() { + if (opts.enter.call(org_elem, callback_data) === false) { + return; + } + + // Get the text and append it in the tiptip_content. + var org_title; + if (opts.content) { + org_title = $.isFunction(opts.content) ? opts.content.call(org_elem, callback_data) : opts.content; + } else { + org_title = opts.content = org_elem.attr(opts.attribute); + org_elem.removeAttr(opts.attribute); //remove original Attribute + } + if (!org_title) { + return; // don't show tip when no content. + } + + tiptip_content.html(org_title); + tiptip_holder.hide().removeAttr('class').css({ 'max-width': opts.maxWidth }); + if (opts.cssClass) { + tiptip_holder.addClass(opts.cssClass); + } + + // Calculate the position of the tooltip. + position_tiptip(); + + // Show the tooltip. + if (timeout) { + clearTimeout(timeout); + } + + timeout = setTimeout(function () { + tiptip_holder.stop(true, true).fadeIn(opts.fadeIn); + }, opts.delay); + + $(window).bind('resize.tipTip scroll.tipTip', position_tiptip); + + // Ensure clicking on anything makes tipTip deactivate + $(document).unbind("click.tipTip dblclick.tipTip").bind("click.tiptip dblclick.tiptip", deactivate); + + + org_elem.addClass('tiptip_visible'); // Add marker class to easily find the target element with visible tooltip. It will be remove later on deactivate(). + + opts.afterEnter.call(org_elem, callback_data); + } + + function deactivate() { + if (opts.exit.call(org_elem, callback_data) === false) { + return; + } + + if (timeout) { + clearTimeout(timeout); + } + + tiptip_holder.fadeOut(opts.fadeOut); + + $(window).unbind('resize.tipTip scroll.tipTip'); + $(document).unbind("click.tipTip").unbind("dblclick.tipTip"); + + org_elem.removeClass('tiptip_visible'); + + opts.afterExit.call(org_elem, callback_data); + } + + function position_tiptip() { + var org_offset = org_elem.offset(), + org_top = org_offset.top, + org_left = org_offset.left, + org_width = org_elem.outerWidth(), + org_height = org_elem.outerHeight(), + tip_top, + tip_left, + tip_width = tiptip_holder.outerWidth(), + tip_height = tiptip_holder.outerHeight(), + tip_class, + tip_classes = { top: 'tip_top', bottom: 'tip_bottom', left: 'tip_left', right: 'tip_right' }, + arrow_top, + arrow_left, + arrow_width = 12, // tiptip_arrow.outerHeight() and tiptip_arrow.outerWidth() don't work because they need the element to be visible. + arrow_height = 12, + win = $(window), + win_top = win.scrollTop(), + win_left = win.scrollLeft(), + win_width = win.width(), + win_height = win.height(), + is_rtl = opts.detectTextDir && isRtlText(tiptip_content.text()); + + function moveTop() { + tip_class = tip_classes.top; + tip_top = org_top - tip_height - opts.edgeOffset - (arrow_height / 2); + tip_left = org_left + ((org_width - tip_width) / 2); + } + + function moveBottom() { + tip_class = tip_classes.bottom; + tip_top = org_top + org_height + opts.edgeOffset + (arrow_height / 2); + tip_left = org_left + ((org_width - tip_width) / 2); + } + + function moveLeft() { + tip_class = tip_classes.left; + tip_top = org_top + ((org_height - tip_height) / 2); + tip_left = org_left - tip_width - opts.edgeOffset - (arrow_width / 2); + } + + function moveRight() { + tip_class = tip_classes.right; + tip_top = org_top + ((org_height - tip_height) / 2); + tip_left = org_left + org_width + opts.edgeOffset + (arrow_width / 2); + } + + // Calculate the position of the tooltip. + if (opts.defaultPosition == 'bottom') { + moveBottom(); + } else if (opts.defaultPosition == 'top') { + moveTop(); + } else if (opts.defaultPosition == 'left' && !is_rtl) { + moveLeft(); + } else if (opts.defaultPosition == 'left' && is_rtl) { + moveRight(); + } else if (opts.defaultPosition == 'right' && !is_rtl) { + moveRight(); + } else if (opts.defaultPosition == 'right' && is_rtl) { + moveLeft(); + } else { + moveBottom(); + } + + // Flip the tooltip if off the window's viewport. (left <-> right and top <-> bottom). + if (tip_class == tip_classes.left && !is_rtl && tip_left < win_left) { + moveRight(); + } else if (tip_class == tip_classes.left && is_rtl && tip_left - tip_width < win_left) { + moveRight(); + } else if (tip_class == tip_classes.right && !is_rtl && tip_left > win_left + win_width) { + moveLeft(); + } else if (tip_class == tip_classes.right && is_rtl && tip_left + tip_width > win_left + win_width) { + moveLeft(); + } else if (tip_class == tip_classes.top && tip_top < win_top) { + moveBottom(); + } else if (tip_class == tip_classes.bottom && tip_top > win_top + win_height) { + moveTop(); + } + + // Fix the vertical position if the tooltip is off the top or bottom sides of the window's viewport. + if (tip_class == tip_classes.left || tip_class == tip_classes.right) { // If positioned left or right check if the tooltip is off the top or bottom window's viewport. + if (tip_top + tip_height > win_height + win_top) { // If the bottom edge of the tooltip is off the bottom side of the window's viewport. + tip_top = org_top + org_height > win_height + win_top ? org_top + org_height - tip_height : win_height + win_top - tip_height; // Make 'bottom edge of the tooltip' == 'bottom side of the window's viewport'. + } else if (tip_top < win_top) { // If the top edge of the tooltip if off the top side of the window's viewport. + tip_top = org_top < win_top ? org_top : win_top; // Make 'top edge of the tooltip' == 'top side of the window's viewport'. + } + } + + // Fix the horizontal position if the tooltip is off the right or left sides of the window's viewport. + if (tip_class == tip_classes.top || tip_class == tip_classes.bottom) { + if (tip_left + tip_width > win_width + win_left) { // If the right edge of the tooltip is off the right side of the window's viewport. + tip_left = org_left + org_width > win_width + win_left ? org_left + org_width - tip_width : win_width + win_left - tip_width; // Make 'right edge of the tooltip' == 'right side of the window's viewport'. + } else if (tip_left < win_left) { // If the left edge of the tooltip if off the left side of the window's viewport. + tip_left = org_left < win_left ? org_left : win_left; // Make 'left edge of the tooltip' == 'left side of the window's viewport'. + } + } + + // Apply the new position. + tiptip_holder + .css({ left: Math.round(tip_left), top: Math.round(tip_top) }) + .removeClass(tip_classes.top) + .removeClass(tip_classes.bottom) + .removeClass(tip_classes.left) + .removeClass(tip_classes.right) + .addClass(tip_class); + + // Position the arrow + if (tip_class == tip_classes.top) { + arrow_top = tip_height; // Position the arrow vertically on the top of the tooltip. + arrow_left = org_left - tip_left + ((org_width - arrow_width) / 2); // Center the arrow horizontally on the center of the target element. + } else if (tip_class == tip_classes.bottom) { + arrow_top = -arrow_height; // Position the arrow vertically on the bottom of the tooltip. + arrow_left = org_left - tip_left + ((org_width - arrow_width) / 2); // Center the arrow horizontally on the center of the target element. + } else if (tip_class == tip_classes.left) { + arrow_top = org_top - tip_top + ((org_height - arrow_height) / 2); // Center the arrow vertically on the center of the target element. + arrow_left = tip_width; // Position the arrow vertically on the left of the tooltip. + } else if (tip_class == tip_classes.right) { + arrow_top = org_top - tip_top + ((org_height - arrow_height) / 2); // Center the arrow vertically on the center of the target element. + arrow_left = -arrow_width; // Position the arrow vertically on the right of the tooltip. + } + + tiptip_arrow + .css({ left: Math.round(arrow_left), top: Math.round(arrow_top) }); + } + }); } - $.fn.tipTip = function(options) { - var defaults = { - activation: "hover", - keepAlive: false, - maxWidth: "200px", - edgeOffset: 3, - defaultPosition: "bottom", - delay: 400, - fadeIn: 200, - fadeOut: 200, - attribute: "title", - content: false, // HTML String or function to fill TipTIp with - enter: function(){}, - exit: function(){} - }; - var opts = $.extend(defaults, options); - - // Setup tip tip elements and render them to the DOM - if($("#tiptip_holder").length <= 0){ - var tiptip_holder = $('<div id="tiptip_holder" style="max-width:'+ opts.maxWidth +';"></div>'); - var tiptip_content = $('<div id="tiptip_content"></div>'); - var tiptip_arrow = $('<div id="tiptip_arrow"></div>'); - $("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>'))); - } else { - var tiptip_holder = $("#tiptip_holder"); - var tiptip_content = $("#tiptip_content"); - var tiptip_arrow = $("#tiptip_arrow"); - } - - return this.each(function(){ - var org_elem = $(this); - if(opts.content || org_elem.attr(opts.attribute)){ - if(!opts.content){ - org_elem.removeAttr(opts.attribute); //remove original Attribute - } - var timeout = false; - - if(opts.activation == "hover"){ - org_elem.hover(function(){ - active_tiptip(); - }, function(){ - if(!opts.keepAlive){ - deactive_tiptip(); - } - }); - if(opts.keepAlive){ - tiptip_holder.hover(function(){}, function(){ - deactive_tiptip(); - }); - } - } else if(opts.activation == "focus"){ - org_elem.focus(function(){ - active_tiptip(); - }).blur(function(){ - deactive_tiptip(); - }); - } else if(opts.activation == "click"){ - org_elem.click(function(){ - active_tiptip(); - return false; - }).hover(function(){},function(){ - if(!opts.keepAlive){ - deactive_tiptip(); - } - }); - if(opts.keepAlive){ - tiptip_holder.hover(function(){}, function(){ - deactive_tiptip(); - }); - } - } - - function active_tiptip(){ - opts.enter.call(this); - var org_title = typeof opts.content === 'function' ? opts.content.call(org_elem, opts) : opts.content; - org_title = org_title || org_elem.attr(opts.attribute); - tiptip_content.html(org_title); - tiptip_holder.hide().removeAttr("class").css("margin","0"); - tiptip_arrow.removeAttr("style"); - - var top = parseInt(org_elem.offset()['top']); - var left = parseInt(org_elem.offset()['left']); - var org_width = parseInt(org_elem.outerWidth()); - var org_height = parseInt(org_elem.outerHeight()); - var tip_w = tiptip_holder.outerWidth(); - var tip_h = tiptip_holder.outerHeight(); - var w_compare = Math.round((org_width - tip_w) / 2); - var h_compare = Math.round((org_height - tip_h) / 2); - var marg_left = Math.round(left + w_compare); - var marg_top = Math.round(top + org_height + opts.edgeOffset); - var t_class = ""; - var arrow_top = ""; - var arrow_left = Math.round(tip_w - 12) / 2; - - if(opts.defaultPosition == "bottom"){ - t_class = "_bottom"; - } else if(opts.defaultPosition == "top"){ - t_class = "_top"; - } else if(opts.defaultPosition == "left"){ - t_class = "_left"; - } else if(opts.defaultPosition == "right"){ - t_class = "_right"; - } - - var right_compare = (w_compare + left) < parseInt($(window).scrollLeft()); - var left_compare = (tip_w + left) > parseInt($(window).width()); - - if((right_compare && w_compare < 0) || (t_class == "_right" && !left_compare) || (t_class == "_left" && left < (tip_w + opts.edgeOffset + 5))){ - t_class = "_right"; - arrow_top = Math.round(tip_h - 13) / 2; - arrow_left = -12; - marg_left = Math.round(left + org_width + opts.edgeOffset); - marg_top = Math.round(top + h_compare); - } else if((left_compare && w_compare < 0) || (t_class == "_left" && !right_compare)){ - t_class = "_left"; - arrow_top = Math.round(tip_h - 13) / 2; - arrow_left = Math.round(tip_w); - marg_left = Math.round(left - (tip_w + opts.edgeOffset + 5)); - marg_top = Math.round(top + h_compare); - } - - var top_compare = (top + org_height + opts.edgeOffset + tip_h + 8) > parseInt($(window).height() + $(window).scrollTop()); - var bottom_compare = ((top + org_height) - (opts.edgeOffset + tip_h + 8)) < 0; - - if(top_compare || (t_class == "_bottom" && top_compare) || (t_class == "_top" && !bottom_compare)){ - if(t_class == "_top" || t_class == "_bottom"){ - t_class = "_top"; - } else { - t_class = t_class+"_top"; - } - arrow_top = tip_h; - marg_top = Math.round(top - (tip_h + 5 + opts.edgeOffset)); - } else if(bottom_compare | (t_class == "_top" && bottom_compare) || (t_class == "_bottom" && !top_compare)){ - if(t_class == "_top" || t_class == "_bottom"){ - t_class = "_bottom"; - } else { - t_class = t_class+"_bottom"; - } - arrow_top = -12; - marg_top = Math.round(top + org_height + opts.edgeOffset); - } - - if(t_class == "_right_top" || t_class == "_left_top"){ - marg_top = marg_top + 5; - } else if(t_class == "_right_bottom" || t_class == "_left_bottom"){ - marg_top = marg_top - 5; - } - if(t_class == "_left_top" || t_class == "_left_bottom"){ - marg_left = marg_left + 5; - } - tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"}); - tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class); - - if (timeout){ clearTimeout(timeout); } - timeout = setTimeout(function() { - tiptip_holder.stop(true,true); - if ($.contains(document.documentElement, org_elem[0])) { - tiptip_holder.fadeIn(opts.fadeIn); - } - }, opts.delay); - } - - function deactive_tiptip(){ - opts.exit.call(this); - if (timeout){ clearTimeout(timeout); } - tiptip_holder.fadeOut(opts.fadeOut); - } - } - }); - } -})(jQuery); + + var ltrChars = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF', + rtlChars = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC', + rtlDirCheckRe = new RegExp('^[^' + ltrChars + ']*[' + rtlChars + ']'); + + function isRtlText(text) { + return rtlDirCheckRe.test(text); + }; + +})(jQuery); + diff --git a/addons/web/static/lib/jquery.tipTip/jquery.tipTip_old.js b/addons/web/static/lib/jquery.tipTip/jquery.tipTip_old.js deleted file mode 100644 index d2b460d1261..00000000000 --- a/addons/web/static/lib/jquery.tipTip/jquery.tipTip_old.js +++ /dev/null @@ -1,191 +0,0 @@ - /* - * TipTip - * Copyright 2010 Drew Wilson - * www.drewwilson.com - * code.drewwilson.com/entry/tiptip-jquery-plugin - * - * Version 1.3 - Updated: Mar. 23, 2010 - * - * This Plug-In will create a custom tooltip to replace the default - * browser tooltip. It is extremely lightweight and very smart in - * that it detects the edges of the browser window and will make sure - * the tooltip stays within the current window size. As a result the - * tooltip will adjust itself to be displayed above, below, to the left - * or to the right depending on what is necessary to stay within the - * browser window. It is completely customizable as well via CSS. - * - * This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - */ - -(function($){ - $.fn.tipTip = function(options) { - var defaults = { - activation: "hover", - keepAlive: false, - maxWidth: "200px", - edgeOffset: 3, - defaultPosition: "bottom", - delay: 400, - fadeIn: 200, - fadeOut: 200, - attribute: "title", - content: false, // HTML or String to fill TipTIp with - enter: function(){}, - exit: function(){} - }; - var opts = $.extend(defaults, options); - - // Setup tip tip elements and render them to the DOM - if($("#tiptip_holder").length <= 0){ - var tiptip_holder = $('<div id="tiptip_holder" style="max-width:'+ opts.maxWidth +';"></div>'); - var tiptip_content = $('<div id="tiptip_content"></div>'); - var tiptip_arrow = $('<div id="tiptip_arrow"></div>'); - $("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>'))); - } else { - var tiptip_holder = $("#tiptip_holder"); - var tiptip_content = $("#tiptip_content"); - var tiptip_arrow = $("#tiptip_arrow"); - } - - return this.each(function(){ - var org_elem = $(this); - if(opts.content){ - var org_title = opts.content; - } else { - var org_title = org_elem.attr(opts.attribute); - } - if(org_title != ""){ - if(!opts.content){ - org_elem.removeAttr(opts.attribute); //remove original Attribute - } - var timeout = false; - - if(opts.activation == "hover"){ - org_elem.hover(function(){ - active_tiptip(); - }, function(){ - if(!opts.keepAlive){ - deactive_tiptip(); - } - }); - if(opts.keepAlive){ - tiptip_holder.hover(function(){}, function(){ - deactive_tiptip(); - }); - } - } else if(opts.activation == "focus"){ - org_elem.focus(function(){ - active_tiptip(); - }).blur(function(){ - deactive_tiptip(); - }); - } else if(opts.activation == "click"){ - org_elem.click(function(){ - active_tiptip(); - return false; - }).hover(function(){},function(){ - if(!opts.keepAlive){ - deactive_tiptip(); - } - }); - if(opts.keepAlive){ - tiptip_holder.hover(function(){}, function(){ - deactive_tiptip(); - }); - } - } - - function active_tiptip(){ - opts.enter.call(this); - tiptip_content.html(org_title); - tiptip_holder.hide().removeAttr("class").css("margin","0"); - tiptip_arrow.removeAttr("style"); - - var top = parseInt(org_elem.offset()['top']); - var left = parseInt(org_elem.offset()['left']); - var org_width = parseInt(org_elem.outerWidth()); - var org_height = parseInt(org_elem.outerHeight()); - var tip_w = tiptip_holder.outerWidth(); - var tip_h = tiptip_holder.outerHeight(); - var w_compare = Math.round((org_width - tip_w) / 2); - var h_compare = Math.round((org_height - tip_h) / 2); - var marg_left = Math.round(left + w_compare); - var marg_top = Math.round(top + org_height + opts.edgeOffset); - var t_class = ""; - var arrow_top = ""; - var arrow_left = Math.round(tip_w - 12) / 2; - - if(opts.defaultPosition == "bottom"){ - t_class = "_bottom"; - } else if(opts.defaultPosition == "top"){ - t_class = "_top"; - } else if(opts.defaultPosition == "left"){ - t_class = "_left"; - } else if(opts.defaultPosition == "right"){ - t_class = "_right"; - } - - var right_compare = (w_compare + left) < parseInt($(window).scrollLeft()); - var left_compare = (tip_w + left) > parseInt($(window).width()); - - if((right_compare && w_compare < 0) || (t_class == "_right" && !left_compare) || (t_class == "_left" && left < (tip_w + opts.edgeOffset + 5))){ - t_class = "_right"; - arrow_top = Math.round(tip_h - 13) / 2; - arrow_left = -12; - marg_left = Math.round(left + org_width + opts.edgeOffset); - marg_top = Math.round(top + h_compare); - } else if((left_compare && w_compare < 0) || (t_class == "_left" && !right_compare)){ - t_class = "_left"; - arrow_top = Math.round(tip_h - 13) / 2; - arrow_left = Math.round(tip_w); - marg_left = Math.round(left - (tip_w + opts.edgeOffset + 5)); - marg_top = Math.round(top + h_compare); - } - - var top_compare = (top + org_height + opts.edgeOffset + tip_h + 8) > parseInt($(window).height() + $(window).scrollTop()); - var bottom_compare = ((top + org_height) - (opts.edgeOffset + tip_h + 8)) < 0; - - if(top_compare || (t_class == "_bottom" && top_compare) || (t_class == "_top" && !bottom_compare)){ - if(t_class == "_top" || t_class == "_bottom"){ - t_class = "_top"; - } else { - t_class = t_class+"_top"; - } - arrow_top = tip_h; - marg_top = Math.round(top - (tip_h + 5 + opts.edgeOffset)); - } else if(bottom_compare | (t_class == "_top" && bottom_compare) || (t_class == "_bottom" && !top_compare)){ - if(t_class == "_top" || t_class == "_bottom"){ - t_class = "_bottom"; - } else { - t_class = t_class+"_bottom"; - } - arrow_top = -12; - marg_top = Math.round(top + org_height + opts.edgeOffset); - } - - if(t_class == "_right_top" || t_class == "_left_top"){ - marg_top = marg_top + 5; - } else if(t_class == "_right_bottom" || t_class == "_left_bottom"){ - marg_top = marg_top - 5; - } - if(t_class == "_left_top" || t_class == "_left_bottom"){ - marg_left = marg_left + 5; - } - tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"}); - tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class); - - if (timeout){ clearTimeout(timeout); } - timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay); - } - - function deactive_tiptip(){ - opts.exit.call(this); - if (timeout){ clearTimeout(timeout); } - tiptip_holder.fadeOut(opts.fadeOut); - } - } - }); - } -})(jQuery); diff --git a/addons/web/static/lib/jquery.tipTip/tipTip.css b/addons/web/static/lib/jquery.tipTip/tipTip.css index 4fb95d37691..dc41b650615 100644 --- a/addons/web/static/lib/jquery.tipTip/tipTip.css +++ b/addons/web/static/lib/jquery.tipTip/tipTip.css @@ -13,15 +13,15 @@ } #tiptip_holder.tip_bottom { - padding-top: 5px; + padding-bottom: 5px; } #tiptip_holder.tip_right { - padding-left: 5px; + padding-right: 5px; } #tiptip_holder.tip_left { - padding-right: 5px; + padding-left: 5px; } #tiptip_content { @@ -110,4 +110,25 @@ #tiptip_holder.tip_top #tiptip_arrow_inner { border-top-color: rgba(20,20,20,0.92); } +} + +/* Alternative theme for TipTip */ +#tiptip_holder.alt.tip_top #tiptip_arrow_inner { + border-top-color: #444444; +} + +#tiptip_holder.alt.tip_bottom #tiptip_arrow_inner { + border-bottom-color: #444444; +} + +#tiptip_holder.alt.tip_right #tiptip_arrow_inner { + border-right-color: #444444; +} + +#tiptip_holder.alt.tip_left #tiptip_arrow_inner { + border-left-color: #444444; +} + +#tiptip_holder.alt #tiptip_content { + background-color: #444444; border: 1px solid White; border-radius: 3px; box-shadow: 0 0 3px #555555; color: #FFFFFF; font-size: 11px; padding: 4px 8px; text-shadow: 0 0 1px Black; }
\ No newline at end of file diff --git a/addons/web/static/lib/qweb/qweb-benchmark.html b/addons/web/static/lib/qweb/qweb-benchmark.html index 0cc67e7e54f..4f7fb56ac1f 100644 --- a/addons/web/static/lib/qweb/qweb-benchmark.html +++ b/addons/web/static/lib/qweb/qweb-benchmark.html @@ -5,11 +5,25 @@ <script type="text/javascript" src="qweb.js"></script> <script type="text/javascript" src="qweb2.js"></script> <script type="text/javascript"> + (function (c) { + if (c.time) { return; } + var d = {}; + c.time = function (key) { + d[key] = Date.now(); + }; + c.timeEnd = function (key) { + var end = Date.now(), + origin = d[key]; + delete d[key]; + if (!origin) { return; } + console.log(key + ': ' + (end - origin) + 'ms'); + }; + })(window.console); var dict = { session : true, testing : 'yes', name : 'AGR' - } + }; console.time("Load template with QWeb"); QWeb.add_template("qweb-benchmark.xml"); console.timeEnd("Load template with QWeb"); diff --git a/addons/web/static/lib/qweb/qweb-test-call.xml b/addons/web/static/lib/qweb/qweb-test-call.xml index 5d8f0019f7c..3f7bd60ffbc 100644 --- a/addons/web/static/lib/qweb/qweb-test-call.xml +++ b/addons/web/static/lib/qweb/qweb-test-call.xml @@ -1,6 +1,6 @@ <templates> <t t-name="basic-callee">ok</t> - <t t-name="callee-printsbody"><t t-esc="0"/></t> + <t t-name="callee-printsbody"><t t-esc="__content__"/></t> <t t-name="callee-uses-foo"><t t-esc="foo"/></t> <t t-name="callee-sets-foo"><t t-set="foo" t-value="'ok'"/></t> diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index 093b3651fa0..8657a8b20be 100644 --- a/addons/web/static/lib/qweb/qweb2.js +++ b/addons/web/static/lib/qweb/qweb2.js @@ -194,7 +194,7 @@ var QWeb2 = { QWeb2.Engine = (function() { function Engine() { - // TODO: handle prefix at template level : t-prefix="x" + // TODO: handle prefix at template level : t-prefix="x", don't forget to lowercase it this.prefix = 't'; this.debug = false; this.templates_resources = []; // TODO: implement this.reload() @@ -329,12 +329,12 @@ QWeb2.Engine = (function() { " return r.join('');"; }, render : function(template, dict) { - var ndict = QWeb2.tools.extend({}, this.default_dict); - QWeb2.tools.extend(ndict, dict); + dict = dict || {}; + QWeb2.tools.extend(dict, this.default_dict); /*if (this.debug && window['console'] !== undefined) { console.time("QWeb render template " + template); }*/ - var r = this._render(template, ndict); + var r = this._render(template, dict); /*if (this.debug && window['console'] !== undefined) { console.timeEnd("QWeb render template " + template); }*/ @@ -620,7 +620,7 @@ QWeb2.Element = (function() { } } } - if (this.tag !== this.engine.prefix) { + if (this.tag.toLowerCase() !== this.engine.prefix) { var tag = "<" + this.tag; for (var a in this.attributes) { tag += this.engine.tools.gen_attribute([a, this.attributes[a]]); diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index d4bd7a6ff1b..32c7f14b345 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,5 @@ -body.openerp { +body { padding: 0; margin: 0; } +.openerp { padding: 0; margin: 0; height: 100%; @@ -7,7 +8,8 @@ body.openerp { font-family: Ubuntu, Helvetica, sans-serif; } -body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, .openerp button, .openerp .ui-widget { +.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, +.openerp button, .openerp .ui-widget { font-family: Ubuntu, Helvetica, sans-serif; font-size:85%; } @@ -1416,7 +1418,7 @@ label.error { } @-moz-document url-prefix() { /* Strange firefox behaviour on width: 100% + white-space: nowrap */ - .openerp .oe_forms .oe_button { + .openerp .oe_forms .oe_form_button .oe_button { width: auto; } } @@ -1851,15 +1853,28 @@ label.error { } .openerp .oe-treeview-table { width: 100%; + background-color : #FFFFFF; + border-spacing: 0; +} +.openerp .oe-treeview-table tr:hover{ + color: blue; + background-color : #D8D8D8; } .treeview-tr, .treeview-td { cursor: pointer; vertical-align: top; text-align: left; + border-bottom: 1px solid #CFCCCC; +} +.oe-number{ + text-align: right !important; } .treeview-tr span, .treeview-td span { + font-size: 90%; + font-weight: normal; + white-space: nowrap; display: block; -} + } .treeview-tr:first-of-type { background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; } @@ -1872,8 +1887,11 @@ label.error { } .treeview-header { - text-align: left; vertical-align: top; + background-color : #D8D8D8; + white-space: nowrap; + text-align: left; + padding: 4px 5px; } /* Shortcuts*/ .oe-shortcut-toggle { diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 39bc0181e16..8b9a0d4efc6 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -205,7 +205,7 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({ buttons: buttons }).open(); dialog.$element.html(QWeb.render('CrashManagerError', {session: openerp.connection, error: error})); - }, + } }); openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading# */{ @@ -280,6 +280,9 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database init: function(parent, element_id, option_id) { this._super(parent, element_id); this.unblockUIFunction = $.unblockUI; + $.validator.addMethod('matches', function (s, _, re) { + return new RegExp(re).test(s); + }, _t("Invalid database name")); }, start: function() { this.$option_id = $("#oe_db_options"); @@ -646,7 +649,7 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{ } } }); - }, + } }); openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# */{ @@ -1059,13 +1062,9 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie this._current_state = null; }, - render_element: function() { - this.$element = $('<body/>'); - this.$element.attr("id", "oe"); - this.$element.addClass("openerp"); - }, start: function() { var self = this; + this.$element = $(document.body); if (jQuery.param != undefined && jQuery.deparam(jQuery.param.querystring()).kitten != undefined) { this.$element.addClass("kitten-mode-activated"); this.$element.delegate('img.oe-record-edit-link-img', 'hover', function(e) { @@ -1089,7 +1088,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie self.bind_hashchange(); if (!self.session.openerp_entreprise) { self.$element.find('.oe_footer_powered').append('<span> - <a href="http://www.openerp.com/support-or-publisher-warranty-contract" target="_blank">Unsupported/Community Version</a></span>'); - $('title').html('OpenERP - Unsupported/Community Version'); + document.title = _t("OpenERP - Unsupported/Community Version"); } }); }, @@ -1212,7 +1211,7 @@ openerp.web.EmbeddedClient = openerp.web.Widget.extend({ self.am.do_action(action); }); - }, + } }); diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index b36e576ae47..3005fc80d13 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -491,7 +491,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. dataType: 'json', contentType: 'application/json', data: JSON.stringify(payload), - processData: false, + processData: false }, url); if (this.synch) ajax.async = false; @@ -502,7 +502,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. // extracted from payload to set on the url var data = { session_id: this.session_id, - id: payload.id, + id: payload.id }; url.url = this.get_url(url.url); var ajax = _.extend({ @@ -864,7 +864,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. } finally { this.synch = synch; } - }, + } }); /** diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 447b95d17cf..bb53fb2175a 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -829,9 +829,9 @@ openerp.web.Model = openerp.web.CallbackEnabled.extend({ model: this.model_name, method: method, args: args, - kwargs: kwargs, + kwargs: kwargs }); - }, + } }); openerp.web.CompoundContext = openerp.web.Class.extend({ diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js index 78be735edc7..3d15a4e3607 100644 --- a/addons/web/static/src/js/data_export.js +++ b/addons/web/static/src/js/data_export.js @@ -364,9 +364,8 @@ openerp.web.DataExport = openerp.web.Dialog.extend({ on_click_export_data: function() { var self = this; var exported_fields = this.$element.find('#fields_list option').map(function () { - var name = self.records[this.value] || this.value // DOM property is textContent, but IE8 only knows innerText - return {name: this.value, + return {name: self.records[this.value] || this.value, label: this.textContent || this.innerText}; }).get(); diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js index bf920380ff9..6e58886fadd 100644 --- a/addons/web/static/src/js/view_editor.js +++ b/addons/web/static/src/js/view_editor.js @@ -806,7 +806,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ 'widget' : {'name':'widget', 'string': 'widget', 'type': 'selection'}, 'colors' : {'name':'colors', 'string': 'Colors', 'type': 'char'}, 'editable' : {'name':'editable', 'string': 'Editable', 'type': 'selection', 'selection': [["",""],["top","Top"],["bottom", "Bottom"]]}, - 'groups' : {'name':'groups', 'string': 'Groups', 'type': 'seleciton_multi'}, + 'groups' : {'name':'groups', 'string': 'Groups', 'type': 'seleciton_multi'} }; var arch_val = self.get_object_by_id(this.one_object.clicked_tr_id,this.one_object['main_object'], []); this.edit_node_dialog.$element.append('<table id="rec_table" style="width:400px" class="oe_forms"></table>'); @@ -928,7 +928,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ type: 'ir.actions.act_window', target: "new", flags: { - action_buttons: true, + action_buttons: true } } var action_manager = new openerp.web.ActionManager(self); @@ -982,7 +982,7 @@ openerp.web.ViewEditor.Field = openerp.web.Class.extend({ }, render: function() { return _.str.sprintf("<td id = %s>%s</td>", this.name, QWeb.render(this.template, {widget: this})) - }, + } }); openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({ template : "vieweditor_boolean", @@ -1084,7 +1084,7 @@ var _PROPERTIES = { 'action' : ['name', 'string', 'colspan', 'groups'], 'tree' : ['string', 'colors', 'editable', 'link', 'limit', 'min_rows'], 'graph' : ['string', 'type'], - 'calendar' : ['string', 'date_start', 'date_stop', 'date_delay', 'day_length', 'color', 'mode'], + 'calendar' : ['string', 'date_start', 'date_stop', 'date_delay', 'day_length', 'color', 'mode'] }; var _CHILDREN = { 'form': ['notebook', 'group', 'field', 'label', 'button','board', 'newline', 'separator'], @@ -1100,7 +1100,7 @@ var _CHILDREN = { 'label': [], 'button' : [], 'newline': [], - 'separator': [], + 'separator': [] }; var _ICONS = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD', 'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER', @@ -1134,6 +1134,6 @@ openerp.web.ViewEditor.property_widget = new openerp.web.Registry({ 'seleciton_multi' : 'openerp.web.ViewEditor.FieldSelectMulti', 'selection' : 'openerp.web.ViewEditor.FieldSelect', 'char' : 'openerp.web.ViewEditor.FieldChar', - 'float' : 'openerp.web.ViewEditor.FieldFloat', + 'float' : 'openerp.web.ViewEditor.FieldFloat' }); }; diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index ebe1ca26785..ebcbfc18100 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -40,7 +40,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# this.fields = {}; this.fields_order = []; this.datarecord = {}; - this.show_invalid = true; this.default_focus_field = null; this.default_focus_button = null; this.registry = openerp.web.form.widgets; @@ -179,7 +178,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# }); return $.when.apply(null, set_values).pipe(function() { if (!record.id) { - self.show_invalid = false; // New record: Second pass in order to trigger the onchanges // respecting the fields order defined in the view _.each(self.fields_order, function(field_name) { @@ -192,7 +190,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# } self.on_form_changed(); self.is_initialized.resolve(); - self.show_invalid = true; self.do_update_pager(record.id == null); if (self.sidebar) { self.sidebar.attachments.do_update(); @@ -429,7 +426,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# f = self.fields[f]; if (!f.is_valid()) { form_invalid = true; - f.update_dom(); + f.update_dom(true); if (!first_invalid_field) { first_invalid_field = f; } @@ -716,9 +713,11 @@ openerp.web.form.compute_domain = function(expr, fields) { stack.push(field_value >= val); break; case 'in': + if (!_.isArray(val)) val = [val]; stack.push(_(val).contains(field_value)); break; case 'not in': + if (!_.isArray(val)) val = [val]; stack.push(!_(val).contains(field_value)); break; default: @@ -791,6 +790,11 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form. return QWeb.render(template, { "widget": this }); }, do_attach_tooltip: function(widget, trigger, options) { + if ($.browser.mozilla && parseInt($.browser.version.split('.')[0], 10) < 2) { + // Unknown bug in old version of firefox : + // input type=text onchange event not fired when tootip is shown + return; + } widget = widget || this; trigger = trigger || this.$element; options = _.extend({ @@ -1063,7 +1067,6 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ this.execute_action().always(function() { self.force_disabled = false; self.check_disable(); - $.tipTipClear(); }); }, execute_action: function() { @@ -1075,17 +1078,17 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ title: _t('Confirm'), modal: true, buttons: [ + {text: _t("Cancel"), click: function() { + def.resolve(); + $(this).dialog("close"); + } + }, {text: _t("Ok"), click: function() { self.on_confirmed().then(function() { def.resolve(); }); $(this).dialog("close"); } - }, - {text: _t("Cancel"), click: function() { - def.resolve(); - $(this).dialog("close"); - } } ] }); @@ -1116,7 +1119,7 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ }); }, update_dom: function() { - this._super(); + this._super.apply(this, arguments); this.check_disable(); }, check_disable: function() { @@ -1238,7 +1241,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f get_on_change_value: function() { return this.get_value(); }, - update_dom: function() { + update_dom: function(show_invalid) { this._super.apply(this, arguments); if (this.field.translate) { this.$element.find('.oe_field_translate').toggle(!!this.view.datarecord.id); @@ -1246,7 +1249,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f if (!this.disable_utility_classes) { this.$element.toggleClass('disabled', this.readonly); this.$element.toggleClass('required', this.required); - if (this.view.show_invalid) { + if (show_invalid) { this.$element.toggleClass('invalid', !this.is_valid()); } } @@ -1259,7 +1262,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.view.do_onchange(this); this.view.on_form_changed(); } else { - this.update_dom(); + this.update_dom(true); } }, validate: function() { @@ -1281,7 +1284,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.definition_options = JSON.parse(str); } return this.definition_options; - }, + } }); openerp.web.form.FieldChar = openerp.web.form.Field.extend({ @@ -2424,7 +2427,7 @@ openerp.web.form.One2ManyListView = openerp.web.ListView.extend({ var self = this; var def = $.Deferred().then(callback).then(function() {self.o2m.view.reload();}); return this._super(name, id, _.bind(def.resolve, def)); - }, + } }); openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({ @@ -3214,7 +3217,6 @@ openerp.web.form.widgets = new openerp.web.Registry({ 'email' : 'openerp.web.form.FieldEmail', 'url' : 'openerp.web.form.FieldUrl', 'text' : 'openerp.web.form.FieldText', - 'text_wiki' : 'openerp.web.form.FieldText', 'date' : 'openerp.web.form.FieldDate', 'datetime' : 'openerp.web.form.FieldDatetime', 'selection' : 'openerp.web.form.FieldSelection', diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index aa970c31649..1f8a6020f46 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -1316,19 +1316,24 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L if (!self.datagroup.openable) { view.configure_pager(dataset); } else { - var pages = Math.ceil(dataset.ids.length / limit); - self.$row - .find('.oe-pager-state') - .text(_.str.sprintf(_t("%(page)d/%(page_count)d"), { - page: page + 1, - page_count: pages - })) - .end() - .find('button[data-pager-action=previous]') - .attr('disabled', page === 0) - .end() - .find('button[data-pager-action=next]') - .attr('disabled', page === pages - 1); + if (dataset.ids.length == records.length) { + // only one page + self.$row.find('td.oe-group-pagination').empty(); + } else { + var pages = Math.ceil(dataset.ids.length / limit); + self.$row + .find('.oe-pager-state') + .text(_.str.sprintf(_t("%(page)d/%(page_count)d"), { + page: page + 1, + page_count: pages + })) + .end() + .find('button[data-pager-action=previous]') + .attr('disabled', page === 0) + .end() + .find('button[data-pager-action=next]') + .attr('disabled', page === pages - 1); + } } self.records.add(records, {silent: true}); diff --git a/addons/web/static/src/js/view_page.js b/addons/web/static/src/js/view_page.js index d3ee79effca..31190d70f85 100644 --- a/addons/web/static/src/js/view_page.js +++ b/addons/web/static/src/js/view_page.js @@ -241,7 +241,6 @@ openerp.web.page = function (openerp) { 'email': 'openerp.web.page.FieldEmailReadonly', 'url': 'openerp.web.page.FieldUrlReadonly', 'text': 'openerp.web.page.FieldCharReadonly', - 'text_wiki' : 'openerp.web.page.FieldCharReadonly', 'date': 'openerp.web.page.FieldCharReadonly', 'datetime': 'openerp.web.page.FieldCharReadonly', 'selection' : 'openerp.web.page.FieldSelectionReadonly', diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 5158fda62c2..b119e5aae3c 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -70,7 +70,8 @@ </tr> <tr> <td><label for="db_name">New database name:</label></td> - <td><input type="text" name="db_name" class="required"/></td> + <td><input type="text" name="db_name" + class="required" matches="^[a-zA-Z][a-zA-Z0-9_]+$"/></td> </tr> <tr> <td><label for="demo_data">Load Demonstration data:</label></td> @@ -553,16 +554,21 @@ t-att-data-id="record.id" t-att-data-level="level + 1"> <t t-set="children" t-value="record[children_field]"/> <t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/> + <t t-set="style" t-value="'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;'"/> <td t-foreach="fields_view" t-as="field" t-if="!field.attrs.modifiers.tree_invisible" t-att-data-id="record.id" - t-att-style="color_for(record) + (!field_index ? 'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;' : '')" - t-att-class="class"> - <span t-if="!field.attrs.modifiers.invisible"> + t-att-style="color_for(record) + style " + t-att-class="(fields[field.attrs.name].type === 'float') or (fields[field.attrs.name].type === 'integer') + ? (class +' ' +'oe-number') : class"> + + <span t-if="!field.attrs.modifiers.invisible" > <t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" /> </span> + <t t-set="class" t-value="'treeview-td'"/> + <t t-set="style" t-value="''"/> </td> </tr> @@ -1717,32 +1723,18 @@ <t t-name="About-Page"> <div> - <a class="oe_activate_debug_mode" href="?debug">Debug mode</a> - <h1>OpenERP Web</h1> - <h3 style="padding:0 5px 5px">Version <t t-esc="version_info.version"/></h3> + <a class="oe_activate_debug_mode" href="?debug" style="float:right; font-size: 80%;">Activate the developper mode</a> + <h1 style="margin:0;">OpenERP</h1> + <h3 style="margin:15px 0;padding:0;">Version <t t-esc="version_info.version"/></h3> <p> - Copyright © 2011-TODAY OpenERP SA. All Rights Reserved.<br /> + Copyright © 2004-TODAY OpenERP SA. All Rights Reserved.<br /> OpenERP is a trademark of the <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP SA Company</a>. </p> <p> Licenced under the terms of <a target="_blank" href="http://www.gnu.org/licenses/agpl.html" style="text-decoration: underline;">GNU Affero General Public License</a> </p> - <br /> - <h1>About OpenERP</h1> - <p> - <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP</a> is a free enterprise-scale software system that is designed to boost - productivity and profit through data integration. It connects, improves and - manages business processes in areas such as sales, finance, supply chain, - project management, production, services, CRM, etc... - </p> - <p> - The system is platform-independent, and can be installed on Windows, Mac OS X, - and various Linux and other Unix-based distributions. Its architecture enables - new functionality to be rapidly created, modifications to be made to a - production system and migration to a new version to be straightforward. - </p> <p> - Depending on your needs, OpenERP is available through a web or application client. + For more information visit <a target="_blank" href="http://openerp.com/" style="text-decoration: underline;">OpenERP.com</a> </p> </div> </t> |
