-
-
Notifications
You must be signed in to change notification settings - Fork 723
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[15.0][PORT] stock_location_tray: Porting module from 14.0 to 15.0
- Loading branch information
1 parent
115d625
commit 2c179c6
Showing
8 changed files
with
290 additions
and
309 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
263 changes: 263 additions & 0 deletions
263
stock_location_tray/static/src/js/stock_location_tray.esm.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
/** @odoo-module */ | ||
import {DebouncedField} from "web.basic_fields"; | ||
import registry from "web.field_registry"; | ||
|
||
/** | ||
* Shows a canvas with the Tray's cells | ||
* | ||
* An action can be configured which is called when a cell is clicked. | ||
* The action must be an action.multi, it will receive the x and y positions | ||
* of the cell clicked (starting from 0). The action must be configured in | ||
* the options of the field and be on the same model: | ||
* | ||
* <field name="tray_matrix" | ||
* widget="location_tray_matrix" | ||
* options="{'click_action': 'action_tray_matrix_click'}" | ||
* /> | ||
* | ||
*/ | ||
const LocationTrayMatrixField = DebouncedField.extend({ | ||
className: "o_field_location_tray_matrix", | ||
tagName: "canvas", | ||
supportedFieldTypes: ["serialized"], | ||
events: { | ||
click: "_onClick", | ||
}, | ||
|
||
cellColorEmpty: "#ffffff", | ||
cellColorNotEmpty: "#4e6bfd", | ||
selectedColor: "#08f46b", | ||
selectedLineWidth: 5, | ||
globalAlpha: 0.8, | ||
cellPadding: 2, | ||
|
||
init: function (parent, name, record, options) { | ||
this._super.apply(this, arguments); | ||
this.nodeOptions = _.defaults(this.nodeOptions, {}); | ||
if ("clickAction" in (options || {})) { | ||
this.clickAction = options.clickAction; | ||
} else { | ||
this.clickAction = this.nodeOptions.click_action; | ||
} | ||
}, | ||
|
||
isSet: function () { | ||
if (Object.keys(this.value).length === 0) { | ||
return false; | ||
} | ||
if (this.value.cells.length === 0) { | ||
return false; | ||
} | ||
return this._super.apply(this, arguments); | ||
}, | ||
|
||
start: function () { | ||
// Setup resize events to redraw the canvas | ||
this._resizeDebounce = this._resizeDebounce.bind(this); | ||
this._resizePromise = null; | ||
$(window).on("resize", this._resizeDebounce); | ||
|
||
var self = this; | ||
return this._super.apply(this, arguments).then(function () { | ||
if (self.clickAction) { | ||
self.$el.css("cursor", "pointer"); | ||
} | ||
// _super calls _render(), but the function | ||
// resizeCanvasToDisplaySize would resize the canvas | ||
// to 0 because the actual canvas would still be unknown. | ||
// Call again _render() here but through a setTimeout to | ||
// let the js renderer thread catch up. | ||
self._ready = true; | ||
return self._resizeDebounce(); | ||
}); | ||
}, | ||
|
||
_onClick: function (ev) { | ||
if (!this.isSet()) { | ||
return; | ||
} | ||
if (!this.clickAction) { | ||
return; | ||
} | ||
var width = this.canvas.width, | ||
height = this.canvas.height, | ||
rect = this.canvas.getBoundingClientRect(); | ||
|
||
var clickX = ev.clientX - rect.left, | ||
clickY = ev.clientY - rect.top; | ||
|
||
var cells = this.value.cells, | ||
cols = cells[0].length, | ||
rows = cells.length; | ||
|
||
// We remove 1 to start counting from 0 | ||
var coordX = Math.ceil((clickX * cols) / width) - 1, | ||
coordY = Math.ceil((clickY * rows) / height) - 1; | ||
// If we click on the last pixel on the bottom or the right | ||
// we would get an offset index | ||
if (coordX >= cols) { | ||
coordX = cols - 1; | ||
} | ||
if (coordY >= rows) { | ||
coordY = rows - 1; | ||
} | ||
|
||
// The coordinate we get when we click is from top, | ||
// but we are looking for the coordinate from the bottom | ||
// to match the user's expectations, invert Y | ||
coordY = Math.abs(coordY - rows + 1); | ||
|
||
var self = this; | ||
this._rpc({ | ||
model: this.model, | ||
method: this.clickAction, | ||
args: [[this.res_id], coordX, coordY], | ||
}).then(function (action) { | ||
self.trigger_up("do_action", {action: action}); | ||
}); | ||
}, | ||
|
||
/** | ||
* Debounce the rendering on resize. | ||
* It is useless to render on each resize event. | ||
* | ||
*/ | ||
_resizeDebounce: function () { | ||
clearTimeout(this._resizePromise); | ||
var self = this; | ||
this._resizePromise = setTimeout(function () { | ||
self._render(); | ||
}, 20); | ||
}, | ||
|
||
destroy: function () { | ||
$(window).off("resize", this._resizeDebounce); | ||
this._super.apply(this, arguments); | ||
}, | ||
|
||
/** | ||
* Render the widget only when it is in the DOM. | ||
* We need the width and height of the widget to draw the canvas. | ||
* | ||
* @returns {Promise} | ||
*/ | ||
_render: function () { | ||
if (this._ready) { | ||
return this._renderInDOM(); | ||
} | ||
return $.when(); | ||
}, | ||
|
||
/** | ||
* Resize the canvas width and height to the actual size. | ||
* If we don't do that, it will automatically scale to the | ||
* CSS size with blurry squares. | ||
* | ||
* @param {jQueryElement} canvas - the DOM canvas to draw | ||
* @returns {Boolean} | ||
*/ | ||
resizeCanvasToDisplaySize: function (canvas) { | ||
// Look up the size the canvas is being displayed | ||
var width = canvas.clientWidth; | ||
var height = canvas.clientHeight; | ||
|
||
// If it's resolution does not match change it | ||
if (canvas.width !== width || canvas.height !== height) { | ||
canvas.width = width; | ||
canvas.height = height; | ||
return true; | ||
} | ||
|
||
return false; | ||
}, | ||
|
||
/** | ||
* Resize the canvas, clear it and redraw the cells | ||
* Should be called only if the canvas is already in DOM | ||
* | ||
*/ | ||
_renderInDOM: function () { | ||
this.canvas = this.$el[0]; | ||
var canvas = this.canvas; | ||
var ctx = canvas.getContext("2d"); | ||
this.resizeCanvasToDisplaySize(ctx.canvas); | ||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
ctx.save(); | ||
if (this.isSet()) { | ||
var selected = this.value.selected || []; | ||
var cells = this.value.cells; | ||
this._drawMatrix(canvas, ctx, cells, selected); | ||
} | ||
}, | ||
|
||
/** | ||
* Draw the cells in the canvas. | ||
* | ||
* @param {jQueryElement} canvas - the DOM canvas to draw | ||
* @param {Object} ctx - the canvas 2d context | ||
* @param {List} cells - A 2-dimensional list of cells | ||
* @param {List} selected - A list containing the position (x,y) of the | ||
* selected cell (can be empty if no cell is selected) | ||
*/ | ||
_drawMatrix: function (canvas, ctx, cells, selected) { | ||
var colors = { | ||
0: this.cellColorEmpty, | ||
1: this.cellColorNotEmpty, | ||
}; | ||
|
||
var cols = cells[0].length; | ||
var rows = cells.length; | ||
var selectedX = null, | ||
selectedY = null; | ||
if (selected.length) { | ||
selectedX = selected[0]; | ||
// We draw top to bottom, but the highlighted cell should | ||
// be a coordinate from bottom to top: reverse the y axis | ||
selectedY = Math.abs(selected[1] - rows + 1); | ||
} | ||
|
||
var padding = this.cellPadding; | ||
var padding_width = padding * cols; | ||
var padding_height = padding * rows; | ||
var w = (canvas.width - padding_width) / cols; | ||
var h = (canvas.height - padding_height) / rows; | ||
|
||
ctx.globalAlpha = this.globalAlpha; | ||
// Again, our matrix is top to bottom (0 is the first line) | ||
// but visually, we want them bottom to top | ||
var reversed_cells = cells.slice().reverse(); | ||
for (var y = 0; y < rows; y++) { | ||
for (var x = 0; x < cols; x++) { | ||
ctx.fillStyle = colors[reversed_cells[y][x]]; | ||
var fillWidth = w; | ||
var fillHeight = h; | ||
// Cheat: remove the padding at bottom and right | ||
// the cells will be a bit larger but not really noticeable | ||
if (x === cols - 1) { | ||
fillWidth += padding; | ||
} | ||
if (y === rows - 1) { | ||
fillHeight += padding; | ||
} | ||
ctx.fillRect( | ||
x * (w + padding), | ||
y * (h + padding), | ||
fillWidth, | ||
fillHeight | ||
); | ||
if (selected && selectedX === x && selectedY === y) { | ||
ctx.globalAlpha = 1.0; | ||
ctx.strokeStyle = this.selectedColor; | ||
ctx.lineWidth = this.selectedLineWidth; | ||
ctx.strokeRect(x * (w + padding), y * (h + padding), w, h); | ||
ctx.globalAlpha = this.globalAlpha; | ||
} | ||
} | ||
} | ||
ctx.restore(); | ||
}, | ||
}); | ||
|
||
registry.add("location_tray_matrix", LocationTrayMatrixField); | ||
|
||
export default LocationTrayMatrixField; |
Oops, something went wrong.