diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index a66bd4687a7..6921b36f91d 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -23,6 +23,7 @@ "static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js", "static/lib/jquery.ui.notify/js/jquery.notify.js", "static/lib/jquery.deferred-queue/jquery.deferred-queue.js", + "static/lib/jquery.scrollTo/jquery.scrollTo-min.js", "static/lib/json/json2.js", "static/lib/qweb/qweb2.js", "static/lib/underscore/underscore.js", diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 74285b1f444..6f72d836ea4 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1193,19 +1193,26 @@ class Export(View): @openerpweb.jsonrequest def get_fields(self, req, model, prefix='', parent_name= '', - import_compat=True, parent_field_type=None): + import_compat=True, parent_field_type=None, + exclude=None): if import_compat and parent_field_type == "many2one": fields = {} else: fields = self.fields_get(req, model) - fields['.id'] = fields.pop('id') if 'id' in fields else {'string': 'ID'} + + if import_compat: + fields.pop('id', None) + else: + fields['.id'] = fields.pop('id', {'string': 'ID'}) fields_sequence = sorted(fields.iteritems(), key=lambda field: field[1].get('string', '')) records = [] for field_name, field in fields_sequence: + if import_compat and (exclude and field_name in exclude): + continue if import_compat and field.get('readonly'): # If none of the field's states unsets readonly, skip the field if all(dict(attrs).get('readonly', True) @@ -1217,7 +1224,8 @@ class Export(View): record = {'id': id, 'string': name, 'value': id, 'children': False, 'field_type': field.get('type'), - 'required': field.get('required')} + 'required': field.get('required'), + 'relation_field': field.get('relation_field')} records.append(record) if len(name.split('/')) < 3 and 'relation' in field: @@ -1249,7 +1257,6 @@ class Export(View): def fields_info(self, req, model, export_fields): info = {} fields = self.fields_get(req, model) - fields['.id'] = fields.pop('id') if 'id' in fields else {'string': 'ID'} # To make fields retrieval more efficient, fetch all sub-fields of a # given field at the same time. Because the order in the export list is diff --git a/addons/web/po/ar.po b/addons/web/po/ar.po index 0aac2c8aed2..4a6ebecff9f 100644 --- a/addons/web/po/ar.po +++ b/addons/web/po/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-08 06:12+0000\n" -"X-Generator: Launchpad (build 14231)\n" +"X-Launchpad-Export-Date: 2011-11-09 05:09+0000\n" +"X-Generator: Launchpad (build 14263)\n" #: addons/web/static/src/js/view_form.js:355 msgid "" diff --git a/addons/web/po/da.po b/addons/web/po/da.po index c0931065d1e..db03cc5e19b 100644 --- a/addons/web/po/da.po +++ b/addons/web/po/da.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2011-10-07 10:38+0200\n" -"PO-Revision-Date: 2011-10-11 14:21+0000\n" +"PO-Revision-Date: 2011-11-08 21:58+0000\n" "Last-Translator: Jonas Mortensen \n" "Language-Team: Danish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n" -"X-Generator: Launchpad (build 14197)\n" +"X-Launchpad-Export-Date: 2011-11-09 05:09+0000\n" +"X-Generator: Launchpad (build 14263)\n" #: addons/web/static/src/js/view_form.js:355 msgid "" @@ -264,7 +264,7 @@ msgstr "oe_secondary_menu_item" #: addons/web/static/src/xml/base.xml:0 msgid "oe_secondary_submenu_item" -msgstr "" +msgstr "oe_secondary_submenu_item" #: addons/web/static/src/xml/base.xml:0 msgid "Hide this tip" diff --git a/addons/web/static/lib/jquery.scrollTo/changes.txt b/addons/web/static/lib/jquery.scrollTo/changes.txt new file mode 100644 index 00000000000..4b2933f6667 --- /dev/null +++ b/addons/web/static/lib/jquery.scrollTo/changes.txt @@ -0,0 +1,91 @@ +1.4.2 +[Feature] +- The plugin support percentages as target ('50%' or {top:'50%', left:'45%'}) +- Exposed the max() calculation as $.scrollTo.max +[Enhancement] +- Renamed $.fn.scrollable to $.fn._scrollable to avoid conflicts with other plugins +[Fix] +- Fixing max calculations for regular DOM elements + +1.4.1 +[Feature] +- The target can be 'max' to scroll to the end while keeping it elegant. +[Enhancement] +- Default duration is 0 for jquery +1.3. Means sync animation +- The plugin works on all major browsers, on compat & quirks modes, including iframes. +- In addition to window/document, if html or body are received, the plugin will choose the right one. +[Fix] +- The plugin accepts floating numbers, Thanks Ramin +- Using jQuery.nodeName where neccessary so that this works on xml+xhtml +- The max() internal function wasn't completely accurrate, now it is 98% (except for IE on quirks mode and it's not too noticeable). + +1.4 +[Fix] +- Fixed the problem when scrolling the window to absolute positioned elements on Safari. +- Fixed the problem on Opera 9.5 when scrolling the window. That it always scrolls to 0. +[Feature] +- Added the settings object as 2nd argument to the onAfter callback. +- The 3rd argument of scrollTo can be just a function and it's used as the onAfter. +- Added full support for iframes (even max scroll calculation). +- Instead of $.scrollTo, $(window).scrollTo() and $(document).scrollTo() can be used. +- Added $().scrollable() that returns the real element to scroll, f.e: $(window).scrollable() == [body|html], works for iframes. +[Enhancement] +- Cleaned the code a bit, specially the comments + +1.3.3 +[Change] +- Changed the licensing from GPL to GPL+MIT. + +1.3.2 +[Enhancement] +- Small improvements to make the code shorter. +[Change] +- Removed the last argument received by onAfter as it was the same as the 'this' but jqueryfied. + +1.3.1 +[Feature] +- Exposed $.scrollTo.window() to get the element that needs to be animated, to scroll the window. +- Added option 'over'. +[Enhancement] +- Made the code as short as possible. +[Change] +- Changed the arguments received by onAfter + +1.3 +[Enhancement] +- Added semicolon to the start, for safe file concatenation +- Added a limit check, values below 0 or over the maximum are fixed. +- Now it should work faster, only one of html or body go through all the processing, instead of both for all browsers. +[Fix] +- Fixed the behavior for Opera, which seemed to react to both changes on and . +- The border is also reduced, when 'margin' is set to true. +[Change] +- The option speed has been renamed to duration. +[Feature] +- The duration can be specified with a number as 2nd argument, and the rest of the settings as the third ( like $().animate ) +- Remade the demo + +1.2.4 +[Enhancement] +- The target can be in the form of { top:x, left:y } allowing different position for each axis. +[Feature] +- The option 'offset' has been added, to scroll behind or past the target. Can be a number(both axes) or { top:x, left:y }. + +1.2.3 +[Feature] +- Exposed the defaults. +[Enhancement] +- Made the callback functions receive more parameters. + +1.2.2 +[Fix] +- Fixed a bug, I didn't have to add the scrolled amount if it was body or html. + +1.2 +[Change] +- The option 'onafter' is now called 'onAfter'. +[Feature] +- Two axes can be scrolled together, this is set with the option 'axis'. +- In case 2 axes are chosen, the scrolling can be queued: one scrolls, and then the other. +- There's an intermediary event, 'onAfterFirst' called in case the axes are queued, after the first ends. +- If the option 'margin' is set to true, the plugin will take in account, the margin of the target(no use if target is a value). \ No newline at end of file diff --git a/addons/web/static/lib/jquery.scrollTo/jquery.scrollTo-min.js b/addons/web/static/lib/jquery.scrollTo/jquery.scrollTo-min.js new file mode 100644 index 00000000000..73a334184e4 --- /dev/null +++ b/addons/web/static/lib/jquery.scrollTo/jquery.scrollTo-min.js @@ -0,0 +1,11 @@ +/** + * jQuery.ScrollTo - Easy element scrolling using jQuery. + * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Dual licensed under MIT and GPL. + * Date: 5/25/2009 + * @author Ariel Flesler + * @version 1.4.2 + * + * http://flesler.blogspot.com/2007/10/jqueryscrollto.html + */ +;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery); \ No newline at end of file diff --git a/addons/web/static/lib/jquery.scrollTo/jquery.scrollTo.js b/addons/web/static/lib/jquery.scrollTo/jquery.scrollTo.js new file mode 100644 index 00000000000..eec31e191cb --- /dev/null +++ b/addons/web/static/lib/jquery.scrollTo/jquery.scrollTo.js @@ -0,0 +1,215 @@ +/** + * jQuery.ScrollTo + * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Dual licensed under MIT and GPL. + * Date: 5/25/2009 + * + * @projectDescription Easy element scrolling using jQuery. + * http://flesler.blogspot.com/2007/10/jqueryscrollto.html + * Works with jQuery +1.2.6. Tested on FF 2/3, IE 6/7/8, Opera 9.5/6, Safari 3, Chrome 1 on WinXP. + * + * @author Ariel Flesler + * @version 1.4.2 + * + * @id jQuery.scrollTo + * @id jQuery.fn.scrollTo + * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements. + * The different options for target are: + * - A number position (will be applied to all axes). + * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes + * - A jQuery/DOM element ( logically, child of the element to scroll ) + * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc ) + * - A hash { top:x, left:y }, x and y can be any kind of number/string like above. +* - A percentage of the container's dimension/s, for example: 50% to go to the middle. + * - The string 'max' for go-to-end. + * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead. + * @param {Object,Function} settings Optional set of settings or the onAfter callback. + * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'. + * @option {Number} duration The OVERALL length of the animation. + * @option {String} easing The easing method for the animation. + * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position. + * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }. + * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes. + * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends. + * @option {Function} onAfter Function to be called after the scrolling ends. + * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends. + * @return {jQuery} Returns the same jQuery object, for chaining. + * + * @desc Scroll to a fixed position + * @example $('div').scrollTo( 340 ); + * + * @desc Scroll relatively to the actual position + * @example $('div').scrollTo( '+=340px', { axis:'y' } ); + * + * @dec Scroll using a selector (relative to the scrolled element) + * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } ); + * + * @ Scroll to a DOM element (same for jQuery object) + * @example var second_child = document.getElementById('container').firstChild.nextSibling; + * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){ + * alert('scrolled!!'); + * }}); + * + * @desc Scroll on both axes, to different values + * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } ); + */ +;(function( $ ){ + + var $scrollTo = $.scrollTo = function( target, duration, settings ){ + $(window).scrollTo( target, duration, settings ); + }; + + $scrollTo.defaults = { + axis:'xy', + duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1 + }; + + // Returns the element that needs to be animated to scroll the window. + // Kept for backwards compatibility (specially for localScroll & serialScroll) + $scrollTo.window = function( scope ){ + return $(window)._scrollable(); + }; + + // Hack, hack, hack :) + // Returns the real elements to scroll (supports window/iframes, documents and regular nodes) + $.fn._scrollable = function(){ + return this.map(function(){ + var elem = this, + isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1; + + if( !isWin ) + return elem; + + var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem; + + return $.browser.safari || doc.compatMode == 'BackCompat' ? + doc.body : + doc.documentElement; + }); + }; + + $.fn.scrollTo = function( target, duration, settings ){ + if( typeof duration == 'object' ){ + settings = duration; + duration = 0; + } + if( typeof settings == 'function' ) + settings = { onAfter:settings }; + + if( target == 'max' ) + target = 9e9; + + settings = $.extend( {}, $scrollTo.defaults, settings ); + // Speed is still recognized for backwards compatibility + duration = duration || settings.speed || settings.duration; + // Make sure the settings are given right + settings.queue = settings.queue && settings.axis.length > 1; + + if( settings.queue ) + // Let's keep the overall duration + duration /= 2; + settings.offset = both( settings.offset ); + settings.over = both( settings.over ); + + return this._scrollable().each(function(){ + var elem = this, + $elem = $(elem), + targ = target, toff, attr = {}, + win = $elem.is('html,body'); + + switch( typeof targ ){ + // A number will pass the regex + case 'number': + case 'string': + if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){ + targ = both( targ ); + // We are done + break; + } + // Relative selector, no break! + targ = $(targ,this); + case 'object': + // DOMElement / jQuery + if( targ.is || targ.style ) + // Get the real position of the target + toff = (targ = $(targ)).offset(); + } + $.each( settings.axis.split(''), function( i, axis ){ + var Pos = axis == 'x' ? 'Left' : 'Top', + pos = Pos.toLowerCase(), + key = 'scroll' + Pos, + old = elem[key], + max = $scrollTo.max(elem, axis); + + if( toff ){// jQuery / DOMElement + attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] ); + + // If it's a dom element, reduce the margin + if( settings.margin ){ + attr[key] -= parseInt(targ.css('margin'+Pos)) || 0; + attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0; + } + + attr[key] += settings.offset[pos] || 0; + + if( settings.over[pos] ) + // Scroll to a fraction of its width/height + attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos]; + }else{ + var val = targ[pos]; + // Handle percentage values + attr[key] = val.slice && val.slice(-1) == '%' ? + parseFloat(val) / 100 * max + : val; + } + + // Number or 'number' + if( /^\d+$/.test(attr[key]) ) + // Check the limits + attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max ); + + // Queueing axes + if( !i && settings.queue ){ + // Don't waste time animating, if there's no need. + if( old != attr[key] ) + // Intermediate animation + animate( settings.onAfterFirst ); + // Don't animate this axis again in the next iteration. + delete attr[key]; + } + }); + + animate( settings.onAfter ); + + function animate( callback ){ + $elem.animate( attr, duration, settings.easing, callback && function(){ + callback.call(this, target, settings); + }); + }; + + }).end(); + }; + + // Max scrolling position, works on quirks mode + // It only fails (not too badly) on IE, quirks mode. + $scrollTo.max = function( elem, axis ){ + var Dim = axis == 'x' ? 'Width' : 'Height', + scroll = 'scroll'+Dim; + + if( !$(elem).is('html,body') ) + return elem[scroll] - $(elem)[Dim.toLowerCase()](); + + var size = 'client' + Dim, + html = elem.ownerDocument.documentElement, + body = elem.ownerDocument.body; + + return Math.max( html[scroll], body[scroll] ) + - Math.min( html[size] , body[size] ); + + }; + + function both( val ){ + return typeof val == 'object' ? val : { top:val, left:val }; + }; + +})( jQuery ); \ No newline at end of file diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 94e36d60419..01f4b11f4d3 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -654,6 +654,9 @@ label.error { display: none; } +.openerp .oe_search-view-buttons { + padding: 10px 0 10px 0; +} .openerp .oe_search-view-custom-filter-btn span { background: url(/web/static/src/img/icons/gtk-add.png) repeat-y; padding-left: 18px; @@ -1080,11 +1083,16 @@ label.error { } .openerp .oe-view-manager-logs { clear: both; - font-size: 85%; - margin: 0.25em 0; background: #fff; - padding: 0 10px; + margin: 0.25em 0; + font-size: 85%; color: #4C4C4C; + position: relative; + overflow: hidden; +} +.openerp .oe-view-manager-logs ul { + margin: 0; + padding: 0 10px; list-style: none; } .openerp .oe-view-manager-logs li:before { @@ -1094,6 +1102,24 @@ label.error { text-decoration: none; color: inherit; } +/* only display first three log items of a folded logs list */ +.openerp .oe-view-manager-logs.oe-folded li:nth-child(n+4) { + display: none; +} +/* display link to more logs if there are more logs to view and the logview is + currently folded */ +.openerp .oe-view-manager-logs a.oe-more-logs { + display: none; +} +.openerp .oe-view-manager-logs.oe-folded.oe-has-more a.oe-more-logs { + display: block; +} +.openerp .oe-view-manager-logs a.oe-remove-everything { + position: absolute; + top: 0; + right: 0; + cursor: pointer; +} .openerp .view-manager-main-sidebar { width: 180px; diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 5fba5f4d8d4..58dcd922ea9 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -65,6 +65,11 @@ openerp.web = function(instance) { openerp.web[files[i]](instance); } } + instance.log = function() { + if (instance.connection.debug && window.console) { + console.log.apply(console, arguments); + } + } }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index d85942feead..25b73ee59d5 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -109,7 +109,7 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# } }, start: function () { - this.$dialog = $('
').dialog(this.dialog_options); + this.$dialog = $(this.$element).dialog(this.dialog_options); this._super(); return this; }, diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 7b402cae7fd..1929c573e42 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -792,6 +792,11 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * @type string */ identifier_prefix: 'generic-identifier-', + /** + * Tag name when creating a default $element. + * @type string + */ + tag_name: 'div', /** * Construct the widget and set its parent if a parent is given. * @@ -814,7 +819,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W this.element_id = element_id; this.element_id = this.element_id || _.uniqueId(this.identifier_prefix); var tmp = document.getElementById(this.element_id); - this.$element = tmp ? $(tmp) : undefined; + this.$element = tmp ? $(tmp) : $(document.createElement(this.tag_name)); this.widget_parent = parent; this.widget_children = []; @@ -869,8 +874,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, _render_and_insert: function(insertion, target) { - var rendered = this.render(); - this.$element = $(rendered); + this.render_element(); if (target instanceof openerp.web.Widget) target = target.$element; insertion(target); @@ -878,6 +882,15 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W return this.start(); }, on_inserted: function(element, widget) {}, + /** + * Renders the element and insert the result of the render() method in this.$element. + */ + render_element: function() { + var rendered = this.render(); + if (rendered || rendered === "") + this.$element = $(rendered); + return this; + }, /** * Renders the widget using QWeb, `this.template` must be defined. * The context given to QWeb contains the "widget" key that references `this`. @@ -885,7 +898,9 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * @param {Object} additional Additional context arguments to pass to the template. */ render: function (additional) { - return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {})); + if (this.template) + return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {})); + return false; }, /** * Method called after rendering. Mostly used to bind actions, perform asynchronous diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js index 51ac2cbd568..ea142606b5b 100644 --- a/addons/web/static/src/js/data_export.js +++ b/addons/web/static/src/js/data_export.js @@ -165,7 +165,11 @@ openerp.web.DataExport = openerp.web.Dialog.extend({ } var model = record['params']['model'], prefix = record['params']['prefix'], - name = record['params']['name']; + name = record['params']['name'], + exclude_fields = []; + if (record['relation_field']) { + exclude_fields.push(record['relation_field']); + } if (!record.loaded) { var import_comp = self.$element.find("#import_compat").val(); @@ -174,7 +178,8 @@ openerp.web.DataExport = openerp.web.Dialog.extend({ prefix: prefix, parent_name: name, import_compat: Boolean(import_comp), - parent_field_type : record['field_type'] + parent_field_type : record['field_type'], + exclude: exclude_fields }, function(results) { record.loaded = true; self.on_show_data(results, record.id); diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js index 639ade0e6a4..39738f0d20e 100644 --- a/addons/web/static/src/js/view_editor.js +++ b/addons/web/static/src/js/view_editor.js @@ -336,11 +336,16 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ } switch (this.id) { case "side-add": - var tr = $(this).closest("tr[id^='viewedit-']").find('a').text(); + var tr = $(this).closest("tr[id^='viewedit-']").find('a').text(); var tag = _.detect(_.keys(_CHILDREN),function(res){ return _.includes(tr, res); }); - var properties = _CHILDREN[tag]; + self.rpc("/web/searchview/fields_get", {model:self.model}, function(result) { + var fields = _.keys(result.fields); + fields.push(" "); + fields.sort(); + self.on_add_node(_CHILDREN[tag],fields); + }); break; case "side-remove": break; @@ -480,7 +485,6 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ _.each(update_values, function(val){ if(val[0] == "required"){ $(arch1).attr("required", "true"); - console.log(arch1); }else{ $(arch1).attr(val[0],val[1]); } @@ -504,7 +508,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ }); } } - }, + }, on_expand: function(expand_img){ var level = parseInt($(expand_img).closest("tr[id^='viewedit-']").attr('level')); var cur_tr = $(expand_img).closest("tr[id^='viewedit-']"); @@ -539,9 +543,8 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ "Update": function(){ var update_values = []; _.each(self.edit_widget, function(widget) { - var value = widget.get_value(); - if (value) { - update_values.push(value); + if (widget.dirty) { + update_values.push(widget.get_value()); } }); self.do_save_update_arch(obj, view_id, view_xml_id, clicked_tr_id, clicked_tr_level, "update_node", update_values); @@ -562,9 +565,9 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ type_widget; self.ready = $.when(self.on_groups(id)).then(function () { if (_.include(widget,id)){ - type_widget = new (self.property.get_any(['undefined' , id, arch_val[0]['att_list'][0]])) (self.edit_node_dialog, arch_val, id); + type_widget = new (self.property.get_any(['undefined' , id, arch_val[0]['att_list'][0]])) (self.edit_node_dialog, id); } else { - type_widget = new openerp.web.ViewEditor.FieldChar (self.edit_node_dialog,arch_val, id); + type_widget = new openerp.web.ViewEditor.FieldChar (self.edit_node_dialog, id); } var value = _.detect(arch_val[0]['att_list'],function(res) { return _.include(res, id); @@ -609,12 +612,85 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ }); }) return def.promise(); + }, + on_add_node: function(properties,fields){ + var self = this; + var positions = ['After','Before','Inside']; + var render_list = []; + render_list.push(["node_type",(_.keys(_CHILDREN)).sort()]); + render_list.push(["position",positions]); + render_list.push([" ",fields]); + this.add_node_dialog = new openerp.web.Dialog(this,{ + modal: true, + title: 'Properties', + width: 500, + height: 300, + buttons: { + "Update": function(){ + }, + "Cancel": function(){ + self.add_node_dialog.close(); + } + } + }).start().open(); + this.add_node_dialog.$element. + append('
'); + var table_selector = self.add_node_dialog.$element.find('table[id=rec_table]'); + _.each(render_list,function(node){ + type_widget = new openerp.web.ViewEditor.FieldSelect (self.add_node_dialog, node[0]); + type_widget.value = node[1]; + table_selector.append(''+node[0]+''+type_widget.render()+''); + type_widget.start(); + }); + table_selector.append(' '); + self.add_node_dialog.$element.find("select[id=node_type] option[value=field]").attr("selected",1) + self.add_node_dialog.$element.find('#new_field').click(function() { + //to do + self.Add_new_field(); + }); + }, + Add_new_field : function(){ + var self = this; + var action = { + name: _.sprintf("Manage Views (%s)", this.model), + res_model: 'ir.model.fields', + views: [['form']], + type: 'ir.actions.act_window', + target: "new", + limit: this.dataset.limit || 80, + auto_search: true, + flags: { + sidebar: false, + deletable: false, + views_switcher: false, + action_buttons: false, + search_view: false, + pager: false, + radio: true + }, + }; + this.add_new_field = new openerp.web.Dialog(this, { + modal: true, + title: 'ViewEditor', + width: 750, + height: 500, + buttons: { + "Save": function(){ + //to do + }, + "Close": function(){ + self.add_new_field.close(); + } + }, + }).start().open(); + var action_manager = new openerp.web.ActionManager(this); + action_manager.appendTo(this.add_new_field); + action_manager.do_action(action); } }); openerp.web.ViewEditor.Field = openerp.web.Class.extend({ - init: function(view, node, id) { + init: function(view, id) { this.$element = view.$element; - this.node = node; this.dirty = false; this.name = id; this.value = undefined; @@ -640,9 +716,6 @@ openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({ } }, get_value: function() { - if (!this.dirty) { - return false; - } var value = this.$element.find("input[id=" + this.name + "]").is(':checked'); return value ? [this.name, value] : [this.name, null]; } @@ -659,9 +732,6 @@ openerp.web.ViewEditor.FieldChar = openerp.web.ViewEditor.Field.extend({ value ? this.$element.find("input[id=" + this.name + "]").val(value[1]): this.$element.find("tr[id=" + this.name + "] input").val(); }, get_value: function() { - if (!this.dirty) { - return false; - } var value= this.$element.find("input[id=" + this.name + "]").val(); return value ? [this.name, value] : [this.name, ""]; } @@ -684,16 +754,13 @@ openerp.web.ViewEditor.FieldSelect = openerp.web.ViewEditor.Field.extend({ this.$element.find("select[id=" + this.name + "]")[0].selectedIndex = index; }, get_value: function() { - if (!this.dirty) { - return false; - } var value = this.$element.find("select[id=" + this.name + "]").val(); return value ? [this.name, value] : [this.name, ""]; } }); openerp.web.ViewEditor.WidgetProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.registry = openerp.web.form.widgets; var values = _.keys(this.registry.map); values.push(''); @@ -702,44 +769,44 @@ openerp.web.ViewEditor.WidgetProperty = openerp.web.ViewEditor.FieldSelect.exten }, }); openerp.web.ViewEditor.IconProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.value = icons; }, }); openerp.web.ViewEditor.ButtonTargetProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.value = [['', ''], ['new', 'New Window']]; }, }); openerp.web.ViewEditor.ButtonTypeProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.value = [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']]; }, }); openerp.web.ViewEditor.AlignProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.value = [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']]; }, }); openerp.web.ViewEditor.ButtonSpecialProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.value = [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']]; }, }); openerp.web.ViewEditor.PositionProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.value = [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']]; }, }); openerp.web.ViewEditor.GroupsProperty = openerp.web.ViewEditor.FieldSelect.extend({ - init: function(view, node, id) { - this._super(view, node, id); + init: function(view, id) { + this._super(view, id); this.multiple = true; }, start: function () { diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 603e2abb008..15790d3c1c0 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -102,7 +102,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# self.on_pager_action(action); }); - this.$form_header.find('button.oe_form_button_save').click(this.do_save_then_readonly); + this.$form_header.find('button.oe_form_button_save').click(this.on_button_save); this.$form_header.find('button.oe_form_button_new').click(this.on_button_new); this.$form_header.find('button.oe_form_button_duplicate').click(this.on_button_duplicate); this.$form_header.find('button.oe_form_button_delete').click(this.on_button_delete); @@ -197,7 +197,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# this.do_update_pager(record.id == null); if (this.sidebar) { this.sidebar.attachments.do_update(); - this.sidebar.$element.find('.oe_sidebar_translate').toggleClass('oe_hide', !record.id); } if (this.default_focus_field && !this.embedded_view) { this.default_focus_field.focus(); @@ -295,7 +294,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# return self.on_processed_onchange(response, processed); }); } else { - console.log("Wrong on_change format", on_change); + console.warn("Wrong on_change format", on_change); } } } catch(e) { @@ -346,6 +345,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# return $.Deferred().reject(); } }, + on_button_save: function() { + return this.do_save().then(this.do_set_readonly); + }, on_button_new: function() { var self = this; var def = $.Deferred(); @@ -404,9 +406,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# * @param {Function} success callback on save success * @param {Boolean} [prepend_on_create=false] if ``do_save`` creates a new record, should that record be inserted at the start of the dataset (by default, records are added at the end) */ - do_save_then_readonly: function(success, prepend_on_create) { - return this.do_save(success, prepend_on_create).then(this.do_set_readonly); - }, do_save: function(success, prepend_on_create) { var self = this; var action = function() { @@ -435,12 +434,18 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# self.on_invalid(); return $.Deferred().reject(); } else { - console.log("About to save", values); if (!self.datarecord.id) { + openerp.log("FormView(", self, ") : About to create", values); return self.dataset.create(values).pipe(function(r) { return self.on_created(r, undefined, prepend_on_create); }).then(success); + } else if (_.isEmpty(values)) { + openerp.log("FormView(", self, ") : Nothing to save"); + if (success) { + success(); + } } else { + openerp.log("FormView(", self, ") : About to save", values); return self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) { return self.on_saved(r); }).then(success); @@ -503,7 +508,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# if (this.sidebar) { this.sidebar.attachments.do_update(); } - console.debug("The record has been created with id #" + this.datarecord.id); + openerp.log("The record has been created with id #" + this.datarecord.id); this.reload(); return $.when(_.extend(r, {created: true})).then(success); } @@ -697,7 +702,7 @@ openerp.web.form.compute_domain = function(expr, fields) { stack.push(!_(val).contains(field_value)); break; default: - console.log("Unsupported operator in modifiers :", op); + console.warn("Unsupported operator in modifiers :", op); } } return _.all(stack, _.identity); @@ -1097,7 +1102,7 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({ var self = this; this.$element.find("label").dblclick(function() { var widget = self['for'] || self; - console.log(widget.element_class , widget); + openerp.log(widget.element_class , widget); window.w = widget; }); } diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 62928401492..a6aaf02d5e6 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -441,6 +441,16 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner } } + var $res_logs = this.$element.find('.oe-view-manager-logs:first'); + $res_logs.delegate('a.oe-more-logs', 'click', function () { + $res_logs.removeClass('oe-folded'); + return false; + }).delegate('a.oe-remove-everything', 'click', function () { + $res_logs.removeClass('oe-has-more') + .find('ul').empty(); + return false; + }); + return manager_ready; }, on_mode_switch: function (view_type) { @@ -518,10 +528,14 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner */ do_display_log: function (log_records) { var self = this, - $logs = this.$element.find('ul.oe-view-manager-logs:first').empty(); - _(log_records).each(function (record) { + cutoff = 3, + $logs = this.$element.find('.oe-view-manager-logs:first') + .addClass('oe-folded'), + $logs_list = $logs.find('ul').empty(); + $logs.toggleClass('oe-has-more', log_records.length > cutoff); + _(log_records.reverse()).each(function (record) { $(_.sprintf('
  • %s
  • ', record.name)) - .appendTo($logs) + .appendTo($logs_list) .delegate('a', 'click', function (e) { self.do_action({ type: 'ir.actions.act_window', @@ -564,36 +578,38 @@ session.web.Sidebar = session.web.Widget.extend({ }, add_default_sections: function() { - this.add_section(_t('Customize'), 'customize'); - this.add_items('customize', [ - { - label: _t("Manage Views"), - callback: this.call_default_on_sidebar, - title: _t("Manage views of the current object") - }, { - label: _t("Edit Workflow"), - callback: this.call_default_on_sidebar, - title: _t("Manage views of the current object"), - classname: 'oe_hide oe_sidebar_edit_workflow' - }, { - label: _t("Customize Object"), - callback: this.call_default_on_sidebar, - title: _t("Manage views of the current object") - } - ]); + if (this.session.uid === 1) { + this.add_section(_t('Customize'), 'customize'); + this.add_items('customize', [ + { + label: _t("Manage Views"), + callback: this.call_default_on_sidebar, + title: _t("Manage views of the current object") + }, { + label: _t("Edit Workflow"), + callback: this.call_default_on_sidebar, + title: _t("Manage views of the current object"), + classname: 'oe_hide oe_sidebar_edit_workflow' + }, { + label: _t("Customize Object"), + callback: this.call_default_on_sidebar, + title: _t("Manage views of the current object") + }, { + label: _t("Translate"), + callback: this.call_default_on_sidebar, + title: _t("Technical translation") + } + ]); + } this.add_section(_t('Other Options'), 'other'); - this.add_items('other', [ + this.add_items('other', [ { label: _t("Import"), callback: this.call_default_on_sidebar }, { label: _t("Export"), callback: this.call_default_on_sidebar - }, { - label: _t("Translate"), - callback: this.call_default_on_sidebar, - classname: 'oe_sidebar_translate oe_hide' }, { label: _t("View Log"), callback: this.call_default_on_sidebar, @@ -619,14 +635,14 @@ session.web.Sidebar = session.web.Widget.extend({ } }); }, - + add_section: function(name, code) { if(!code) code = _.underscored(name); var $section = this.sections[code]; if(!$section) { - section_id = _.uniqueId(this.element_id + '_section_' + code + '_'); - var $section = $(session.web.qweb.render("Sidebar.section", { + var section_id = _.uniqueId(this.element_id + '_section_' + code + '_'); + $section = $(session.web.qweb.render("Sidebar.section", { section_id: section_id, name: name, classname: 'oe_sidebar_' + code @@ -740,11 +756,6 @@ session.web.TranslateDialog = session.web.Dialog.extend({ this._super(); $.when(this.languages_loaded).then(function() { self.$element.html(session.web.qweb.render('TranslateDialog', { widget: self })); - self.$element.tabs(); - if (!(self.view.translatable_fields && self.view.translatable_fields.length)) { - self.hide_tabs('fields'); - self.select_tab('view'); - } self.$fields_form = self.$element.find('.oe_translation_form'); self.$fields_form.find('.oe_trad_field').change(function() { $(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value'))); @@ -787,21 +798,6 @@ session.web.TranslateDialog = session.web.Dialog.extend({ }); $.when.apply(null, deffered).then(callback); }, - show_tabs: function() { - for (var i = 0; i < arguments.length; i++) { - this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().show(); - } - }, - hide_tabs: function() { - for (var i = 0; i < arguments.length; i++) { - this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().hide(); - } - }, - select_tab: function(name) { - this.show_tabs(name); - var index = this.$element.find('ul.oe_translate_tabs li a[href$="' + arguments[i] + '"]').parent().index() - 1; - this.$element.tabs('select', index); - }, open: function(field) { var self = this, sup = this._super; @@ -810,7 +806,9 @@ session.web.TranslateDialog = session.web.Dialog.extend({ self.do_load_fields_values(function() { sup.call(self); if (field) { - // TODO: focus and scroll to field + var $field_input = self.$element.find('tr[data-field="' + field.name + '"] td:nth-child(2) *:first-child'); + self.$element.scrollTo($field_input); + $field_input.focus(); } }); } else { @@ -963,7 +961,15 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{ export_view.start(); }, on_sidebar_translate: function() { - this.open_translate_dialog(); + return this.do_action({ + res_model : 'ir.translation', + domain : [['type', '!=', 'object'], '|', ['name', '=', this.dataset.model], ['name', 'ilike', this.dataset.model + ',']], + views: [[false, 'list'], [false, 'form']], + type : 'ir.actions.act_window', + auto_search : true, + view_type : "list", + view_mode : "list" + }); }, on_sidebar_view_log: function() { } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 95bd6f663dd..f5448168f5e 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -457,7 +457,11 @@ -
      +
      @@ -482,38 +486,25 @@ - -
      - - - - - - - - - -
      -
      Field
      -
      -
      -
      - - - - -
      -
      -
      - Translate view -
      -
      - Translate sidebar -
      + + + + + + + + + +
      +
      Field
      +
      +
      +
      + + + + +
      diff --git a/addons/web_default_home/po/ar.po b/addons/web_default_home/po/ar.po index 48260328d70..16c56db9120 100644 --- a/addons/web_default_home/po/ar.po +++ b/addons/web_default_home/po/ar.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-08 06:12+0000\n" -"X-Generator: Launchpad (build 14231)\n" +"X-Launchpad-Export-Date: 2011-11-09 05:09+0000\n" +"X-Generator: Launchpad (build 14263)\n" #: addons/web_default_home/static/src/xml/web_default_home.xml:0 msgid "Welcome to your new OpenERP instance." diff --git a/addons/web_diagram/po/da.po b/addons/web_diagram/po/da.po index b0a68cf641c..76d870fbc78 100644 --- a/addons/web_diagram/po/da.po +++ b/addons/web_diagram/po/da.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2011-10-07 10:39+0200\n" -"PO-Revision-Date: 2011-10-11 14:05+0000\n" +"PO-Revision-Date: 2011-11-08 21:59+0000\n" "Last-Translator: Jonas Mortensen \n" "Language-Team: Danish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-01 05:10+0000\n" -"X-Generator: Launchpad (build 14197)\n" +"X-Launchpad-Export-Date: 2011-11-09 05:09+0000\n" +"X-Generator: Launchpad (build 14263)\n" #: addons/web_diagram/static/src/xml/base_diagram.xml:0 msgid "New Node" @@ -23,7 +23,7 @@ msgstr "Ny tilstand" #: addons/web_diagram/static/src/xml/base_diagram.xml:0 msgid "New Edge" -msgstr "" +msgstr "Ny kant" #: addons/web_diagram/static/src/xml/base_diagram.xml:0 msgid "Show Grid:"