diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 3f279eeeec7..cdaed1d7b4f 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -165,6 +165,7 @@ var InputField = DebouncedField.extend({ */ init: function () { this._super.apply(this, arguments); + this.nodeOptions.isPassword = 'password' in this.attrs; if (this.mode === 'edit') { this.tagName = 'input'; } @@ -222,7 +223,7 @@ var InputField = DebouncedField.extend({ this.$input = $input || $(""); this.$input.addClass('o_input'); this.$input.attr({ - type: 'text', + type: this.nodeOptions.isPassword ? 'password' : 'text', placeholder: this.attrs.placeholder || "", }); this.$input.val(this._formatValue(this.value)); diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index 0606af0d662..75403c288e5 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -56,10 +56,15 @@ function formatBoolean(value) { * a description of the field (note: this parameter is ignored) * @param {Object} [options] additional options * @param {boolean} [options.escape=false] if true, escapes the formatted value + * @param {boolean} [options.isPassword=false] if true, returns '********' + * instead of the formatted value * @returns {string} */ function formatChar(value, field, options) { value = typeof value === 'string' ? value : ''; + if (options && options.isPassword) { + return _.str.repeat('*', value ? value.length : 0); + } if (options && options.escape) { value = _.escape(value); } @@ -177,9 +182,16 @@ function formatFloatTime(value) { * return an empty string. * * @param {integer|false} value + * @param {Object} [field] + * a description of the field (note: this parameter is ignored) + * @param {Object} [options] additional options + * @param {boolean} [options.isPassword=false] if true, returns '********' * @returns {string} */ -function formatInteger(value) { +function formatInteger(value, field, options) { + if (options && options.isPassword) { + return _.str.repeat('*', String(value).length); + } if (!value && value !== 0) { // previously, it returned 'false'. I don't know why. But for the Pivot // view, I want to display the concept of 'no value' with an empty diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js index 059e2aeccad..e589c0d430a 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -254,6 +254,7 @@ var ListRenderer = BasicRenderer.extend({ var formattedValue = field_utils.format[field.type](value, field, { data: record.data, escape: true, + isPassword: 'password' in node.attrs, }); return $td.html(formattedValue); }, diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index a36cfec075a..c67d8a1bff6 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -4618,5 +4618,28 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('support password attribute', function (assert) { + assert.expect(3); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '', + res_id: 1, + }); + + assert.strictEqual(form.$('span[name="foo"]').text(), '***', + "password should be displayed with stars"); + form.$buttons.find('.o_form_button_edit').click(); + assert.strictEqual(form.$('input[name="foo"]').val(), '***', + "password should be displayed with stars"); + assert.strictEqual(form.$('input[name="foo"]').prop('type'), 'password', + "input should be of type password"); + form.destroy(); + }); + }); }); diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 3753634c239..601e7a23533 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -2243,6 +2243,25 @@ QUnit.module('Views', { "should not have a visible save button"); list.destroy(); }); + + QUnit.test('field with password attribute', function (assert) { + assert.expect(2); + + var list = createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '', + }); + + assert.strictEqual(list.$('td.o_data_cell:eq(0)').text(), '***', + "should display string as password"); + assert.strictEqual(list.$('td.o_data_cell:eq(1)').text(), '****', + "should display string as password"); + + list.destroy(); + }); + }); });