[Merge]Merge lp:openerp-web

bzr revid: vja@tinyerp.com-20130301104802-h03oi6khbhjv0pvs
This commit is contained in:
Vishmita Jadeja (openerp)
2013-03-01 16:18:02 +05:30
30 changed files with 1392 additions and 169 deletions
+4 -3
View File
@@ -13,6 +13,7 @@ import os
import re
import simplejson
import time
import urllib
import urllib2
import zlib
from xml.etree import ElementTree
@@ -293,9 +294,9 @@ def manifest_list(req, extension, mods=None, db=None):
if not req.debug:
path = '/web/webclient/' + extension
if mods is not None:
path += '?mods=' + mods
path += '?' + urllib.urlencode({'mods': mods})
elif db:
path += '?db=' + db
path += '?' + urllib.urlencode({'db': db})
return [path]
files = manifest_glob(req, extension, addons=mods, db=db)
i_am_diabetic = req.httprequest.environ["QUERY_STRING"].count("no_sugar") >= 1 or \
@@ -1310,7 +1311,7 @@ class Binary(openerpweb.Controller):
'id': attachment_id
}
except Exception:
args = {'error':e.faultCode }
args = {'error': "Something horrible happened"}
return out % (simplejson.dumps(callback), simplejson.dumps(args))
@openerpweb.httprequest
+5 -5
View File
@@ -32,12 +32,12 @@ NOMODULE_TEMPLATE = Template(u"""<!DOCTYPE html>
</form>
</body>
</html>
""")
""", default_filters=['h'])
NOTFOUND = Template(u"""
<p>Unable to find the module [${module}], please check that the module
name is correct and the module is on OpenERP's path.</p>
<a href="/web/tests">&lt;&lt; Back to tests</a>
""")
""", default_filters=['h'])
TESTING = Template(u"""<!DOCTYPE html>
<html style="height: 100%">
<%def name="to_path(module, p)">/${module}/${p}</%def>
@@ -51,9 +51,9 @@ TESTING = Template(u"""<!DOCTYPE html>
<script src="/web/static/lib/qunit/qunit.js"></script>
<script type="text/javascript">
var oe_db_info = ${db_info};
var oe_db_info = ${db_info | n};
// List of modules, each module is preceded by its dependencies
var oe_all_dependencies = ${dependencies};
var oe_all_dependencies = ${dependencies | n};
QUnit.config.testTimeout = 5 * 60 * 1000;
</script>
</head>
@@ -83,7 +83,7 @@ TESTING = Template(u"""<!DOCTYPE html>
% endif
% endfor
</html>
""")
""", default_filters=['h'])
class TestRunnerController(http.Controller):
_cp_path = '/web/tests'
+30 -6
View File
@@ -1,4 +1,4 @@
@charset "UTF-8";
@charset "utf-8";
@font-face {
font-family: "mnmliconsRegular";
src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot");
@@ -1263,7 +1263,7 @@
color: white;
padding: 2px 4px;
margin: 1px 6px 0 0;
border: 1px solid lightgrey;
border: 1px solid lightGray;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
@@ -1295,7 +1295,7 @@
transform: scale(1.1);
}
.openerp .oe_secondary_submenu .oe_active {
border-top: 1px solid lightgrey;
border-top: 1px solid lightGray;
border-bottom: 1px solid #dedede;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2);
@@ -1415,7 +1415,13 @@
display: inline-block;
overflow: hidden;
}
.openerp .oe_view_manager {
display: table;
height: inherit;
width: 100%;
}
.openerp .oe_view_manager .oe_view_manager_body {
display: table-row;
height: inherit;
}
.openerp .oe_view_manager .oe_view_manager_view_kanban {
@@ -2251,7 +2257,7 @@
}
.openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span {
font-size: 80%;
color: darkgreen;
color: darkGreen;
vertical-align: top;
position: relative;
top: -4px;
@@ -2323,6 +2329,7 @@
width: 100%;
display: inline-block;
padding: 2px 2px 2px 0px;
vertical-align: top;
}
.openerp .oe_form .oe_form_field input {
margin: 0px;
@@ -2366,7 +2373,6 @@
white-space: nowrap;
}
.openerp .oe_form .oe_form_field_boolean {
padding-top: 4px;
width: auto;
}
.openerp .oe_form .oe_datepicker_container {
@@ -3088,8 +3094,25 @@
color: #333333;
}
@-moz-document url-prefix() {
.openerp .oe_view_manager .oe_view_manager_switch li {
line-height: 21px;
}
.openerp .oe_searchview .oe_searchview_search {
top: -1px;
}
.openerp .oe_form_field_many2one .oe_m2o_cm_button {
line-height: 18px;
}
.openerp .oe_secondary_submenu {
line-height: 14px;
}
.openerp .oe_webclient .oe_star_on, .openerp .oe_webclient .oe_star_off {
top: 0px;
}
}
.kitten-mode-activated {
background-image: url(http://placekitten.com/g/1365/769);
background-size: cover;
background-attachment: fixed;
}
@@ -3318,6 +3341,7 @@ div.ui-widget-overlay {
overflow: hidden !important;
}
}
.blockUI.blockOverlay {
background-color: black;
opacity: 0.6;
+19 -2
View File
@@ -1137,7 +1137,11 @@ $sheet-padding: 16px
// }}}
// ViewManager common {{{
.oe_view_manager
display: table
height: inherit
width: 100%
.oe_view_manager_body
display: table-row
height: inherit
.oe_view_manager_view_kanban
height: inherit
@@ -1845,6 +1849,7 @@ $sheet-padding: 16px
width: 100%
display: inline-block
padding: 2px 2px 2px 0px
vertical-align: top
input
margin: 0px
input[type="text"], input[type="password"], input[type="file"], select
@@ -1872,7 +1877,6 @@ $sheet-padding: 16px
.oe_form_field_datetime
white-space: nowrap
.oe_form_field_boolean
padding-top: 4px
width: auto
.oe_datepicker_container
display: none
@@ -2434,9 +2438,22 @@ $sheet-padding: 16px
float: right
color: #333
// }}}
@-moz-document url-prefix()
.openerp
.oe_view_manager .oe_view_manager_switch li
line-height: 21px
.oe_searchview .oe_searchview_search
top: -1px
.oe_form_field_many2one .oe_m2o_cm_button
line-height: 18px
.oe_secondary_submenu
line-height: 14px
.oe_webclient
.oe_star_on, .oe_star_off
top: 0px
// Kitten Mode {{{
.kitten-mode-activated
background-image: url(http://placekitten.com/g/1365/769)
background-size: cover
background-attachment: fixed
>*
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

+16 -10
View File
@@ -1084,7 +1084,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
if (!self.session.uid)
return;
var func = new instance.web.Model("res.users").get_func("read");
return func(self.session.uid, ["name", "company_id"]).then(function(res) {
return self.alive(func(self.session.uid, ["name", "company_id"])).then(function(res) {
var topbar_name = res.name;
if(instance.session.debug)
topbar_name = _.str.sprintf("%s (%s)", topbar_name, instance.session.db);
@@ -1100,6 +1100,9 @@ instance.web.UserMenu = instance.web.Widget.extend({
};
this.update_promise = this.update_promise.then(fct, fct);
},
on_menu_help: function() {
window.open('http://help.openerp.com', '_blank');
},
on_menu_logout: function() {
this.trigger('user_logout');
},
@@ -1213,6 +1216,7 @@ instance.web.WebClient = instance.web.Client.extend({
return $.when(this._super()).then(function() {
if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) {
$("body").addClass("kitten-mode-activated");
$("body").css("background-image", "url(" + instance.session.origin + "/web/static/src/img/back-enable.jpg" + ")");
if ($.blockUI) {
$.blockUI.defaults.message = '<img src="http://www.amigrave.com/kitten.gif">';
}
@@ -1299,7 +1303,7 @@ instance.web.WebClient = instance.web.Client.extend({
},
logo_edit: function(ev) {
var self = this;
new instance.web.Model("res.users").get_func("read")(this.session.uid, ["company_id"]).then(function(res) {
new self.alive(instance.web.Model("res.users").get_func("read")(this.session.uid, ["company_id"])).then(function(res) {
self.rpc("/web/action/load", { action_id: "base.action_res_company_form" }).done(function(result) {
result.res_id = res['company_id'][0];
result.target = "new";
@@ -1320,7 +1324,7 @@ instance.web.WebClient = instance.web.Client.extend({
},
check_timezone: function() {
var self = this;
return new instance.web.Model('res.users').call('read', [[this.session.uid], ['tz_offset']]).then(function(result) {
return self.alive(new instance.web.Model('res.users').call('read', [[this.session.uid], ['tz_offset']])).then(function(result) {
var user_offset = result[0]['tz_offset'];
var offset = -(new Date().getTimezoneOffset());
// _.str.sprintf()'s zero front padding is buggy with signed decimals, so doing it manually
@@ -1396,8 +1400,9 @@ instance.web.WebClient = instance.web.Client.extend({
},
on_hashchange: function(event) {
var self = this;
var state = event.getState(true);
if (!_.isEqual(this._current_state, state)) {
var stringstate = event.getState(false);
if (!_.isEqual(this._current_state, stringstate)) {
var state = event.getState(true);
if(!state.action && state.menu_id) {
self.menu.has_been_loaded.done(function() {
self.menu.do_reload().done(function() {
@@ -1409,13 +1414,13 @@ instance.web.WebClient = instance.web.Client.extend({
this.action_manager.do_load_state(state, !!this._current_state);
}
}
this._current_state = state;
this._current_state = stringstate;
},
do_push_state: function(state) {
this.set_title(state.title);
delete state.title;
var url = '#' + $.param(state);
this._current_state = _.clone(state);
this._current_state = $.deparam($.param(state), false); // stringify all values
$.bbq.pushState(url);
this.trigger('state_pushed', state);
},
@@ -1425,9 +1430,10 @@ instance.web.WebClient = instance.web.Client.extend({
.then(function (result) {
return self.action_mutex.exec(function() {
if (options.needaction) {
result.context = new instance.web.CompoundContext(
result.context,
{search_default_message_unread: true});
result.context = new instance.web.CompoundContext(result.context, {
search_default_message_unread: true,
search_disable_custom_filters: true,
});
}
var completed = $.Deferred();
$.when(self.action_manager.do_action(result, {
+33 -10
View File
@@ -228,6 +228,38 @@ instance.web.ParentedMixin = {
isDestroyed : function() {
return this.__parentedDestroyed;
},
/**
Utility method to only execute asynchronous actions if the current
object has not been destroyed.
@param {Promise} promise The promise representing the asynchronous action.
@param {bool} reject Defaults to false. If true, the returned promise will be
rejected with no arguments if the current object is destroyed. If false,
the returned promise will never be resolved nor rejected.
@returns {Promise} A promise that will mirror the given promise if everything goes
fine but will either be rejected with no arguments or never resolved if the
current object is destroyed.
*/
alive: function(promise, reject) {
var def = $.Deferred();
var self = this;
promise.done(function() {
if (! self.isDestroyed()) {
if (! reject)
def.resolve.apply(def, arguments);
else
def.reject();
}
}).fail(function() {
if (! self.isDestroyed()) {
if (! reject)
def.reject.apply(def, arguments);
else
def.reject();
}
});
return def.promise();
},
/**
* Inform the object it should destroy itself, releasing any
* resource it could have reserved.
@@ -495,16 +527,7 @@ instance.web.Controller = instance.web.Class.extend(instance.web.PropertiesMixin
return false;
},
rpc: function(url, data, options) {
var def = $.Deferred();
var self = this;
instance.session.rpc(url, data, options).done(function() {
if (!self.isDestroyed())
def.resolve.apply(def, arguments);
}).fail(function() {
if (!self.isDestroyed())
def.reject.apply(def, arguments);
});
return def.promise();
return this.alive(instance.session.rpc(url, data, options));
}
});
+89 -25
View File
@@ -690,7 +690,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
return filter.user_id && filter.is_default;
});
if (personal_filter) {
this.custom_filters.enable_filter(personal_filter, true);
this.custom_filters.toggle_filter(personal_filter, true);
return;
}
@@ -698,7 +698,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
return !filter.user_id && filter.is_default;
});
if (global_filter) {
this.custom_filters.enable_filter(global_filter, true);
this.custom_filters.toggle_filter(global_filter, true);
return;
}
}
@@ -1466,12 +1466,15 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
},
complete: function (needle) {
var self = this;
// TODO: context
// FIXME: "concurrent" searches (multiple requests, mis-ordered responses)
var context = instance.web.pyeval.eval(
'contexts', [this.view.dataset.get_context()]);
return this.model.call('name_search', [], {
name: needle,
args: instance.web.pyeval.eval(
'domains', this.attrs.domain ? [this.attrs.domain] : [], context),
limit: 8,
context: {}
context: context
}).then(function (results) {
if (_.isEmpty(results)) { return null; }
return [{label: self.attrs.string}].concat(
@@ -1541,6 +1544,9 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
})
.on('reset', this.proxy('clear_selection'));
this.$el.on('submit', 'form', this.proxy('save_current'));
this.$el.on('click', 'input[type=checkbox]', function() {
$(this).siblings('input[type=checkbox]').prop('checked', false);
});
this.$el.on('click', 'h4', function () {
self.$el.toggleClass('oe_opened');
});
@@ -1591,6 +1597,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
get_groupby: function () { return [filter.context]; },
get_domain: function () { return filter.domain; }
},
_id: filter['id'],
is_custom_filter: true,
values: [{label: filter.name, value: null}]
};
@@ -1632,10 +1639,18 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
}
$filter.unbind('click').click(function () {
self.enable_filter(filter);
self.toggle_filter(filter);
});
},
enable_filter: function (filter, preventSearch) {
toggle_filter: function (filter, preventSearch) {
var current = this.view.query.find(function (facet) {
return facet.get('_id') === filter.id;
});
if (current) {
this.view.query.remove(current);
this.$filters[this.key_for(filter)].removeClass('oe_selected');
return;
}
this.view.query.reset([this.facet_for(filter)], {
preventSearch: preventSearch || false});
this.$filters[this.key_for(filter)].addClass('oe_selected');
@@ -1800,6 +1815,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
template: 'SearchView.extended_search.proposition',
events: {
'change .searchview_extended_prop_field': 'changed',
'change .searchview_extended_prop_op': 'operator_changed',
'click .searchview_extended_delete_prop': function (e) {
e.stopPropagation();
this.getParent().remove_proposition(this);
@@ -1831,6 +1847,17 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
this.select_field(_.detect(this.fields, function(x) {return x.name == nval;}));
}
},
operator_changed: function (e) {
var $value = this.$('.searchview_extended_prop_value');
switch ($(e.target).val()) {
case '∃':
case '∄':
$value.hide();
break;
default:
$value.show();
}
},
/**
* Selects the provided field object
*
@@ -1859,7 +1886,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
.text(String(operator.text))
.appendTo(self.$('.searchview_extended_prop_op'));
});
var $value_loc = this.$('.searchview_extended_prop_value').empty();
var $value_loc = this.$('.searchview_extended_prop_value').show().empty();
this.value.appendTo($value_loc);
},
@@ -1867,19 +1894,12 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @
if ( this.attrs.selected == null)
return null;
var field = this.attrs.selected;
var op = this.$('.searchview_extended_prop_op')[0];
var operator = op.options[op.selectedIndex];
var op_select = this.$('.searchview_extended_prop_op')[0];
var operator = op_select.options[op_select.selectedIndex];
return {
label: _.str.sprintf(_t('%(field)s %(operator)s "%(value)s"'), {
field: field.string,
// According to spec, HTMLOptionElement#label should return
// HTMLOptionElement#text when not defined/empty, but it does
// not in older Webkit (between Safari 5.1.5 and Chrome 17) and
// Gecko (pre Firefox 7) browsers, so we need a manual fallback
// for those
operator: operator.label || operator.text,
value: this.value}),
value: [field.name, operator.value, this.value.get_value()]
label: this.value.get_label(field, operator),
value: this.value.get_domain(field, operator),
};
}
});
@@ -1889,6 +1909,37 @@ instance.web.search.ExtendedSearchProposition.Field = instance.web.Widget.extend
this._super(parent);
this.field = field;
},
get_label: function (field, operator) {
var format;
switch (operator.value) {
case '∃': case '∄': format = _t('%(field)s %(operator)s'); break;
default: format = _t('%(field)s %(operator)s "%(value)s"'); break;
}
return this.format_label(format, field, operator);
},
format_label: function (format, field, operator) {
return _.str.sprintf(format, {
field: field.string,
// According to spec, HTMLOptionElement#label should return
// HTMLOptionElement#text when not defined/empty, but it does
// not in older Webkit (between Safari 5.1.5 and Chrome 17) and
// Gecko (pre Firefox 7) browsers, so we need a manual fallback
// for those
operator: operator.label || operator.text,
value: this
});
},
get_domain: function (field, operator) {
switch (operator.value) {
case '∃': return this.make_domain(field.name, '!=', false);
case '∄': return this.make_domain(field.name, '=', false);
default: return this.make_domain(
field.name, operator.value, this.get_value());
}
},
make_domain: function (field, operator, value) {
return [field, operator, value];
},
/**
* Returns a human-readable version of the value, in case the "logical"
* and the "semantic" values of a field differ (as for selection fields,
@@ -1908,7 +1959,9 @@ instance.web.search.ExtendedSearchProposition.Char = instance.web.search.Extende
{value: "ilike", text: _lt("contains")},
{value: "not ilike", text: _lt("doesn't contain")},
{value: "=", text: _lt("is equal to")},
{value: "!=", text: _lt("is not equal to")}
{value: "!=", text: _lt("is not equal to")},
{value: "∃", text: _lt("is set")},
{value: "∄", text: _lt("is not set")}
],
get_value: function() {
return this.$el.val();
@@ -1922,7 +1975,9 @@ instance.web.search.ExtendedSearchProposition.DateTime = instance.web.search.Ext
{value: ">", text: _lt("greater than")},
{value: "<", text: _lt("less than")},
{value: ">=", text: _lt("greater or equal than")},
{value: "<=", text: _lt("less or equal than")}
{value: "<=", text: _lt("less or equal than")},
{value: "∃", text: _lt("is set")},
{value: "∄", text: _lt("is not set")}
],
/**
* Date widgets live in view_form which is not yet loaded when this is
@@ -1956,7 +2011,9 @@ instance.web.search.ExtendedSearchProposition.Integer = instance.web.search.Exte
{value: ">", text: _lt("greater than")},
{value: "<", text: _lt("less than")},
{value: ">=", text: _lt("greater or equal than")},
{value: "<=", text: _lt("less or equal than")}
{value: "<=", text: _lt("less or equal than")},
{value: "∃", text: _lt("is set")},
{value: "∄", text: _lt("is not set")}
],
toString: function () {
return this.$el.val();
@@ -1981,7 +2038,9 @@ instance.web.search.ExtendedSearchProposition.Float = instance.web.search.Extend
{value: ">", text: _lt("greater than")},
{value: "<", text: _lt("less than")},
{value: ">=", text: _lt("greater or equal than")},
{value: "<=", text: _lt("less or equal than")}
{value: "<=", text: _lt("less or equal than")},
{value: "∃", text: _lt("is set")},
{value: "∄", text: _lt("is not set")}
],
toString: function () {
return this.$el.val();
@@ -1999,7 +2058,9 @@ instance.web.search.ExtendedSearchProposition.Selection = instance.web.search.Ex
template: 'SearchView.extended_search.proposition.selection',
operators: [
{value: "=", text: _lt("is")},
{value: "!=", text: _lt("is not")}
{value: "!=", text: _lt("is not")},
{value: "∃", text: _lt("is set")},
{value: "∄", text: _lt("is not set")}
],
toString: function () {
var select = this.$el[0];
@@ -2016,7 +2077,10 @@ instance.web.search.ExtendedSearchProposition.Boolean = instance.web.search.Exte
{value: "=", text: _lt("is true")},
{value: "!=", text: _lt("is false")}
],
toString: function () { return ''; },
get_label: function (field, operator) {
return this.format_label(
_t('%(field)s %(operator)s'), field, operator);
},
get_value: function() {
return true;
}
+103 -49
View File
@@ -247,13 +247,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
do_load_state: function(state, warm) {
if (state.id && this.datarecord.id != state.id) {
if (!this.dataset.get_id_index(state.id)) {
if (this.dataset.get_id_index(state.id) === null) {
this.dataset.ids.push(state.id);
}
this.dataset.select_id(state.id);
if (warm) {
this.do_show();
}
this.do_show({ reload: warm });
}
},
/**
@@ -511,9 +509,13 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var on_change = widget.node.attrs.on_change;
if (on_change) {
var change_spec = self.parse_on_change(on_change, widget);
var id = [self.datarecord.id == null ? [] : [self.datarecord.id]];
def = new instance.web.Model(self.dataset.model).call(
change_spec.method, id.concat(change_spec.args));
var ids = [];
if (self.datarecord.id && !instance.web.BufferedDataSet.virtual_id_regex.test(self.datarecord.id)) {
// In case of a o2m virtual id, we should pass an empty ids list
ids.push(self.datarecord.id);
}
def = self.alive(new instance.web.Model(self.dataset.model).call(
change_spec.method, [ids].concat(change_spec.args)));
} else {
def = $.when({});
}
@@ -531,9 +533,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var condition = fieldname + '=' + value_;
if (value_) {
return new instance.web.Model('ir.values').call(
return self.alive(new instance.web.Model('ir.values').call(
'get_defaults', [self.model, condition]
).then(function (results) {
)).then(function (results) {
if (!results.length) {
return response;
}
@@ -1191,6 +1193,10 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
$('button', doc).each(function() {
$(this).attr('data-button-type', $(this).attr('type')).attr('type', 'button');
});
// IE's html parser is also a css parser. How convenient...
$('board', doc).each(function() {
$(this).attr('layout', $(this).attr('style'));
});
return $('<div class="oe_form"/>').append(instance.web.xml_to_str(doc));
},
render_to: function($target) {
@@ -2327,7 +2333,7 @@ instance.web.form.FieldUrl = instance.web.form.FieldChar.extend({
this._super();
} else {
var tmp = this.get('value');
var s = /(\w+):(.+)/.exec(tmp);
var s = /(\w+):(.+)|^\.{0,2}\//.exec(tmp);
if (!s) {
tmp = "http://" + this.get('value');
}
@@ -2376,6 +2382,7 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
type_of_date: "datetime",
events: {
'change .oe_datepicker_master': 'change_datetime',
'dragstart img.oe_datepicker_trigger': function () { return false; },
},
init: function(parent) {
this._super(parent);
@@ -2395,6 +2402,11 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
showButtonPanel: true,
firstDay: Date.CultureInfo.firstDayOfWeek
});
// Some clicks in the datepicker dialog are not stopped by the
// datepicker and "bubble through", unexpectedly triggering the bus's
// click event. Prevent that.
this.picker('widget').click(function (e) { e.stopPropagation(); });
this.$el.find('img.oe_datepicker_trigger').click(function() {
if (self.get("effective_readonly") || self.picker('widget').is(':visible')) {
self.$input.focus();
@@ -2970,7 +2982,9 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
case $.ui.keyCode.DOWN:
e.stopPropagation();
}
}
},
'dragstart .oe_m2o_drop_down_button img': function () { return false; },
'dragstart .oe_m2o_cm_button': function () { return false; }
},
init: function(field_manager, node) {
this._super(field_manager, node);
@@ -3060,9 +3074,9 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
this.$input.keydown(input_changed);
this.$input.change(input_changed);
this.$drop_down.click(function() {
self.$input.focus();
if (self.$input.autocomplete("widget").is(":visible")) {
self.$input.autocomplete("close");
self.$input.focus();
self.$input.autocomplete("close");
} else {
if (self.get("value") && ! self.floating) {
self.$input.autocomplete("search", "");
@@ -3071,6 +3085,15 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
}
}
});
// Autocomplete close on dialog content scroll
var close_autocomplete = _.debounce(function() {
if (self.$input.autocomplete("widget").is(":visible")) {
self.$input.autocomplete("close");
}
}, 50);
this.$input.closest(".ui-dialog .ui-dialog-content").on('scroll', this, close_autocomplete);
self.ed_def = $.Deferred();
self.uned_def = $.Deferred();
var ed_delay = 200;
@@ -4107,6 +4130,13 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
focus: function () {
this.$text[0].focus();
},
set_dimensions: function (height, width) {
this._super(height, width);
this.$("textarea").css({
width: width,
minHeight: height
});
},
});
/**
@@ -4463,6 +4493,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
* options:
* -readonly: only applicable when not in creation mode, default to false
* - alternative_form_view
* - view_id
* - write_function
* - read_function
* - create_function
@@ -4529,7 +4560,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
_.extend(options, {
$buttons: this.$buttonpane,
});
this.view_form = new instance.web.FormView(this, this.dataset, false, options);
this.view_form = new instance.web.FormView(this, this.dataset, this.options.view_id || false, options);
if (this.options.alternative_form_view) {
this.view_form.set_embedded_view(this.options.alternative_form_view);
}
@@ -4558,6 +4589,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
});
var $cbutton = self.$buttonpane.find(".oe_abstractformpopup-form-close");
$cbutton.click(function() {
self.view_form.trigger('on_button_cancel');
self.check_exit();
});
self.view_form.do_show();
@@ -5236,8 +5268,20 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
this.options.clickable = this.options.clickable || (this.node.attrs || {}).clickable || false;
this.options.visible = this.options.visible || (this.node.attrs || {}).statusbar_visible || false;
this.set({value: false});
this.selection = [];
this.set("selection", []);
this.selection_dm = new instance.web.DropMisordered();
},
start: function() {
this.field_manager.on("view_content_has_changed", this, this.calc_domain);
this.calc_domain();
this.on("change:value", this, this.get_selection);
this.on("change:evaluated_selection_domain", this, this.get_selection);
this.get_selection();
this.on("change:selection", this, function() {
this.selection = this.get("selection");
this.render_value();
});
if (this.options.clickable) {
this.$el.on('click','li',this.on_click_stage);
}
@@ -5254,15 +5298,20 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
},
render_value: function() {
var self = this;
self.get_selection().done(function() {
var content = QWeb.render("FieldStatus.content", {widget: self});
self.$el.html(content);
var colors = JSON.parse((self.node.attrs || {}).statusbar_colors || "{}");
var color = colors[self.get('value')];
if (color) {
self.$("oe_active").css("color", color);
}
});
var content = QWeb.render("FieldStatus.content", {widget: self});
self.$el.html(content);
var colors = JSON.parse((self.node.attrs || {}).statusbar_colors || "{}");
var color = colors[self.get('value')];
if (color) {
self.$("oe_active").css("color", color);
}
},
calc_domain: function() {
var d = instance.web.pyeval.eval('domain', this.build_domain());
domain = ['|', ['id', '=', this.get('value')]].concat(d);
if (! _.isEqual(domain, this.get("evaluated_selection_domain"))) {
this.set("evaluated_selection_domain", domain);
}
},
/** Get the selection and render it
* selection: [[identifier, value_to_display], ...]
@@ -5271,32 +5320,37 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
*/
get_selection: function() {
var self = this;
self.selection = [];
if (this.field.type == "many2one") {
var domain = [];
if(!_.isEmpty(this.field.domain) || !_.isEmpty(this.node.attrs.domain)) {
var d = instance.web.pyeval.eval('domain', self.build_domain());
domain = ['|', ['id', '=', self.get('value')]].concat(d);
}
var ds = new instance.web.DataSetSearch(this, this.field.relation, self.build_context(), domain);
return ds.read_slice(['name'], {}).then(function (records) {
for(var i = 0; i < records.length; i++) {
self.selection.push([records[i].id, records[i].name]);
}
});
} else {
// For field type selection filter values according to
// statusbar_visible attribute of the field. For example:
// statusbar_visible="draft,open".
var selection = this.field.selection;
for(var i=0; i < selection.length; i++) {
var key = selection[i][0];
if(key == this.get('value') || !this.options.visible || this.options.visible.indexOf(key) != -1) {
this.selection.push(selection[i]);
var selection = [];
var calculation = _.bind(function() {
if (this.field.type == "many2one") {
var domain = [];
var ds = new instance.web.DataSetSearch(this, this.field.relation,
self.build_context(), this.get("evaluated_selection_domain"));
return ds.read_slice(['name'], {}).then(function (records) {
for(var i = 0; i < records.length; i++) {
selection.push([records[i].id, records[i].name]);
}
});
} else {
// For field type selection filter values according to
// statusbar_visible attribute of the field. For example:
// statusbar_visible="draft,open".
var select = this.field.selection;
for(var i=0; i < select.length; i++) {
var key = select[i][0];
if(key == this.get('value') || !this.options.visible || this.options.visible.indexOf(key) != -1) {
selection.push(select[i]);
}
}
return $.when();
}
return $.when();
}
}, this);
this.selection_dm.add(calculation()).then(function () {
if (! _.isEqual(selection, self.get("selection"))) {
self.set("selection", selection);
}
});
},
on_click_stage: function (ev) {
var self = this;
@@ -5340,8 +5394,8 @@ instance.web.form.FieldMonetary = instance.web.form.FieldFloat.extend({
this.set({"currency_info": null});
return;
}
return this.ci_dm.add(new instance.web.Model("res.currency").query(["symbol", "position"])
.filter([["id", "=", self.get("currency")]]).first()).then(function(res) {
return this.ci_dm.add(self.alive(new instance.web.Model("res.currency").query(["symbol", "position"])
.filter([["id", "=", self.get("currency")]]).first())).then(function(res) {
self.set({"currency_info": res});
});
},
+3 -3
View File
@@ -1186,7 +1186,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
}
});
instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.web.ListView.Groups# */{
passtrough_events: 'action deleted row_link',
passthrough_events: 'action deleted row_link',
/**
* Grouped display for the ListView. Handles basic DOM events and interacts
* with the :js:class:`~DataGroup` bound to it.
@@ -1406,7 +1406,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
// can have selections spanning multiple links
var selection = self.get_selection();
$this.trigger(e, [selection.ids, selection.records]);
}).bind(this.passtrough_events, function (e) {
}).bind(this.passthrough_events, function (e) {
// additional positional parameters are provided to trigger as an
// Array, following the event type or event object, but are
// provided to the .bind event handler as *args.
@@ -2212,7 +2212,7 @@ instance.web.list.Binary = instance.web.list.Column.extend({
if (value && value.substr(0, 10).indexOf(' ') == -1) {
download_url = "data:application/octet-stream;base64," + value;
} else {
download_url = this.session.url('/web/binary/saveas', {model: options.model, field: this.id, id: options.id});
download_url = instance.session.url('/web/binary/saveas', {model: options.model, field: this.id, id: options.id});
if (this.filename) {
download_url += '&filename_field=' + this.filename;
}
+10 -5
View File
@@ -132,6 +132,15 @@ openerp.web.list_editable = function (instance) {
var self = this;
// tree/@editable takes priority on everything else if present.
var result = this._super(data, grouped);
// In case current editor was started previously, also has to run
// when toggling from editable to non-editable in case form widgets
// have setup global behaviors expecting themselves to exist
// somehow.
this.editor.destroy();
// Editor is not restartable due to formview not being restartable
this.editor = this.make_editor();
if (this.editable()) {
this.$el.addClass('oe_list_editable');
// FIXME: any hook available to ensure this is only done once?
@@ -143,10 +152,6 @@ openerp.web.list_editable = function (instance) {
e.preventDefault();
self.cancel_edition();
});
this.editor.destroy();
// Editor is not restartable due to formview not being
// restartable
this.editor = this.make_editor();
var editor_ready = this.editor.prependTo(this.$el)
.done(this.proxy('setup_events'));
@@ -795,7 +800,7 @@ openerp.web.list_editable = function (instance) {
});
instance.web.ListView.Groups.include(/** @lends instance.web.ListView.Groups# */{
passtrough_events: instance.web.ListView.Groups.prototype.passtrough_events + " edit saved",
passthrough_events: instance.web.ListView.Groups.prototype.passthrough_events + " edit saved",
get_row_for: function (record) {
return _(this.children).chain()
.invoke('get_row_for', record)
+71 -17
View File
@@ -190,6 +190,18 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
state = _.extend(params || {}, state);
}
if (this.inner_action.context) {
var active_id = this.inner_action.context.active_id;
if (active_id) {
state["active_id"] = active_id;
}
var active_ids = this.inner_action.context.active_ids;
if (active_ids && !(active_ids.length === 1 && active_ids[0] === active_id)) {
// We don't push active_ids if it's a single element array containing the active_id
// This makes the url shorter in most cases.
state["active_ids"] = this.inner_action.context.active_ids.join(',');
}
}
}
if(!this.dialog) {
this.getParent().do_push_state(state);
@@ -212,8 +224,22 @@ instance.web.ActionManager = instance.web.Widget.extend({
} else {
var run_action = (!this.inner_widget || !this.inner_widget.action) || this.inner_widget.action.id !== state.action;
if (run_action) {
var add_context = {};
if (state.active_id) {
add_context.active_id = state.active_id;
}
if (state.active_ids) {
// The jQuery BBQ plugin does some parsing on values that are valid integers.
// It means that if there's only one item, it will do parseInt() on it,
// otherwise it will keep the comma seperated list as string.
add_context.active_ids = state.active_ids.toString().split(',').map(function(id) {
return parseInt(id, 10) || id;
});
} else if (state.active_id) {
add_context.active_ids = [state.active_id];
}
this.null_action();
action_loaded = this.do_action(state.action);
action_loaded = this.do_action(state.action, { additional_context: add_context });
$.when(action_loaded || null).done(function() {
instance.webclient.menu.has_been_loaded.done(function() {
if (self.inner_action && self.inner_action.id) {
@@ -249,12 +275,25 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
});
},
/**
* Execute an OpenERP action
*
* @param {Number|String|Object} Can be either an action id, a client action or an action descriptor.
* @param {Object} [options]
* @param {Boolean} [options.clear_breadcrumbs=false] Clear the breadcrumbs history list
* @param {Function} [options.on_reverse_breadcrumb] Callback to be executed whenever an anterior breadcrumb item is clicked on.
* @param {Function} [options.on_close] Callback to be executed when the dialog is closed (only relevant for target=new actions)
* @param {Function} [options.action_menu_id] Manually set the menu id on the fly.
* @param {Object} [options.additional_context] Additional context to be merged with the action's context.
* @return {jQuery.Deferred} Action loaded
*/
do_action: function(action, options) {
options = _.defaults(options || {}, {
clear_breadcrumbs: false,
on_reverse_breadcrumb: function() {},
on_close: function() {},
action_menu_id: null,
additional_context: {},
});
if (action === false) {
action = { type: 'ir.actions.act_window_close' };
@@ -269,9 +308,13 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
// Ensure context & domain are evaluated and can be manipulated/used
if (action.context) {
action.context = instance.web.pyeval.eval(
'context', action.context);
var ncontext = new instance.web.CompoundContext(options.additional_context, action.context || {});
action.context = instance.web.pyeval.eval('context', ncontext);
if (action.context.active_id || action.context.active_ids) {
// Here we assume that when an `active_id` or `active_ids` is used
// in the context, we are in a `related` action, so we disable the
// searchview's default custom filters.
action.context.search_disable_custom_filters = true;
}
if (action.domain) {
action.domain = instance.web.pyeval.eval(
@@ -539,7 +582,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
_.each(_.keys(self.views), function(view_name) {
var controller = self.views[view_name].controller;
if (controller) {
var container = self.$el.find(".oe_view_manager_view_" + view_name + ":first");
var container = self.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_name);
if (view_name === view_type) {
container.show();
controller.do_show(view_options || {});
@@ -582,7 +625,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
controller.on('switch_mode', self, this.switch_mode);
controller.on('previous_view', self, this.prev_view);
var container = this.$el.find(".oe_view_manager_view_" + view_type);
var container = this.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_type);
var view_promise = controller.appendTo(container);
this.views[view_type].controller = controller;
this.views[view_type].deferred.resolve(view_type);
@@ -597,6 +640,12 @@ instance.web.ViewManager = instance.web.Widget.extend({
self.trigger("controller_inited",view_type,controller);
});
},
/**
* @returns {Number|Boolean} the view id of the given type, false if not found
*/
get_view_id: function(view_type) {
return this.views[view_type] && this.views[view_type].view_id || false;
},
set_title: function(title) {
this.$el.find('.oe_view_title_text:first').text(title);
},
@@ -953,10 +1002,11 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
});
},
do_create_view: function(view_type) {
var r = this._super.apply(this, arguments);
var view = this.views[view_type].controller;
view.set({ 'title': this.action.name });
return r;
var self = this;
return this._super.apply(this, arguments).then(function() {
var view = self.views[view_type].controller;
view.set({ 'title': self.action.name });
});
},
get_action_manager: function() {
var cur = this;
@@ -1270,11 +1320,6 @@ instance.web.View = instance.web.Widget.extend({
active_ids: [record_id],
active_model: dataset.model
});
if (("" + action.context).match(/\bactive_id\b/)) {
// Special case: when the context is evaluted using
// the active_id, we want to disable the custom filters.
ncontext.add({ search_disable_custom_filters: true });
}
}
ncontext.add(action.context || {});
action.context = ncontext;
@@ -1502,13 +1547,22 @@ instance.web.json_node_to_xml = function(node, human_readable, indent) {
}
};
instance.web.xml_to_str = function(node) {
var str = "";
if (window.XMLSerializer) {
return (new XMLSerializer()).serializeToString(node);
str = (new XMLSerializer()).serializeToString(node);
} else if (window.ActiveXObject) {
return node.xml;
str = node.xml;
} else {
throw new Error(_t("Could not serialize XML"));
}
// Browsers won't deal with self closing tags except br, hr, input, ...
// http://stackoverflow.com/questions/97522/what-are-all-the-valid-self-closing-elements-in-xhtml-as-implemented-by-the-maj
//
// The following regex is a bit naive but it's ok for the xmlserializer output
str = str.replace(/<([a-z]+)([^<>]*)\s*\/\s*>/g, function(match, tag, attrs) {
return "<" + tag + attrs + "></" + tag + ">";
});
return str;
};
/**
+4 -3
View File
@@ -119,7 +119,7 @@
</tr>
<tr>
<td><label for="db_name">New database name:</label></td>
<td><input type="text" name="db_name" class="required" matches="^[a-zA-Z][a-zA-Z0-9_-]+$" autofocus="true"/></td>
<td><input type="text" name="db_name" class="required" matches="^[a-zA-Z0-9][a-zA-Z0-9_-]+$" autofocus="true"/></td>
</tr>
<tr>
<td><label for="demo_data">Load Demonstration data:</label></td>
@@ -403,8 +403,9 @@
<img class="oe_topbar_avatar" t-att-data-default-src="_s + '/web/static/src/img/user_menu_avatar.png'"/>
<span class="oe_topbar_name"/>
<ul class="oe_dropdown_menu">
<li><a href="#" data-menu="about">About OpenERP</a></li>
<li><a href="#" data-menu="settings">Preferences</a></li>
<li><a href="#" data-menu="about">About OpenERP</a></li>
<li><a href="#" data-menu="help">Help</a></li>
<li><a href="#" data-menu="logout">Log out</a></li>
</ul>
</span>
@@ -1299,7 +1300,7 @@
<span class='oe_attach_label'>File</span>
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
<t t-set="fileupload_action">/web/binary/upload_attachment</t>
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
<input type="hidden" name="model" t-att-value="widget.view.model"/>
<input type="hidden" name="id" value="0"/>
<input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
+91 -2
View File
@@ -318,6 +318,28 @@ openerp.testing.section('defaults', {
"facet value should match provided default's selection");
});
});
test("M2O default: value array", {asserts: 2}, function (instance, $s, mock) {
var view = {inputs: []}, id = 5;
var f = new instance.web.search.ManyToOneField(
{attrs: {name: 'dummy', string: 'Dummy'}},
{relation: 'dummy.model.name'},
view);
mock('dummy.model.name:name_get', function (args) {
equal(args[0], id);
return [[id, "DumDumDum"]];
});
return f.facet_for_defaults({dummy: [id]})
.done(function (facet) {
var model = facet;
if (!(model instanceof instance.web.search.Facet)) {
model = new instance.web.search.Facet(facet);
}
deepEqual(
model.values.toJSON(),
[{label: "DumDumDum", value: id}],
"should support default as a singleton");
});
});
test("M2O default: value", {asserts: 1}, function (instance, $s, mock) {
var view = {inputs: []}, id = 4;
var f = new instance.web.search.ManyToOneField(
@@ -330,6 +352,15 @@ openerp.testing.section('defaults', {
ok(!facet, "an invalid m2o default should yield a non-facet");
});
});
test("M2O default: values", {rpc: false}, function (instance) {
var view = {inputs: []};
var f = new instance.web.search.ManyToOneField(
{attrs: {name: 'dummy', string: 'Dummy'}},
{relation: 'dummy.model.name'},
view);
raises(function () { f.facet_for_defaults({dummy: [6, 7]}) },
"should not accept multiple default values");
})
});
openerp.testing.section('completions', {
dependencies: ['web.search'],
@@ -526,7 +557,7 @@ openerp.testing.section('completions', {
return [[42, "choice 1"], [43, "choice @"]];
});
var view = {inputs: []};
var view = {inputs: [], dataset: {get_context: function () {}}};
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
return f.complete("bob")
@@ -555,7 +586,7 @@ openerp.testing.section('completions', {
strictEqual(kwargs.name, 'bob');
return [];
});
var view = {inputs: []};
var view = {inputs: [], dataset: {get_context: function () {}}};
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
return f.complete("bob")
@@ -563,6 +594,26 @@ openerp.testing.section('completions', {
ok(!c, "no match should yield no completion");
});
});
test("M2O filtered", {asserts: 2}, function (instance, $s, mock) {
mock('dummy.model:name_search', function (args, kwargs) {
deepEqual(args, [], "should have no positional arguments");
deepEqual(kwargs, {
name: 'bob',
limit: 8,
args: [['foo', '=', 'bar']],
context: {flag: 1},
}, "should use filtering domain");
return [[42, "Match"]];
});
var view = {
inputs: [],
dataset: {get_context: function () { return {flag: 1}; }}
};
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy', domain: '[["foo", "=", "bar"]]'}},
{relation: 'dummy.model'}, view);
return f.complete("bob");
});
});
openerp.testing.section('search-serialization', {
dependencies: ['web.search'],
@@ -1038,6 +1089,44 @@ openerp.testing.section('saved_filters', {
"should not be checked anymore");
});
});
test('toggling', {asserts: 2}, function (instance, $fix, mock) {
var view = makeSearchView(instance);
mock('ir.filters:get_filters', function () {
return [{name: 'filter name', user_id: 42, id: 1}];
});
return view.appendTo($fix)
.done(function () {
var $row = $fix.find('.oe_searchview_custom li:first').click();
equal(view.query.length, 1, "should have one facet");
$row.click();
equal(view.query.length, 0, "should have removed facet");
});
});
test('replacement', {asserts: 4}, function (instance, $fix, mock) {
var view = makeSearchView(instance);
mock('ir.filters:get_filters', function () {
return [
{name: 'f', user_id: 42, id: 1, context: {'private': 1}},
{name: 'f', user_id: false, id: 2, context: {'private': 0}}
];
});
return view.appendTo($fix)
.done(function () {
$fix.find('.oe_searchview_custom li:eq(0)').click();
equal(view.query.length, 1, "should have one facet");
deepEqual(
view.query.at(0).get('field').get_context(),
{'private': 1},
"should have selected first filter");
$fix.find('.oe_searchview_custom li:eq(1)').click();
equal(view.query.length, 1, "should have one facet");
deepEqual(
view.query.at(0).get('field').get_context(),
{'private': 0},
"should have selected second filter");
});
});
});
openerp.testing.section('advanced', {
dependencies: ['web.search'],
+217
View File
@@ -0,0 +1,217 @@
# Korean translation for openerp-web
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
"PO-Revision-Date: 2013-02-26 07:04+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean <ko@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: 2013-02-27 04:53+0000\n"
"X-Generator: Launchpad (build 16506)\n"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:153
#, python-format
msgid "New event"
msgstr "신규 이벤트"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:156
#, python-format
msgid "Details"
msgstr "상세 내용"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:154
#, python-format
msgid "Save"
msgstr "저장"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:101
#, python-format
msgid "Calendar view has a 'date_delay' type != float"
msgstr "달력 화면에 'date_delay'유형의 != 플로트가 있습니다"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:149
#, python-format
msgid "Today"
msgstr "오늘"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:151
#, python-format
msgid "Week"
msgstr "주"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:163
#, python-format
msgid "Full day"
msgstr "하루 종일"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:161
#: code:addons/web_calendar/static/src/js/calendar.js:174
#, python-format
msgid "Description"
msgstr "설명"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:160
#, python-format
msgid "Event will be deleted permanently, are you sure?"
msgstr "이벤트가 영구 삭제될 것입니다. 확실하십니까?"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/xml/web_calendar.xml:8
#: code:addons/web_calendar/static/src/xml/web_calendar.xml:9
#, python-format
msgid "&nbsp;"
msgstr "&nbsp;"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:173
#, python-format
msgid "Date"
msgstr "날짜"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:470
#, python-format
msgid "Edit: "
msgstr "편집: "
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:150
#, python-format
msgid "Day"
msgstr "일"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:157
#, python-format
msgid "Edit"
msgstr "편집"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:169
#, python-format
msgid "Enabled"
msgstr "활성화 됨"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:166
#, python-format
msgid "Do you want to edit the whole set of repeated events?"
msgstr "반복 이벤트의 전체 세트를 편집하시겠습니까?"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:82
#, python-format
msgid "Filter"
msgstr "필터"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:167
#, python-format
msgid "Repeat event"
msgstr "이벤트 반복"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:172
#: code:addons/web_calendar/static/src/js/calendar.js:180
#, python-format
msgid "Agenda"
msgstr "의제"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:162
#, python-format
msgid "Time period"
msgstr "시한"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:158
#, python-format
msgid "Delete"
msgstr "삭제"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:152
#, python-format
msgid "Month"
msgstr "월"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:168
#, python-format
msgid "Disabled"
msgstr "비활성화 됨"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:435
#, python-format
msgid "Create: "
msgstr "생성: "
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:177
#, python-format
msgid "Year"
msgstr "년도"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:155
#, python-format
msgid "Cancel"
msgstr "취소"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:28
#, python-format
msgid "Calendar"
msgstr "달력"
#. module: web_calendar
#. openerp-web
#: code:addons/web_calendar/static/src/js/calendar.js:93
#, python-format
msgid "Calendar view has not defined 'date_start' attribute."
msgstr "달력 화면이 'date_start' 속성을 정의하지 않았습니다."
@@ -18,7 +18,7 @@
.openerp .oe_calendar .dhx_cal_select_menu .dhx_menu_icon.icon_edit {
display: none;
}
.openerp .oe_calendar .dhx_cal_navline {
.openerp .oe_calendar .dhx_cal_navline, .openerp .oe_calendar .dhx_cal_header {
z-index: auto;
}
.openerp .oe_calendar.oe_cal_month .dhx_cal_data table tr td:last-child div.dhx_month_body {
@@ -20,7 +20,7 @@
// Dhtmlx Scheduler css overrides
.dhx_cal_select_menu .dhx_menu_icon.icon_edit
display: none
.dhx_cal_navline
.dhx_cal_navline, .dhx_cal_header
// dhtmlx sets the index to 3 (in glossy theme)
// I didn't found the reason yet but it overlaps the
// dropdown menus and I want to avoid a z-index war.
+20 -2
View File
@@ -414,6 +414,20 @@ instance.web_calendar.CalendarView = instance.web.View.extend({
self.slow_create(event_id, event_obj);
});
},
get_form_popup_infos: function() {
var parent = this.getParent();
var infos = {
view_id: false,
title: this.name,
};
if (parent instanceof instance.web.ViewManager) {
infos.view_id = parent.get_view_id('form');
if (parent instanceof instance.web.ViewManagerAction && parent.action && parent.action.name) {
infos.title = parent.action.name;
}
}
return infos;
},
slow_create: function(event_id, event_obj) {
var self = this;
if (this.current_mode() === 'month') {
@@ -431,9 +445,11 @@ instance.web_calendar.CalendarView = instance.web.View.extend({
});
var something_saved = false;
var pop = new instance.web.form.FormOpenPopup(this);
var pop_infos = this.get_form_popup_infos();
pop.show_element(this.dataset.model, null, this.dataset.get_context(defaults), {
title: _t("Create: ") + ' ' + this.name,
title: _.str.sprintf(_t("Create: %s"), pop_infos.title),
disable_multiple_selection: true,
view_id: pop_infos.view_id,
});
pop.on('closed', self, function() {
if (!something_saved) {
@@ -465,9 +481,11 @@ instance.web_calendar.CalendarView = instance.web.View.extend({
});
} else {
var pop = new instance.web.form.FormOpenPopup(this);
var pop_infos = this.get_form_popup_infos();
var id_from_dataset = this.dataset.ids[index]; // dhtmlx scheduler loses id's type
pop.show_element(this.dataset.model, id_from_dataset, this.dataset.get_context(), {
title: _t("Edit: ") + this.name
title: _.str.sprintf(_t("Edit: %s"), pop_infos.title),
view_id: pop_infos.view_id,
});
pop.on('write_completed', self, function(){
self.reload_event(id_from_dataset);
+106
View File
@@ -0,0 +1,106 @@
# Korean translation for openerp-web
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
"PO-Revision-Date: 2013-02-26 07:09+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean <ko@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: 2013-02-27 04:53+0000\n"
"X-Generator: Launchpad (build 16506)\n"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:252
#: code:addons/web_diagram/static/src/js/diagram.js:317
#, python-format
msgid "Open: "
msgstr "열기: "
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:215
#, python-format
msgid ""
"Deleting this node cannot be undone.\n"
"It will also delete all connected transitions.\n"
"\n"
"Are you sure ?"
msgstr ""
"해당 노드를 삭제하는 작업은 복구할 수 없습니다.\n"
"또한 모든 연결된 전환을 삭제할 것입니다.\n"
"\n"
"확실하십니까?"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/xml/base_diagram.xml:13
#, python-format
msgid "New Node"
msgstr "신규 노드"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:310
#: code:addons/web_diagram/static/src/js/diagram.js:329
#, python-format
msgid "Transition"
msgstr "전환"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:11
#, python-format
msgid "Diagram"
msgstr "도표"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:244
#: code:addons/web_diagram/static/src/js/diagram.js:278
#, python-format
msgid "Activity"
msgstr "활동"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:420
#, python-format
msgid "%d / %d"
msgstr "%d / %d"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:283
#: code:addons/web_diagram/static/src/js/diagram.js:335
#, python-format
msgid "Create:"
msgstr "생성:"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:185
#, python-format
msgid "Are you sure?"
msgstr "확실하십니까?"
#. module: web_diagram
#. openerp-web
#: code:addons/web_diagram/static/src/js/diagram.js:233
#, python-format
msgid ""
"Deleting this transition cannot be undone.\n"
"\n"
"Are you sure ?"
msgstr ""
"해당 전환을 삭제하는 작업은 복구할 수 없습니다.\n"
"\n"
"확실하십니까 ?"
+32
View File
@@ -0,0 +1,32 @@
# Korean translation for openerp-web
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
"PO-Revision-Date: 2013-02-26 06:02+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean <ko@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: 2013-02-27 04:53+0000\n"
"X-Generator: Launchpad (build 16506)\n"
#. module: web_gantt
#. openerp-web
#: code:addons/web_gantt/static/src/xml/web_gantt.xml:10
#, python-format
msgid "Create"
msgstr "생성"
#. module: web_gantt
#. openerp-web
#: code:addons/web_gantt/static/src/js/gantt.js:11
#, python-format
msgid "Gantt"
msgstr "간트"
+2 -2
View File
@@ -24,8 +24,8 @@ instance.web_gantt.GanttView = instance.web.View.extend({
var self = this;
this.fields_view = fields_view_get;
this.$el.addClass(this.fields_view.arch.attrs['class']);
return new instance.web.Model(this.dataset.model)
.call('fields_get').then(function (fields) {
return self.alive(new instance.web.Model(this.dataset.model)
.call('fields_get')).then(function (fields) {
self.fields = fields;
self.has_been_loaded.resolve();
});
+137
View File
@@ -0,0 +1,137 @@
# Korean translation for openerp-web
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
"PO-Revision-Date: 2013-02-26 06:04+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean <ko@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: 2013-02-27 04:53+0000\n"
"X-Generator: Launchpad (build 16506)\n"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:12
#, python-format
msgid "Bars"
msgstr "막대"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:33
#, python-format
msgid "Show Data"
msgstr "데이터 보기"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/js/graph.js:22
#, python-format
msgid "Graph"
msgstr "그래프"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:25
#, python-format
msgid "Inside"
msgstr "내부"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:3
#, python-format
msgid "&iacute;"
msgstr "&iacute;"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:11
#, python-format
msgid "Pie"
msgstr "파이"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:28
#, python-format
msgid "Actions"
msgstr "액션"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:7
#, python-format
msgid "Graph Mode"
msgstr "그래프 모드"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:18
#, python-format
msgid "Radar"
msgstr "레이더"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:34
#, python-format
msgid "Download as PNG"
msgstr "PNG 형식으로 다운로드"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:26
#, python-format
msgid "Top"
msgstr "상단"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:24
#, python-format
msgid "Hidden"
msgstr "숨겨짐"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:3
#, python-format
msgid "Graph Options"
msgstr "그래프 옵션"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:14
#, python-format
msgid "Lines"
msgstr "선"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:20
#, python-format
msgid "Legend"
msgstr "범례"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:32
#, python-format
msgid "Switch Axis"
msgstr "축 전환"
#. module: web_graph
#. openerp-web
#: code:addons/web_graph/static/src/xml/web_graph.xml:15
#, python-format
msgid "Areas"
msgstr "영역"
+2 -2
View File
@@ -246,7 +246,7 @@ instance.web_graph.GraphView = instance.web.View.extend({
var result = [];
var ticks = {};
return obj.call("fields_view_get", [view_id, 'graph']).then(function(tmp) {
return this.alive(obj.call("fields_view_get", [view_id, 'graph']).then(function(tmp) {
view_get = tmp;
fields = view_get['fields'];
var toload = _.select(group_by, function(x) { return fields[x] === undefined });
@@ -368,7 +368,7 @@ instance.web_graph.GraphView = instance.web.View.extend({
'ticks': _.map(ticks, function(el, key) { return [el, key] })
};
return res;
});
}));
},
// Render the graph and update menu styles
+160
View File
@@ -0,0 +1,160 @@
# Korean translation for openerp-web
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
"PO-Revision-Date: 2013-02-26 05:59+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean <ko@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: 2013-02-27 04:53+0000\n"
"X-Generator: Launchpad (build 16506)\n"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:704
#, python-format
msgid "Edit column"
msgstr "열 편집"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:418
#, python-format
msgid "An error has occured while moving the record to this group."
msgstr "기록을 해당 그룹으로 옮기는 동안 오류가 발생했습니다."
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:10
#, python-format
msgid "Kanban"
msgstr "간판"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:557
#, python-format
msgid "Undefined"
msgstr "정의되지 않음"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:723
#, python-format
msgid "Are you sure to remove this column ?"
msgstr "정말로 해당 열을 제거하시겠습니다?"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:42
#, python-format
msgid "Edit"
msgstr "편집"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:190
#, python-format
msgid "Add column"
msgstr "열 추가"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:1100
#, python-format
msgid "Create: "
msgstr "다음 생성: "
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:24
#, python-format
msgid "Add a new column"
msgstr "열 추가"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:694
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:40
#, python-format
msgid "Fold"
msgstr "접기"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:91
#, python-format
msgid "Add"
msgstr "추가"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:35
#, python-format
msgid "Quick create"
msgstr "빠른 추가"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:936
#, python-format
msgid "Are you sure you want to delete this record ?"
msgstr "정말로 다음 기록을 삭제하시겠습니까 ?"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/js/kanban.js:694
#, python-format
msgid "Unfold"
msgstr "펼치기"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:73
#, python-format
msgid "Show more... ("
msgstr "더 보기... ("
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:92
#, python-format
msgid "Cancel"
msgstr "취소"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:73
#, python-format
msgid "remaining)"
msgstr "남음)"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:22
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:91
#, python-format
msgid "or"
msgstr "또는"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:51
#, python-format
msgid "99+"
msgstr "99+"
#. module: web_kanban
#. openerp-web
#: code:addons/web_kanban/static/src/xml/web_kanban.xml:43
#, python-format
msgid "Delete"
msgstr "삭제"
+15 -4
View File
@@ -92,12 +92,21 @@
overflow: hidden;
text-overflow: ellipsis;
}
.openerp .oe_kanban_view .oe_kanban_group_title .oe_kanban_group_length {
.openerp .oe_kanban_view .oe_kanban_group_length {
text-align: center;
display: none;
}
.openerp .oe_kanban_view .oe_kanban_group_length .oe_tag {
position: relative;
top: +8px;
font-weight: bold;
}
.openerp .oe_kanban_view .oe_fold_column .oe_kanban_group_length {
position: absolute;
top: -1px;
right: -14px;
text-align: center;
float: right;
display: block;
}
.openerp .oe_kanban_view .oe_kanban_header:hover .oe_kanban_group_length {
display: none;
@@ -141,7 +150,8 @@
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title, .openerp .oe_kanban_view .oe_kanban_group_folded.oe_kanban_column *, .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_aggregates, .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_add {
display: none;
}
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title_vertical {
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title_vertical,
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_length {
display: block;
}
.openerp .oe_kanban_view .oe_kanban_group_folded .oe_dropdown_kanban {
@@ -163,7 +173,7 @@
display: none;
position: relative;
opacity: 0.75;
top: 20px;
top: 26px;
}
.openerp .oe_kanban_view .oe_kanban_add, .openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_toggle {
margin-left: 4px;
@@ -175,6 +185,7 @@
}
.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_toggle {
top: -2px;
height: 14px;
}
.openerp .oe_kanban_view .oe_kanban_card, .openerp .oe_kanban_view .oe_dropdown_toggle {
cursor: pointer;
+12 -3
View File
@@ -54,6 +54,13 @@
&.oe_kanban_grouped .oe_kanban_dummy_cell
background: url(/web/static/src/img/form_sheetbg.png)
width: 100%
.oe_kanban_group_length
text-align: center
display: none
.oe_tag
position: relative
top: +8px
font-weight: bold
.ui-sortable-placeholder
border: 1px solid rgba(0,0,0,0.1)
visibility: visible !important
@@ -118,11 +125,12 @@
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
.oe_fold_column
.oe_kanban_group_length
position: absolute
top: -1px
right: -14px
text-align: center
display: block
float: right
&.oe_kanban_grouped
.oe_kanban_column, .oe_kanban_group_header
@@ -159,7 +167,7 @@
.oe_kanban_group_folded
.oe_kanban_group_title, &.oe_kanban_column *, .oe_kanban_aggregates, .oe_kanban_add
display: none
.oe_kanban_group_title_vertical
.oe_kanban_group_title_vertical, .oe_kanban_group_length
display: block
.oe_dropdown_kanban
left: -5px
@@ -178,7 +186,7 @@
display: none
position: relative
opacity: 0.75
top: 20px
top: 26px
// }}}
// KanbanQuickCreate {{{
.oe_kanban_add, .oe_kanban_header .oe_dropdown_toggle
@@ -189,6 +197,7 @@
top: -8px
.oe_kanban_header .oe_dropdown_toggle
top: -2px
height: 14px;
.oe_kanban_card, .oe_dropdown_toggle
cursor: pointer
display: inline-block
+8 -4
View File
@@ -134,7 +134,9 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
switch (node.tag) {
case 'field':
if (this.fields_view.fields[node.attrs.name].type === 'many2many') {
this.many2manys.push(node.attrs.name);
if (_.indexOf(this.many2manys, node.attrs.name) < 0) {
this.many2manys.push(node.attrs.name);
}
node.tag = 'div';
node.attrs['class'] = (node.attrs['class'] || '') + ' oe_form_field oe_tags';
} else {
@@ -227,14 +229,15 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
this.search_domain = domain;
this.search_context = context;
this.search_group_by = group_by;
$.when(this.has_been_loaded).done(function() {
return $.when(this.has_been_loaded).then(function() {
self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by;
self.group_by_field = self.fields_view.fields[self.group_by] || {};
self.grouped_by_m2o = (self.group_by_field.type === 'many2one');
self.$buttons.find('.oe_alternative').toggle(self.grouped_by_m2o);
self.$el.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o);
var grouping = new instance.web.Model(self.dataset.model, context, domain).query().group_by(self.group_by);
$.when(grouping).done(function(groups) {
var grouping_fields = self.group_by ? [self.group_by].concat(_.keys(self.aggregates)) : undefined;
var grouping = new instance.web.Model(self.dataset.model, context, domain).query().group_by(grouping_fields);
return self.alive($.when(grouping)).done(function(groups) {
if (groups) {
self.do_process_groups(groups);
} else {
@@ -635,6 +638,7 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({
self.view.dataset.ids = ids.concat(self.dataset.ids);
self.do_add_records(records);
self.compute_cards_auto_height();
self.view.postprocess_m2m_tags();
return records;
});
},
+17 -10
View File
@@ -34,16 +34,21 @@
<t t-if="widget.view._is_quick_create_enabled()">
<div class="oe_kanban_add oe_e" title="Quick create">]</div>
</t>
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu oe_kanban_group_dropdown">
<li><a data-action="toggle_fold" href="#">Fold</a></li>
<t t-if="widget.view.grouped_by_m2o and widget.value">
<li><a data-action="edit" href="#">Edit</a></li>
<li><a data-action="delete" href="#">Delete</a></li>
</t>
</ul>
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<div class="oe_kanban_group_length">
<span class="oe_tag">
<t t-if="widget.group.get('length') &gt; 99"> 99+ </t><t t-if="widget.group.get('length') &lt;= 99"> <t t-esc="widget.group.get('length')"/> </t>
</span>
</div>
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu oe_kanban_group_dropdown">
<li><a data-action="toggle_fold" href="#">Fold</a></li>
<t t-if="widget.view.grouped_by_m2o and widget.value">
<li><a data-action="edit" href="#">Edit</a></li>
<li><a data-action="delete" href="#">Delete</a></li>
</t>
</ul>
</div>
<div class="oe_fold_column">
<div t-attf-class="oe_kanban_group_title #{widget.undefined_title ? 'oe_kanban_group_title_undefined' : ''}">
<div class="oe_kanban_group_length oe_tag">
@@ -57,7 +62,9 @@
</li>
</ul>
</div>
<span t-if="widget.title" class="oe_kanban_group_title_vertical"><t t-esc="widget.title"/></span>
<span t-if="widget.title" class="oe_kanban_group_title_vertical">
<t t-esc="widget.title"/>
</span>
</div>
</t>
<t t-if="! widget.view.group_by &amp;&amp; widget.view._is_quick_create_enabled()">
+184
View File
@@ -0,0 +1,184 @@
# Korean translation for openerp-web
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openerp-web package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openerp-web\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
"PO-Revision-Date: 2013-02-26 08:08+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Korean <ko@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: 2013-02-27 04:53+0000\n"
"X-Generator: Launchpad (build 16506)\n"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:164
#, python-format
msgid "The following fields are invalid :"
msgstr "다음 필드는 유효하지 않습니다 :"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:63
#, python-format
msgid "Create"
msgstr "생성"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:986
#, python-format
msgid "New Field"
msgstr "신규 필드"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:386
#, python-format
msgid "Do you really wants to create an inherited view here?"
msgstr "정말로 여기에 전승된 화면을 생성하길 원하십니까?"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:396
#, python-format
msgid "Preview"
msgstr "미리보기"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:183
#, python-format
msgid "Do you really want to remove this view?"
msgstr "정말로 해당 화면을 제거하시겠습니까?"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:90
#, python-format
msgid "Save"
msgstr "저장"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:393
#, python-format
msgid "Select an element"
msgstr "요소 선택"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:828
#: code:addons/web_view_editor/static/src/js/view_editor.js:954
#, python-format
msgid "Update"
msgstr "업데이트"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:263
#, python-format
msgid "Please select view in list :"
msgstr "목록에서 화면을 선택하세요 :"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:37
#, python-format
msgid "Manage Views (%s)"
msgstr "화면 관리 (%s)"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:13
#, python-format
msgid "Manage Views"
msgstr "화면 관리"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:825
#: code:addons/web_view_editor/static/src/js/view_editor.js:951
#, python-format
msgid "Properties"
msgstr "속성"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:64
#, python-format
msgid "Edit"
msgstr "편집"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:14
#, python-format
msgid "Could not find current view declaration"
msgstr "현재 화면 선언을 찾을 수 없음"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:382
#, python-format
msgid "Inherited View"
msgstr "전승 화면"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:65
#, python-format
msgid "Remove"
msgstr "제거"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:516
#, python-format
msgid "Do you really want to remove this node?"
msgstr "정말로 이 노드를 삭제하시겠습니까?"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:390
#, python-format
msgid "Can't Update View"
msgstr "화면을 업데이트 할 수 없음"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:379
#, python-format
msgid "View Editor %d - %s"
msgstr "화면 편집기 %d - %s"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:112
#: code:addons/web_view_editor/static/src/js/view_editor.js:846
#: code:addons/web_view_editor/static/src/js/view_editor.js:974
#, python-format
msgid "Cancel"
msgstr "취소"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:66
#: code:addons/web_view_editor/static/src/js/view_editor.js:413
#, python-format
msgid "Close"
msgstr "닫기"
#. module: web_view_editor
#. openerp-web
#: code:addons/web_view_editor/static/src/js/view_editor.js:88
#, python-format
msgid "Create a view (%s)"
msgstr "화면 생성 (%s)"