diff options
| author | Vidhin Mehta (OpenERP) <vme@tinyerp.com> | 2012-07-03 19:19:40 +0530 |
|---|---|---|
| committer | Vidhin Mehta (OpenERP) <vme@tinyerp.com> | 2012-07-03 19:19:40 +0530 |
| commit | d86457a270afeb4ee2e5f7cfb906c73639fa54f2 (patch) | |
| tree | 546b5fb24c38652a34728aa89bb6f27001ea9df6 /addons/web/static | |
| parent | c6ffd20a31c1413adb71716c952f36d74e15533c (diff) | |
| parent | 50413828c552636b596b1b572addc68fae5c261c (diff) | |
[merge]main branch.
bzr revid: vme@tinyerp.com-20120703134940-27u7n3k8lp43hzep
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/lib/jquery.timeago/jquery.timeago.js | 45 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.css | 39 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.sass | 27 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 78 | ||||
| -rw-r--r-- | addons/web/static/src/js/coresetup.js | 32 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 5 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 40 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 24 |
10 files changed, 202 insertions, 92 deletions
diff --git a/addons/web/static/lib/jquery.timeago/jquery.timeago.js b/addons/web/static/lib/jquery.timeago/jquery.timeago.js index 14177473973..91ba5fd7756 100644 --- a/addons/web/static/lib/jquery.timeago/jquery.timeago.js +++ b/addons/web/static/lib/jquery.timeago/jquery.timeago.js @@ -1,6 +1,8 @@ /** * Timeago is a jQuery plugin that makes it easy to support automatically * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). + * + * Please note that the library has been slightly modified for i18n's sake. * * @name timeago * @version 0.11.3 @@ -49,7 +51,8 @@ years: "%d years", wordSeparator: " ", numbers: [] - } + }, + translator: null }, inWords: function(distanceMillis) { var $l = this.settings.strings; @@ -68,26 +71,36 @@ var days = hours / 24; var years = days / 365; - function substitute(stringOrFunction, number) { + function convert(stringOrFunction, number) { var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; - var value = ($l.numbers && $l.numbers[number]) || number; - return string.replace(/%d/i, value); + + // return the proper string and the numeric value that goes in it + return {'string': string, 'value': ($l.numbers && $l.numbers[number]) || number}; } - var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || - seconds < 90 && substitute($l.minute, 1) || - minutes < 45 && substitute($l.minutes, Math.round(minutes)) || - minutes < 90 && substitute($l.hour, 1) || - hours < 24 && substitute($l.hours, Math.round(hours)) || - hours < 42 && substitute($l.day, 1) || - days < 30 && substitute($l.days, Math.round(days)) || - days < 45 && substitute($l.month, 1) || - days < 365 && substitute($l.months, Math.round(days / 30)) || - years < 1.5 && substitute($l.year, 1) || - substitute($l.years, Math.round(years)); + var stringAndNumber = seconds < 45 && convert($l.seconds, Math.round(seconds)) || + seconds < 90 && convert($l.minute, 1) || + minutes < 45 && convert($l.minutes, Math.round(minutes)) || + minutes < 90 && convert($l.hour, 1) || + hours < 24 && convert($l.hours, Math.round(hours)) || + hours < 42 && convert($l.day, 1) || + days < 30 && convert($l.days, Math.round(days)) || + days < 45 && convert($l.month, 1) || + days < 365 && convert($l.months, Math.round(days / 30)) || + years < 1.5 && convert($l.year, 1) || + convert($l.years, Math.round(years)); + var string = stringAndNumber.string; + var value = stringAndNumber.value; var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator; - return $.trim([prefix, words, suffix].join(separator)); + + // compose and translate the final string + var fullString = $.trim([prefix, string, suffix].join(separator)); + var translatedString = $t.settings.translator ? + $t.settings.translator(fullString) : + fullString; + + return translatedString.replace(/%d/i, value); }, parse: function(iso8601) { var s = $.trim(iso8601); diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index e338cc309d9..71214acf4fe 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -34,7 +34,7 @@ background: white; /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image - */ + */ */ } .openerp a { text-decoration: none; @@ -186,6 +186,17 @@ .openerp .ui-menu .ui-menu-item a.ui-state-active { background: #f0f0fa; } +.openerp.ui-dialog { + border: 13px solid rgba(0, 0, 0, 0.3); + -moz-border-radius: 16px; + -webkit-border-radius: 16px; + border-radius: 16px; + -moz-background-clip: padding-box; + -webkit-background-clip: padding; + background-clip: padding-box; + box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.6); + -webkit-box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.2); +} .openerp .oe_i { font-family: "mnmliconsRegular" !important; font-size: 21px; @@ -283,7 +294,7 @@ background: #ed6f6a; } .openerp .oe_title { - width: 55%; + width: 60%; } .openerp .oe_title:after { content: "."; @@ -1162,10 +1173,10 @@ .openerp .oe_view_manager .oe_view_manager_switch .oe_vm_switch_diagram:after { content: "f"; } -.openerp .oe_view_manager_current, .openerp .oe_view_manager_inline { +.openerp .oe_view_manager_current { height: 100%; } -.openerp .oe_view_manager_current > .oe_view_manager_header, .openerp .oe_view_manager_inline > .oe_view_manager_header { +.openerp .oe_view_manager_current > .oe_view_manager_header { border-top: 1px solid #cacaca; border-bottom: 1px solid #cacaca; background-color: #fcfcfc; @@ -1179,12 +1190,18 @@ -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 9px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 9px rgba(0, 0, 0, 0.1); } -.openerp .oe_view_manager_current > .oe_view_manager_header .oe_header_row td, .openerp .oe_view_manager_inline > .oe_view_manager_header .oe_header_row td { +.openerp .oe_view_manager_current > .oe_view_manager_header .oe_header_row td { padding: 8px; } -.openerp .oe_view_manager_current > .oe_view_manager_header .oe_header_row:first-child td, .openerp .oe_view_manager_inline > .oe_view_manager_header .oe_header_row:first-child td { +.openerp .oe_view_manager_current > .oe_view_manager_header .oe_header_row:first-child td { padding-top: 8px; } +.openerp .oe_view_manager_inline { + height: 100%; +} +.openerp .oe_view_manager_inline > .oe_view_manager_header { + display: none; +} .openerp .oe_popup_form > .oe_formview > .oe_form_pager { display: none !important; } @@ -1612,9 +1629,13 @@ .openerp .oe_form_readonly .oe_edit_only, .openerp .oe_form_readonly .oe_form_field:empty { display: none !important; } -.openerp .oe_form_nosheet > *:not(header) { - margin-left: 10px !important; - margin-right: 10px !important; +.openerp .oe_form_nosheet { + margin-left: 10px; + margin-right: 10px; +} +.openerp .oe_form_nosheet > header { + margin-left: -10px; + margin-right: -10px; } .openerp .oe_form header { position: relative; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 6514ea8d70b..97a2f708615 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -200,6 +200,14 @@ $colour4: #8a89ba width: auto a.ui-state-active background: #f0f0fa + &.ui-dialog + border: 13px solid rgba(0, 0, 0, 0.3) + @include radius(16px) + -moz-background-clip: padding-box + -webkit-background-clip: padding + background-clip: padding-box + box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.6) + -webkit-box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.2) // }}} // Generic classes {{{ .oe_i @@ -252,7 +260,7 @@ $colour4: #8a89ba &:hover background: #ED6F6A .oe_title - width: 55% + width: 60% .oe_title:after content: "." display: block @@ -913,7 +921,7 @@ $colour4: #8a89ba content: "f" // }}} // ViewManager application {{{ - .oe_view_manager_current, .oe_view_manager_inline + .oe_view_manager_current height: 100% > .oe_view_manager_header border-top: 1px solid #cacaca @@ -927,6 +935,12 @@ $colour4: #8a89ba td padding-top: 8px // }}} + // ViewManager inline {{{ + .oe_view_manager_inline + height: 100% + > .oe_view_manager_header + display: none + // }}} // Viewmanager popup {{{ .oe_popup_form > .oe_formview > .oe_form_pager display: none !important @@ -1259,9 +1273,12 @@ $colour4: #8a89ba .oe_form_readonly .oe_edit_only, .oe_form_field:empty display: none !important - .oe_form_nosheet > *:not(header) - margin-left: 10px !important - margin-right: 10px !important + .oe_form_nosheet + margin-left: 10px + margin-right: 10px + .oe_form_nosheet > header + margin-left: -10px + margin-right: -10px // }}} // FormView.custom tags and classes {{{ .oe_form diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index cab59c50ae7..b87ebe56856 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -136,14 +136,18 @@ instance.web.Dialog = instance.web.Widget.extend({ }, on_close: function() { if (this.dialog_options.destroy_on_close) { - this.$element.dialog('destroy'); + this.destroy(); } }, on_resized: function() { }, destroy: function () { - this.close(); - this.$element.dialog('destroy'); + _.each(this.getChildren(), function(el) { + el.destroy(); + }); + if (! this.isDestroyed()) { + this.$element.dialog('destroy'); + } this._super(); } }); @@ -579,6 +583,7 @@ instance.web.Menu = instance.web.Widget.extend({ start: function() { this._super.apply(this, arguments); this.$secondary_menus = this.getParent().$element.find('.oe_secondary_menus_container'); + this.$secondary_menus.on('click', 'a[data-menu]', this.on_menu_click); return this.do_reload(); }, do_reload: function() { @@ -591,7 +596,6 @@ instance.web.Menu = instance.web.Widget.extend({ this.limit_entries(); this.$secondary_menus.html(QWeb.render("Menu.secondary", { widget : this })); this.$element.on('click', 'a[data-menu]', this.on_menu_click); - this.$secondary_menus.on('click', 'a[data-menu]', this.on_menu_click); // Hide second level submenus this.$secondary_menus.find('.oe_menu_toggler').siblings('.oe_secondary_submenu').hide(); if (self.current_menu) { @@ -673,32 +677,37 @@ instance.web.Menu = instance.web.Widget.extend({ * Process a click on a menu item * * @param {Number} id the menu_id + * @param {Boolean} [needaction=false] whether the triggered action should execute in a `needs action` context */ - menu_click: function(id) { - if (id) { - // find back the menuitem in dom to get the action - var $item = this.$element.find('a[data-menu=' + id + ']'); - if (!$item.length) { - $item = this.$secondary_menus.find('a[data-menu=' + id + ']'); - } - var action_id = $item.data('action-id'); - // If first level menu doesnt have action trigger first leaf - if (!action_id) { - if(this.$element.has($item).length) { - $sub_menu = this.$secondary_menus.find('.oe_secondary_menu[data-menu-parent=' + id + ']'); - $items = $sub_menu.find('a[data-action-id]').filter('[data-action-id!=""]'); - if($items.length) { - action_id = $items.data('action-id'); - id = $items.data('menu'); - } + menu_click: function(id, needaction) { + if (!id) { return; } + + // find back the menuitem in dom to get the action + var $item = this.$element.find('a[data-menu=' + id + ']'); + if (!$item.length) { + $item = this.$secondary_menus.find('a[data-menu=' + id + ']'); + } + var action_id = $item.data('action-id'); + // If first level menu doesnt have action trigger first leaf + if (!action_id) { + if(this.$element.has($item).length) { + var $sub_menu = this.$secondary_menus.find('.oe_secondary_menu[data-menu-parent=' + id + ']'); + var $items = $sub_menu.find('a[data-action-id]').filter('[data-action-id!=""]'); + if($items.length) { + action_id = $items.data('action-id'); + id = $items.data('menu'); } } - this.open_menu(id); - this.current_menu = id; - this.session.active_id = id; - if (action_id) { - this.trigger('menu_click', action_id, id, $item); - } + } + this.open_menu(id); + this.current_menu = id; + this.session.active_id = id; + if (action_id) { + this.trigger('menu_click', { + action_id: action_id, + needaction: needaction, + id: id + }, $item); } }, /** @@ -708,7 +717,8 @@ instance.web.Menu = instance.web.Widget.extend({ */ on_menu_click: function(ev) { ev.preventDefault(); - this.menu_click($(ev.currentTarget).data('menu')); + var needaction = $(ev.target).is('div.oe_menu_counter'); + this.menu_click($(ev.currentTarget).data('menu'), needaction); }, }); @@ -1018,8 +1028,16 @@ instance.web.WebClient = instance.web.Widget.extend({ this._current_state = _.clone(state); $.bbq.pushState(url); }, - on_menu_action: function(action) { - this.action_manager.do_action(action); + on_menu_action: function(options) { + var self = this; + this.rpc("/web/action/load", { action_id: options.action_id }) + .then(function (result) { + var action = result.result; + if (options.needaction) { + action.context.search_default_needaction_pending = true; + } + self.action_manager.do_action(action); + }); }, do_action: function(action) { var self = this; diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index ee421bee092..a00ca4002e5 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -608,15 +608,31 @@ instance.web.qweb.preprocess_node = function() { }; /** Setup jQuery timeago */ -var timeago_setup = function () { - var s = $.timeago.settings.strings; - _.each(s, function(v,k) { - if(_.isString(v)) { - s[k] = instance.web._t(v); - } - }); +var _t = instance.web._t; +/* + * Strings in timeago are "composed" with prefixes, words and suffixes. This + * makes their detection by our translating system impossible. Use all literal + * strings we're using with a translation mark here so the extractor can do its + * job. + */ +{ + _t('less than a minute ago'); + _t('about a minute ago'); + _t('%d minutes ago'); + _t('about an hour ago'); + _t('%d hours ago'); + _t('a day ago'); + _t('%d days ago'); + _t('about a month ago'); + _t('%d months ago'); + _t('about a year ago'); + _t('%d years ago'); } -instance.connection.on('module_loaded', this, timeago_setup); + +instance.connection.on('module_loaded', this, function () { + // provide timeago.js with our own translator method + $.timeago.settings.translator = instance.web._t; +}); /** * Registry for all the client actions key: tag value: widget diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 2e332ed8b28..c8b6f797dba 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -352,6 +352,11 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea e.stopImmediatePropagation(); self.$element.toggleClass('oe_searchview_open_drawer'); }); + instance.web.bus.on('click', this, function(ev) { + if ($(ev.target).parents('.oe_searchview').length === 0) { + self.$element.removeClass('oe_searchview_open_drawer'); + } + }); // Focus last input if the view itself is clicked (empty section of // facets element) this.$element.on('click', function (e) { diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 8bc2a3894c8..d40a1760e81 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2891,25 +2891,36 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ view.embedded_view = self.field.views[mode]; } if(view.view_type === "list") { - view.options.selectable = self.multi_selection; - view.options.sortable = false; + _.extend(view.options, { + selectable: self.multi_selection, + sortable: false, + import_enabled: false, + }); if (self.get("effective_readonly")) { - view.options.addable = null; - view.options.deletable = null; - view.options.reorderable = false; + _.extend(view.options, { + addable: null, + deletable: null, + reorderable: false, + }); } } else if (view.view_type === "form") { if (self.get("effective_readonly")) { view.view_type = 'form'; } - view.options.not_interactible_on_create = true; + _.extend(view.options, { + not_interactible_on_create: true, + }); } else if (view.view_type === "kanban") { - view.options.confirm_on_delete = false; + _.extend(view.options, { + confirm_on_delete: false, + }); if (self.get("effective_readonly")) { - view.options.action_buttons = false; - view.options.quick_creatable = false; - view.options.creatable = false; - view.options.read_only_mode = true; + _.extend(view.options, { + action_buttons: false, + quick_creatable: false, + creatable: false, + read_only_mode: true, + }); } } views.push(view); @@ -3519,6 +3530,7 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({ 'selectable': self.multi_selection, 'sortable': false, 'reorderable': false, + 'import_enabled': false, }); var embedded = (this.field.views || {}).tree; if (embedded) { @@ -3999,6 +4011,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend _.extend({'deletable': false, 'selectable': !self.options.disable_multiple_selection, 'read_only': true, + 'import_enabled': false, }, self.options.list_view_options || {})); self.view_list.popup = self; self.view_list.appendTo($(".oe_popup_list", self.$element)).pipe(function() { @@ -4359,10 +4372,13 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ }); instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ - tagName: "span", + template: "FieldStatus", start: function() { this._super(); this.selected_value = null; + if (this.$element.parent().is('header')) { + this.$element.after('<div class="oe_clear"/>'); + } // preview in start only for selection fields, because of the dynamic behavior of many2one fields. if (this.field.type in ['selection']) { this.render_list(); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 97fccd343f1..b19e483bed9 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -24,6 +24,8 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi // if true, the view can't be editable, ignoring the view's and the context's // instructions 'read_only': false, + // if true, the 'Import', 'Export', etc... buttons will be shown + 'import_enabled': true, }, /** * Core class for list-type displays. diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index a364b9e0669..98df8a0af0d 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -144,7 +144,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog_viewmanager.destroy(); } this.dialog.dialog_title = action.name; - this.dialog_viewmanager = new instance.web.ViewManagerAction(this, action); + this.dialog_viewmanager = new instance.web.ViewManagerAction(this.dialog, action); this.dialog_viewmanager.appendTo(this.dialog.$element); this.dialog_viewmanager.$element.addClass("oe_view_manager_" + action.target); this.dialog.open(); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 6e0bd2417f1..ce130dc0e1e 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -621,7 +621,9 @@ <button type="button" class="oe_button oe_list_add oe_highlight"> <t t-esc="widget.options.addable"/> </button> - <span class="oe_fade">or</span> <a href="#" class="oe_bold oe_list_button_import">Import</a> + <t t-if="widget.options.import_enabled"> + <span class="oe_fade">or</span> <a href="#" class="oe_bold oe_list_button_import">Import</a> + </t> </t> </div> <t t-name="ListView.pager"> @@ -1008,17 +1010,17 @@ <span></span> </span> </t> +<t t-name="FieldStatus"> + <ul class="oe_form_steps"/> +</t> <t t-name="FieldStatus.content"> - <ul class="oe_form_steps"> - <t t-set="size" t-value="widget.to_show.length"/> - <t t-foreach="_.range(size)" t-as="i"> - <li t-att-class="widget.to_show[i][0] === widget.selected_value ? 'oe_form_steps_active' : ''"> - <span><t t-esc="widget.to_show[i][1]"/></span> - <img t-att-src='_s + "/web/static/src/img/form_steps.png"' class="oe_form_steps_arrow" t-if="i < size - 1"/> - </li> - </t> - </ul> - <div class="oe_clear"/> + <t t-set="size" t-value="widget.to_show.length"/> + <t t-foreach="_.range(size)" t-as="i"> + <li t-att-class="widget.to_show[i][0] === widget.selected_value ? 'oe_form_steps_active' : ''"> + <span><t t-esc="widget.to_show[i][1]"/></span> + <img t-att-src='_s + "/web/static/src/img/form_steps.png"' class="oe_form_steps_arrow" t-if="i < size - 1"/> + </li> + </t> </t> <t t-name="FieldBinaryImage"> <span class="oe_form_field oe_form_field_image"> |
