summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/fields/basic_fields.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static/src/js/fields/basic_fields.js')
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js229
1 files changed, 156 insertions, 73 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index fd156f2d00b..b51fa49ed9a 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -8,7 +8,6 @@ odoo.define('web.basic_fields', function (require) {
*/
var AbstractField = require('web.AbstractField');
-var config = require('web.config');
var core = require('web.core');
var crash_manager = require('web.crash_manager');
var datepicker = require('web.datepicker');
@@ -313,13 +312,23 @@ var InputField = DebouncedField.extend({
this._super.apply(this, arguments);
// the following code only makes sense in edit mode, with an input
- if (this.mode === 'edit') {
+ if (this.mode === 'edit' && ev.data.direction !== 'cancel') {
var input = this.$input[0];
var selecting = (input.selectionEnd !== input.selectionStart);
if ((ev.data.direction === "left" && (selecting || input.selectionStart !== 0))
- || (ev.data.direction === "right" && (selecting || input.selectionStart !== input.value.length))) {
+ || (ev.data.direction === "right" && (selecting || input.selectionStart !== input.value.length))) {
ev.stopPropagation();
}
+ if (ev.data.direction ==='next' &&
+ this.attrs.modifiersValue &&
+ this.attrs.modifiersValue.required) {
+ if (!this.$input.val()){
+ this.setInvalidClass();
+ ev.stopPropagation();
+ } else {
+ this.removeInvalidClass();
+ }
+ }
}
},
});
@@ -347,6 +356,20 @@ var FieldChar = InputField.extend(TranslatableFieldMixin, {
this.$el = this.$el.add(this._renderTranslateButton());
return def;
},
+ /**
+ * Trim the value input by the user.
+ *
+ * @override
+ * @private
+ * @param {any} value
+ * @param {Object} [options]
+ */
+ _setValue: function (value, options) {
+ if (this.field.trim) {
+ value = value.trim();
+ }
+ return this._super(value, options);
+ },
});
@@ -428,7 +451,7 @@ var FieldDate = InputField.extend({
def = this.datewidget.appendTo('<div>').done(function () {
self.datewidget.$el.addClass(self.$el.attr('class'));
self._prepareInput(self.datewidget.$input);
- self.replaceElement(self.datewidget.$el);
+ self._replaceElement(self.datewidget.$el);
});
}
return $.when(def, this._super.apply(this, arguments));
@@ -612,7 +635,7 @@ var FieldMonetary = InputField.extend({
this.$el.empty();
// Prepare and add the input
- this._prepareInput().appendTo(this.$el);
+ this._prepareInput(this.$input).appendTo(this.$el);
if (this.currency) {
// Prepare and add the currency symbol
@@ -989,87 +1012,22 @@ var FieldPhone = FieldEmail.extend({
className: 'o_field_phone',
prefix: 'tel',
- /**
- * The phone widget is an extension of email, with the distinction that, in
- * some cases, we do not want to show a clickable widget in readonly.
- * In particular, we only want to make it clickable if the device can call
- * this particular number. This is controlled by the _canCall function.
- *
- * @override
- */
- init: function () {
- this._super.apply(this, arguments);
- if (this.mode === 'readonly' && !this._canCall()) {
- this.tagName = 'span';
- }
- },
- /**
- * Returns the associated link only if there is one.
- *
- * @override
- */
- getFocusableElement: function () {
- if (this.mode !== 'readonly' || this._canCall()) {
- return this._super.apply(this, arguments);
- }
- return $();
- },
-
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
- * In readonly, we only make the widget clickable if the device can call it.
- * Additionally, we obfuscate the phone number to prevent Skype from seeing it.
- *
* @override
* @private
*/
_renderReadonly: function () {
this._super();
- if (this._canCall()) {
- // Split phone number into two to prevent Skype app from finding it
- var text = this.$el.text();
- var part1 = _.escape(text.substr(0, text.length/2));
- var part2 = _.escape(text.substr(text.length/2));
- this.$el.html(part1 + "&shy;" + part2);
- } else {
- this.$el.removeClass('o_form_uri');
- }
+
// This class should technically be there in case of a very very long
// phone number, but it breaks the o_row mechanism, which is more
// important right now.
this.$el.removeClass('o_text_overflow');
},
-
- /**
- * Remove possibly present &shy; characters when saving number
- *
- * @override
- * @private
- */
- _setValue: function (value, options) {
- // NOT NEEDED AS OF SAAS-11.3
- if (value) {
- // remove possibly pasted &shy; characters
- value = value.replace(/\u00AD/g, '');
- }
- return this._super(value, options);
- },
-
- /**
- * Phone fields are clickable in readonly on small screens ~= on phones.
- * This can be overriden by call-capable modules to display a clickable
- * link in different situations, like always regardless of screen size,
- * or only allow national calls for example.
- *
- * @override
- * @private
- */
- _canCall: function () {
- return config.device.size_class <= config.device.SIZES.XS;
- }
});
var UrlWidget = InputField.extend({
@@ -1266,6 +1224,18 @@ var FieldBinaryImage = AbstractFieldBinary.extend({
}
}
var $img = $(qweb.render("FieldBinaryImage-img", {widget: this, url: url}));
+ // override css size attributes (could have been defined in css files)
+ // if specified on the widget
+ var width = this.nodeOptions.size ? this.nodeOptions.size[0] : this.attrs.width;
+ var height = this.nodeOptions.size ? this.nodeOptions.size[1] : this.attrs.height;
+ if (width) {
+ $img.attr('width', width);
+ $img.css('max-width', width + 'px');
+ }
+ if (height) {
+ $img.attr('height', height);
+ $img.css('max-height', height + 'px');
+ }
this.$('> img').remove();
this.$el.prepend($img);
$img.on('error', function () {
@@ -1358,6 +1328,118 @@ var FieldBinaryFile = AbstractFieldBinary.extend({
},
});
+var FieldPdfViewer = FieldBinaryFile.extend({
+ supportedFieldTypes: ['binary'],
+ template: 'FieldPdfViewer',
+ /**
+ * @override
+ */
+ init: function () {
+ this._super.apply(this, arguments);
+ this.PDFViewerApplication = false;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {DOMElement} iframe
+ */
+ _disableButtons: function (iframe) {
+ if (this.mode === 'readonly') {
+ $(iframe).contents().find('button#download').hide();
+ }
+ $(iframe).contents().find('button#openFile').hide();
+ },
+ /**
+ * @private
+ * @param {string} [fileURI] file URI if specified
+ * @returns {string} the pdf viewer URI
+ */
+ _getURI: function (fileURI) {
+ var page = this.recordData[this.name + '_page'] || 1;
+ if (!fileURI) {
+ var queryObj = {
+ model: this.model,
+ field: this.name,
+ id: this.res_id,
+ };
+ var queryString = $.param(queryObj);
+ fileURI = '/web/image?' + queryString
+ }
+ fileURI = encodeURIComponent(fileURI);
+ var viewerURL = '/web/static/lib/pdfjs/web/viewer.html?file=';
+ return viewerURL + fileURI + '#page=' + page;
+ },
+ /**
+ * @private
+ * @override
+ */
+ _render: function () {
+ var self = this;
+ var $pdfViewer = this.$('.o_form_pdf_controls').children().add(this.$('.o_pdfview_iframe'));
+ var $selectUpload = this.$('.o_select_file_button').first();
+ var $iFrame = this.$('.o_pdfview_iframe');
+
+ $iFrame.on('load', function () {
+ self.PDFViewerApplication = this.contentWindow.window.PDFViewerApplication;
+ self._disableButtons(this);
+ });
+ if (this.mode === "readonly" && this.value) {
+ $iFrame.attr('src', this._getURI());
+ } else {
+ if (this.value) {
+ var binSize = utils.is_bin_size(this.value);
+ $pdfViewer.removeClass('o_hidden');
+ $selectUpload.addClass('o_hidden');
+ if (binSize) {
+ $iFrame.attr('src', this._getURI());
+ }
+ } else {
+ $pdfViewer.addClass('o_hidden');
+ $selectUpload.removeClass('o_hidden');
+ }
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ * @private
+ * @param {Event} ev
+ */
+ on_file_change: function (ev) {
+ this._super.apply(this, arguments);
+ var files = ev.target.files;
+ if (!files || files.length === 0) {
+ return;
+ }
+ // TOCheck: is there requirement to fallback on FileReader if browser don't support URL
+ var fileURI = URL.createObjectURL(files[0]);
+ if (this.PDFViewerApplication) {
+ this.PDFViewerApplication.open(fileURI, 0);
+ } else {
+ this.$('.o_pdfview_iframe').attr('src', this._getURI(fileURI));
+ }
+ },
+ /**
+ * Remove the behaviour of on_save_as in FieldBinaryFile.
+ *
+ * @override
+ * @private
+ * @param {MouseEvent} ev
+ */
+ on_save_as: function (ev) {
+ ev.stopPropagation();
+ },
+
+});
+
var PriorityWidget = AbstractField.extend({
// the current implementation of this widget makes it
// only usable for fields of type selection
@@ -2154,7 +2236,7 @@ var JournalDashboardGraph = AbstractField.extend({
self.chart.forceY([0]);
self.chart.options({
x: function (d, u) { return u; },
- margin: {'left': 0, 'right': 0, 'top': 0, 'bottom': 0},
+ margin: {'left': 0, 'right': 0, 'top': 5, 'bottom': 0},
showYAxis: false,
showLegend: false,
});
@@ -2454,7 +2536,7 @@ var FieldDomain = AbstractField.extend({
var AceEditor = DebouncedField.extend({
template: "AceEditor",
jsLibs: [
- '/web/static/lib/ace/ace.odoo-custom.js',
+ '/web/static/lib/ace/ace.js',
[
'/web/static/lib/ace/mode-python.js',
'/web/static/lib/ace/mode-xml.js'
@@ -2617,6 +2699,7 @@ return {
DebouncedField: DebouncedField,
FieldEmail: FieldEmail,
FieldBinaryFile: FieldBinaryFile,
+ FieldPdfViewer: FieldPdfViewer,
FieldBinaryImage: FieldBinaryImage,
FieldBoolean: FieldBoolean,
FieldBooleanButton: FieldBooleanButton,